撤消git rebase


3177

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

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

  • git签出两个分支的提交父对象
  • 然后从那里创建一个临时分支
  • 手动选择所有提交
  • 用手动创建的分支替换我重新建立基础的分支

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

但是,我的方法给我的印象是次优且容易出错(例如,我刚刚使用自己的两个分支进行了重新基准化)。

有任何想法吗?

澄清:我说的是在重新部署一堆提交时进行的重新部署。不只是一个


6
还请注意,在重新设置基准期间,您可以排除或压缩提交;如果没有指向原始节点的指针或无法通过reflog进行筛选,则这些更改将不可还原,因此无法进行挑选。
2011年

Answers:


4333

最简单的方法是找到分支的头提交,就像在reflog中重新启动基础之前一样。

git reflog

并将其重置为当前分支(通常的警告是在使用该--hard选项重置之前必须绝对确定)。

假设旧的提交HEAD@{5}在引用日志中:

git reset --hard HEAD@{5}

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

git reset --hard "HEAD@{5}"

您只需执行git log HEAD@{5}Windows :),即可检查候选旧头的历史git log "HEAD@{5}"

如果您尚未针对每个分支的更新禁用它,那么您应该能够简单地执行此操作,git reflog branchname@{1}因为在重新连接到最终头之前,通过一个变基将分支头分离。我会再次检查,尽管最近还没有验证。

默认情况下,针对非裸存储库激活所有引用日志:

[core]
    logAllRefUpdates = true

113
Git reflog很棒,只记得您可以使用git log -g(Scott Chacon的progit.org/book技巧)获得更好的格式化输出。
karmi 2010年

60
@Zach: git rebase --abort-i没有意义有--abort)可以放弃尚未完成变基-要么是因为有冲突,或者因为它是互动或两者; 问题不在于撤销成功的重新建立基础。你要么使用rebase --abortreset --hard根据自己的情况你在,你不应该需要做两件事。
CB Bailey

310
以防万一,请先备份:git tag BACKUP。如果出现问题,您可以返回git reset --hard BACKUP
至此

6
如果你已经做了很多提交的HEAD @ {#}你正在寻找将与开头commit:,而不是rebase:。听起来很明显,但是让我有些困惑。
2013年

4
意外改组后加入聚会:D。git reset --hard ORIG_HEAD意外变基之后,立即采取措施也不会吗?
quaylar

1485

实际上,rebase将您的起点保存到了,ORIG_HEAD因此这通常很简单:

git reset --hard ORIG_HEAD

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


34
如果ORIG_HEAD不再有用,也可以使用branchName@{n}语法,其中n分支指针的第n个在前位置。因此,例如,如果您将featureA分支重新设置到master分支上,但是您不喜欢重新设置的结果,则只需git reset --hard featureA@{1}将分支重新设置为恰好进行重新设置之前的位置即可。您可以在官方的Git文档中阅读有关branch @ {n}语法的更多信息以进行修订

15
这是最简单的。跟随它,git rebase --abort尽管。
Seph 2015年

1
@DaBlick在完全成功重新设置基础且没有任何冲突之后,对我来说效果很好git 2.17.0
dvlsg

4
让我补充一下:git reset --hard ORIG_HEAD可以反复使用来回滚。假设,如果A ---将git reset --hard ORIG_HEAD
基准

5
@Seph您能解释一下为什么建议跟进git rebase --abort吗?
UpTheCreek

385

查尔斯的答案有效,但您可能需要这样做:

git rebase --abort

清理后reset

否则,您可能会收到消息“ Interactive rebase already started”。


4
这一步删除了我提示中的“ | REBASE”部分。+1
Wouter Thielen 2014年

62
那不是问题。问题询问如何撤消完成的变基。
Arunav Sanyal

2
应该是对Charles的回答的评论,因为它没有回答关于它的问题
Murmel

嗯,我不必那样做。
维克多·塞奇(ViktorSeč)

1
唯一为我工作的人!
亚历山大·皮卡德

90

将分支重置为其旧提示的悬挂提交对象当然是最好的解决方案,因为它无需花费任何精力即可恢复先前的状态。但是,如果您恰巧丢失了这些提交(例如,因为在此期间您对存储库进行了垃圾回收,或者这是一个新的克隆),则始终可以重新建立分支的基础。关键是--onto开关。

假设您有一个想象中的主题分支topicmaster当提交的尖端master0deadbeef提交时分支出来。在topic分支机构的某个时候,您做到了git rebase master。现在您要撤消此操作。就是这样:

git rebase --onto 0deadbeef master topic

这将接受所有未提交的提交topicmaster并在之上重播它们0deadbeef

使用--onto,您可以将您的历史重新排列成几乎任何形状

玩得开心。:-)


3
我认为这是最好的选择,因为它具有灵活性。我将b1从master分支出来,然后将b1重新建立为新的分支b2,然后又想将b1恢复为基于master。我只是喜欢git-谢谢!
ripper234

2
这是这里最好的选择!它保留了我当前分支上的所有更改,并删除了所有不需要的更改!
艾丽西娅·唐

我想说,带的组合--onto,并-i可以重新布置历史进入几乎任何形状任何责任。使用gitk(或在Mac上为gitx)查看制作的形状:-)。
rjmunro

69

实际上,在执行任何无关紧要的操作之前,我实际上在分支上放置了一个备份标签(大多数rebase是无关紧要的,但是如果看起来很复杂,我会这样做)。

然后,还原就像一样容易git reset --hard BACKUP


