撤消git rebase

web*_*mat 2965 git undo rebase git-rebase

有谁知道如何轻松撤消git rebase?

想到的唯一方法是手动进行:

  • git checkout两个分支的提交父级
  • 然后从那里创建一个临时分支
  • 樱桃 - 手工挑选所有提交
  • 用手动创建的分支替换我重新定位的分支

在我目前的情况下,这是可行的,因为我可以很容易地发现两个分支的提交(一个是我的东西,另一个是我的同事的东西).

然而,我的方法让我感到不理想和容易出错(假设我刚刚用自己的2个分支重新定位).

有任何想法吗?

澄清:我正在谈论一个rebase,在此期间重播了一堆提交.不仅仅是一个.

CB *_*ley 4047

最简单的方法是找到分支的头部提交,就像在reflog中启动rebase之前一样...

git reflog
Run Code Online (Sandbox Code Playgroud)

并将当前分支重置为它(通常在使用该--hard选项重新设置之前绝对确定).

假设旧提交HEAD@{5}在ref日志中:

git reset --hard HEAD@{5}
Run Code Online (Sandbox Code Playgroud)

在Windows中,您可能需要引用引用:

git reset --hard "HEAD@{5}"
Run Code Online (Sandbox Code Playgroud)

您可以通过执行a git log HEAD@{5}(Windows :)来检查候选旧头的历史记录git log "HEAD@{5}".

如果你没有禁用每个分支reflogs,你应该能够简单地做,git reflog branchname@{1}因为rebase在重新连接到最终头之前分离分支头.我会仔细检查这个,尽管我最近没有证实这一点.

默认情况下,为非裸存储库激活所有reflog:

[core]
    logAllRefUpdates = true
