撤销 Git Rebase

4247
我如何轻松撤销 git rebase? 一种冗长的手动方法是:
  1. 检出两个分支的提交父级
  2. 创建和检出临时分支
  3. 手动挑选所有提交
  4. 将有问题的重建分支重置为指向临时分支
在我的当前情况下,这可以工作,因为我可以轻松地识别两个分支的提交(一个是我的东西,另一个是我的同事的东西)。然而,我的方法让我感觉不太理想并且容易出错(假设我刚刚重建了两个自己的分支)。 澄清一下:我说的是在重新播放了多个提交期间进行的rebase,而不仅仅是一个。

commit:是你想要重置到HEAD@{#}的内容。不是rebase:reset:merge:checkout: - cachius
19个回答

16

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

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

git reflog

找到在你开始变基之前的提交。您可能需要向下滚动以查找它(按Enter或PageDown键)。注意HEAD号并替换57:

git checkout HEAD@{57}

审核分支/提交记录,如果正确,则使用此HEAD创建新的分支:

git checkout -b new_branch_name

13

跟随@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)
$

10

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

与其他解决方案一样,您可以使用reflog查找正确的起始点。

git reflog

你还可以在此处使用git log -g以获取更多详细信息。

然后,你需要注意到提交SHA(例如:e86a52b851e)的引用。

最后,你需要使用git branch命令。

git branch recover-branch e86a52b851e

参考文献:https://git-scm.com/book/zh/v2/Git-内部原理维护及数据恢复#_data_recovery


6
如果您当前处于一个分支上,您可以使用以下命令:
git reset --hard @{1}

不只是 git reflog 命令可以得到 HEAD 的参考日志,每个分支都有自己的参考日志(通过 git reflog <branch>)。因此,如果你在 master 分支上,则 git reflog master 将列出该分支的所有更改。您可以使用 master@{1}master@{2} 等方式引用这些更改。

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

@{1} 只是对“当前分支”的一个快捷方式,所以如果你在 master 上,它等同于 master@{1}

git reset --hard ORIG_HEAD 如果在交互式 rebase 过程中使用了 git reset,则无法正常工作。


5

假设我将主分支rebase到我的特性分支,然后我得到了30个新的提交,这些提交导致一些问题。我发现最简单的方法通常是删除有问题的提交。

git rebase -i HEAD~31

对最近的31个提交进行交互式变基(如果您选择了太多提交,也不会有影响)。

只需选取您想要删除的提交,并将它们标记为“d”而不是“pick”。现在,这些提交将被删除,从而撤销变基操作(如果您仅删除重新定位时获取的提交)。


4

我通常做的是

git reset #commit_hash

重置到我认为rebase没有影响的最后一个提交。

接着执行

git pull

现在,您的分支应该与master完全匹配,而rebase提交不应该出现其中。

现在可以在此分支上挑选提交。


3

我非常烦恼的是,尽管它应该是可自动化的(至少大部分是),但这些答案中没有一个是完全自动的。我创建了一组别名来尝试解决这个问题:

# Useful commands
#################

# Undo the last rebase
undo-rebase = "! f() { : git reset ; PREV_COMMIT=`git x-rev-before-rebase` && git reset --merge \"$PREV_COMMIT\" \"$@\";}; f"

# See what changed since the last rebase
rdiff = "!f() { : git diff ; git diff `git x-rev-before-rebase` "$@";}; f"

# Helpers
########
# Get the revision before the last rebase started
x-rev-before-rebase = !git reflog --skip=1 -1 \"`git x-start-of-rebase`\" --format=\"%gD\"

# Get the revision that started the rebase
x-start-of-rebase = reflog --grep-reflog '^rebase (start)' -1 --format="%gD"

您应该能够轻松地调整它,以允许任意数量的变基后退(操作参数最棘手的部分),如果您在快速进行多个变基的过程中出了差错,则这可能非常有用。

注意事项

如果任何提交消息以“rebase(start)”开头,它将感到困惑(请不要这样做)。您可以通过匹配此类正则表达式来使正则表达式更具弹性以改善情况:

--grep-reflog "^rebase (start): checkout " 

警告:未经测试(正则表达式可能需要调整)

我还没有这样做的原因是因为我不确定每次 rebase 都始于 checkout。有人能证实一下吗?

[如果你对函数开头的空命令(:)感到好奇,那是为了为别名设置 bash 自动补全的一种方式]


1

我尝试了重置和reflog的所有建议,但没有成功。恢复IntelliJ的本地历史记录解决了文件丢失的问题。


-5

如果在 git rebase 中出现问题,例如 git rebase --abort,而您有未提交的文件,则它们将丢失,并且 git reflog 将无法帮助您。这种情况发生在我身上,您需要在此处打破常规思维方式。如果您像我一样幸运地使用 IntelliJ Webstorm,则可以通过 右键单击->本地历史记录,无论您在版本控制软件中犯了什么错误,都可以恢复到文件/文件夹的先前状态。始终保持另一个故障转移运行是很好的。


6
git rebase --abort 中止正在进行的变基操作,它并不会撤销已经完成的变基操作。 同时使用两个版本控制系统并不是一个好主意。虽然Jetbrains软件中有这个功能,但你不应该同时使用两种版本控制系统。最好只学习Git,特别是在Stack Overflow上回答关于Git的问题时。 - dudewad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接