2
我也是 git diff BACKUP..HEAD也很有用,以确保您更改了要更改的内容。
Paul Bone

5
我曾经也这样做,但是由于我对reflog更加满意,所以我不再觉得这是必要的。每次更改HEAD时,reflog基本上都是代表您执行此操作。
皮特·霍奇森

4
好吧,我更喜欢有意义的名称,因为在reflog中搜索正确的项目有时一点都不有趣。
亚历克斯·冈特马赫

12
实际上,您甚至不需要建立备份分支,只需使用branchName@{n}语法即可,这n是分支指针的第n个优先位置。因此,例如,如果您将featureA分支重新设置到master分支上,但是您不喜欢重新设置的结果,则只需git reset --hard featureA@{1}将分支重新设置为恰好进行重新设置之前的位置即可。您可以branch@{n}Git官方文档中阅读有关语法的更多信息以进行修订

2
实际上,您甚至不需要使用上面的语法,根据Pat Notz的回答HEAD分支的原始内容临时存储在中ORIG_HEAD。但是使用备份分支标签的技术也可以使用,只是更多步骤。

68

如果您已将分支推送到远程存储库(通常是它的原点),然后成功完成了一次完整的rebase(没有合并)(git rebase --abort给出“ No rebase in progress”),则可以使用以下命令轻松重置分支

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

这对我来说是正确的答案。在重新设置基准之前,重新设置基准和提交具有相同的提交ID,并且回到HEAD {1}只是不会恢复重新基准!
Bill Kotsias '17

23

使用reflog对我不起作用。

对我有用的类似于此处所述。在.git / logs / refs中打开文件,该文件以经过重新基准化的分支命名,并找到包含“ rebase finsihed”的行,如下所示:

5fce6b51 88552c8f Kris Leech <me@example.com> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

检出该行上列出的第二个提交。

git checkout 88552c8f

一旦确认其中包含我丢失的更改,我便分支了,松了一口气。

git log
git checkout -b lost_changes


3
哇-从该链接开始,“有一个警告:我丢失了分支的历史记录,但在这种情况下,这并不重要。我很高兴能够检索到我的更改。” ?
鲁芬2012年

16

对于多个提交,请记住任何提交都引用导致该提交的所有历史记录。因此,在Charles的回答中,将“旧提交”读为“最新的旧提交”。如果您重置为该提交,那么导致该提交的所有历史记录将重新出现。这应该做您想要的。


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)
$

11

如果您成功地根据远程分支重新建立了基础,并且git rebase --abort仍然无法进行操作,那么您仍然可以采取一些技巧来保存您的工作,而不必强制执行。假设您的当前分支被错误地重新建立了基础your-branch并正在跟踪origin/your-branch

  • git branch -m your-branch-rebased #重命名当前分支
  • git checkout origin/your-branch #签出到已知起源的最新状态
  • 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

4

假设我将master重新设置为功能分支,并获得30项新的提交,这些提交可能会破坏某些功能。我发现通常最简单的方法就是删除错误的提交。

git rebase -i HEAD~31

最后31次提交的交互式变基(如果选择太多,这不会受到损害)。

只需删除要删除的提交,并用“ d”(而不是“ pick”)标记它们即可。现在,将删除提交,从而有效地撤消了重新设置的基础(如果仅删除在重新定基时刚刚获得的提交)。


3

对于新手/过于害怕硬重置的人,您可以从reflog中检出提交,然后将其另存为新分支。

git reflog

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

git checkout HEAD@{57}

查看分支/提交,如果看起来不错,请使用此HEAD创建一个新分支:

git checkout -b new_branch_name

2

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

git reset --hard @{1}

不仅有HEAD的参考日志(由获取git reflog),还有每个分支的参考日志(由获取git reflog <branch>)。所以,如果你是master那么git reflog master就会列出所有更改该分支。你可以参考由变化master@{1}master@{2}等等。

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

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

git reset --hard ORIG_HEAD如果您git reset在互动过程中使用过,将无法使用rebase


1

我通常要做的是 git reset #commit_hash

到最后一次提交,我认为重新设置没有任何作用。

然后 git pull

现在,您的分支应该完全匹配,就像master一样,并且不应该包含重新提交的提交。

现在,您可以只选择在该分支上的提交。


1

我尝试过使用reset和reflog的所有建议,但均未成功。恢复IntelliJ的本地历史记录解决了文件丢失的问题


谢谢!以前从未使用过本地历史记录,但是事实证明,这对我来说是恢复一些意外重新构建代码的最简单选择。非常好,但有些隐藏的功能。
Magnus W

0

git reset --hard origin / {branchName}

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


1
如果您硬重设,则origin/branch可能会丢失HEAD与该点之间的更改。一般来说,您不希望这样做。
bluesmonk

这正是我想要的情况。好赞
Mandar Vaze

-4

如果您在git rebase中弄乱了某些东西,例如git rebase --abort,当您有未提交的文件时,它们将丢失并且git reflog无济于事。这发生在我身上,您将需要在这里跳出框框。如果像我一样幸运并使用IntelliJ Webstorm,那么right-click->local history无论您使用版本控制软件犯了什么错误,都可以并且可以恢复到文件/文件夹的先前状态。再次运行故障安全总是好事。


5
git rebase --abort中止活动的基准,它不会撤消基准。同样,同时使用两个VCS是一个坏主意。它是Jetbrains软件中的一个不错的功能,但您不应同时使用两者。最好只学习Git,特别是在有关Stack Git的Stack Overflow问题上回答时。
dudewad
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.