Run Code Online (Sandbox Code Playgroud)

  • 以防万一,首先进行备份:`git tag BACKUP`.如果出现问题你可以返回它:`git reset --hard BACKUP` (284认同)
  • Git reflog很棒,只记得你可以用`git log -g`获得更好的格式化输出(来自Scott Chacon的http://progit.org/book). (103认同)
  • @Zach:`git rebase --abort`(`-i`对`--abort`毫无意义)是放弃一个尚未完成的rebase - 要么是因为存在冲突,要么是因为它是交互式的,或者两者兼而有之; 这不是要取消成功的变革,这就是问题所在.您可以使用`rebase --abort`或`reset --hard`取决于您所处的情况.您不应该同时执行这两种操作. (56认同)
  • 如果你做了很多提交,那么你要找的HEAD @ {#}将以`commit:`开头,而不是`rebase:`.听起来很明显,但它让我有点困惑. (6认同)
  • 根据艾伦下面的回答,还需要“git rebase -i --abort”。仅上述还不够。 (3认同)
  • 在意外变装后参加聚会:D.在意外重组之后,"git reset - hard ORIG_HEAD"不会立即行动吗? (2认同)

Pat*_*otz 1426

实际上,rebase会保存你的起点,ORIG_HEAD所以这通常很简单:

git reset --hard ORIG_HEAD
Run Code Online (Sandbox Code Playgroud)

reset,rebasemerge所有的原始保存HEAD指针变成ORIG_HEAD这样,如果你因为你试图撤消,那么你就必须使用引用日志底垫做过任何的命令.

  • 如果'ORIG_HEAD`不再有用,你也可以使用`branchName @ {n}`语法,其中`n`是分支指针的第n个先前位置.因此,例如,如果你将`featureA`分支重新绑定到你的`master`分支,但是你不喜欢rebase的结果,那么你可以简单地执行`git reset --hard featureA @ {1}`来重置分支回到你做rebase之前的确切位置.您可以在[官方Git docs for revisions](http://git-scm.com/docs/gitrevisions)上阅读有关@ {n}分支语法的更多信息. (29认同)
  • 这是最简单的.然后使用`git rebase --abort`跟进它. (14认同)
  • @Seph你能解释为什么你建议跟进`git rebase --abort`吗? (5认同)
  • 是否可以先检查 ORIG_HEAD 的提交是什么? (4认同)
  • 让我补充一下:`git reset --hard ORIG_HEAD`可以反复使用以一次又一次地回滚。假设,如果A ---重新设置为B ---重新设置为C,现在我在C,则可以使用两次git reset --hard ORIG_HEAD来返回A。 (3认同)

小智 363

查尔斯的答案有效,但你可能想这样做:

git rebase --abort
Run Code Online (Sandbox Code Playgroud)

之后清理reset.

否则,您可能会收到消息" Interactive rebase already started".

  • 那不是问题.该问题询问如何撤消已完成的rebase. (49认同)
  • 虽然这可能不是答案,但此信息至关重要,而答案却没有。使用“reflog”和“reset --hard”后,您可能仍然需要中止变基才能恢复正常。 (6认同)
  • 这个在我的提示中删除了"| REBASE"部分.+1 (4认同)

Ari*_*zis 87

将分支重置为其旧提示的悬空提交对象当然是最佳解决方案,因为它可以在不花费任何精力的情况下恢复之前的状态.但是,如果您碰巧丢失了这些提交(因为您在此期间垃圾收集了您的存储库,或者这是一个新的克隆),您可以再次重新绑定该分支.关键是--onto交换机.

比方说,你有一个特性分支想象力叫topic,你分支master时的尖端master0deadbeef提交.在topic分支的某个时刻,你做到了git rebase master.现在你要撤消这个.这是如何做:

git rebase --onto 0deadbeef master topic
Run Code Online (Sandbox Code Playgroud)

这将采取所有提交的topic使不上master重放一遍之上0deadbeef.

有了--onto,您可以将历史重新排列成几乎任何形状.

玩得开心.:-)

  • 我认为这是最好的选择,因为它的灵活性.我将b1从master分支出来,然后将b1重新命名为新的分支b2,然后又想将b1恢复为基于master的.我只是喜欢git - 谢谢! (3认同)
  • 这是最好的选择!它保留了我当前分支上的所有更改,并删除了所有不需要的更改! (2认同)

Ale*_*her 69

在我做任何非常重要的操作之前,我实际上在分支上放了一个备份标签(大多数rebase都很简单,但是如果它看起来很复杂的话我会这样做).

然后,恢复就像一样容易git reset --hard BACKUP.

  • 你实际上甚至不需要创建备份分支,你可以简单地使用`branchName @ {n}`语法,这里`n`是分支指针的第n个先前位置.因此,例如,如果你将`featureA`分支重新绑定到你的`master`分支,但是你不喜欢rebase的结果,那么你可以简单地执行`git reset --hard featureA @ {1}`来重置分支回到你做rebase之前的确切位置.您可以在[官方Git docs for revisions](http://git-scm.com/docs/gitrevisions)上阅读有关`branch @ {n}`语法的更多信息. (11认同)
  • 我曾经也是这样做的,但是因为我对reflog更加满意,所以我不再认为这是必要的.每次更改HEAD时,reflog基本上都是代表您执行此操作. (5认同)
  • 好吧,我更喜欢有意义的名字,因为在reflog中搜索正确的项目有时根本不好玩. (4认同)
  • 我也是这样做的.git diff BACKUP..HEAD也很有用,可以确保你改变了你想要的东西. (2认同)
  • 实际上,你甚至不需要使用上面的语法,根据[Pat Notz的答案](http://stackoverflow.com/a/692763/456814),分支的原始`HEAD`暂时存储在` ORIG_HEAD`.但是使用备份分支标签的技术也有效,它只是更多步骤. (2认同)

Mak*_*sym 61

如果您已经将分支推送到远程存储库(通常是它的原点),然后您已经完成了成功的rebase(没有合并)(git rebase --abort给出"没有正在进行的rebase"),您可以使用命令轻松地重置分支:

git reset --hard origin/{branchName}

例:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.

nothing to commit, working directory clean
Run Code Online (Sandbox Code Playgroud)


小智 26

git reset --hard origin/{branchName}
Run Code Online (Sandbox Code Playgroud)

是重置所有由 rebase 完成的本地更改的正确解决方案。

  • 如果存在未推送的本地提交,这可能会导致问题。被警告 (10认同)
  • 这是一个非常干净的解决方案。感谢您的发表。我总是在进行 rebase 之前推送到远程,这篇文章救了我的命,因为我在一个大项目上与 master 的时间已经过时了大约 3 天。谢谢 :) (7认同)

Kri*_*ris 20

使用reflog对我不起作用.

对我有用的东西与此处描述的类似.打开以重新分支的分支命名的.git/logs/refs中的文件,找到包含"rebase finsihed"的行,如:

5fce6b51 88552c8f Kris Leech <me@example.com> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878
Run Code Online (Sandbox Code Playgroud)

签出该行上列出的第二个提交.

git checkout 88552c8f
Run Code Online (Sandbox Code Playgroud)

一旦确认,这包含了我失去的变化,我分支并松了一口气.

git log
git checkout -b lost_changes
Run Code Online (Sandbox Code Playgroud)

  • 哇 - 从那个链接,"有一个警告:我失去了分支的历史,但在这种情况下它并不重要.我很高兴能找回我的变化." ? (2认同)
  • 谢谢你,伙计,你救了我的命。对我来说,我有“rebase (finish):”,后面跟着 3 个提交 ID。第二个 ID 是正确的。 (2认同)

Gre*_*ill 16

对于多次提交,请记住任何提交都会引用导致该提交的所有历史记录.所以在查尔斯的回答中,将"旧提交"称为"最新的提交".如果重置为该提交,则会重新出现导致该提交的所有历史记录.这应该做你想要的.


Mat*_*ipe 11

根据@Allan和@Zearin的解决方案,我希望我可以简单地做一个评论,但我没有足够的声誉,所以我使用了以下命令:

而不是做的git rebase -i --abort (注意-i),我不得不简单地做git rebase --abort(没有-i).

使用两者-i--abort同时使Git向我显示使用/选项列表.

因此,此解决方案的先前和当前分支状态为:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$
Run Code Online (Sandbox Code Playgroud)


Ser*_*ure 11

如果您成功地针对远程分支进行了重新设置,那么git rebase --abort您仍然可以做一些技巧来保存您的工作并且没有强制推送.假设您的当前分支被错误地重新命名your-branch并且正在跟踪origin/your-branch

  • git branch -m your-branch-rebased #重命名当前分支
  • git checkout origin/your-branch #checkout到原始已知的最新状态
  • git checkout -b your-branch
  • 检查git log your-branch-rebased,比较git log your-branch和定义缺少的提交your-branch
  • git cherry-pick COMMIT_HASH 每次提交 your-branch-rebased
  • 推动你的改变.请注意,两个本地分支机构相关联,remote/your-branch您应该只推送your-branch


Guy*_*lks 11

另一种不需要进行硬重置的方法是使用您所需的起点创建一个新分支。

与其他解决方案一样,您可以使用引用日志来查找正确的起点。

git reflog
Run Code Online (Sandbox Code Playgroud)

(您也可以使用git log -g此处了解更多详细信息)

然后您记下对提交 SHA 的引用(例如:e86a52b851e)。

最后,使用 gitbranch 命令。

git branch recover-branch e86a52b851e
Run Code Online (Sandbox Code Playgroud)

参考: https: //git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery#_data_recovery


And*_*rew 10

如果您不想进行硬重置...

您可以从 reflog 中检出提交,然后将其保存为新分支:

git reflog
Run Code Online (Sandbox Code Playgroud)

在开始变基之前找到提交。您可能需要进一步向下滚动才能找到它(按 Enter 或 PageDown)。记下 HEAD 编号并替换 57:

git checkout HEAD@{57}
Run Code Online (Sandbox Code Playgroud)

查看分支/提交,如果正确,则使用此 HEAD 创建一个新分支:

git checkout -b new_branch_name
Run Code Online (Sandbox Code Playgroud)


dev*_*ole 6

如果您在分支机构,您可以使用:

git reset --hard @{1}
Run Code Online (Sandbox Code Playgroud)

不仅有 HEAD 的参考日志(由 获得git reflog),还有每个分支的引用日志(由 获得git reflog <branch>)。因此,如果您在,master那么git reflog master将列出该分支的所有更改。master@{1}您可以通过、master@{2}等来参考该更改。

git rebase通常会多次更改 HEAD,但当前分支只会更新一次。

@{1}只是当前分支的快捷方式,因此它等于master@{1}if you are on master

git reset --hard ORIG_HEADgit reset如果您在交互过程中使用,将不起作用rebase


Har*_*dev 5

假设我将 master 重新设置为我的功能分支,并且我收到了 30 个新提交,这些提交破坏了某些内容。我发现通常删除错误的提交是最简单的。

git rebase -i HEAD~31
Run Code Online (Sandbox Code Playgroud)

最后 31 次提交的交互式变基(如果您选择太多也没有什么坏处)。

只需获取您想要删除的提交并用“d”而不是“pick”标记它们即可。现在,提交已被有效删除,从而撤消变基(如果您仅删除变基时刚刚获得的提交)。