3758

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

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

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

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

然而,我的方法给我的印象是次优且容易出错(假设我刚刚用我自己的 2 个分支重新设置了基础)。

有任何想法吗?

澄清:我说的是重放一堆提交的rebase。不止一个。

4

19 回答 19

5164

最简单的方法是找到分支的头部提交,因为它是在reflog中 rebase 开始之前的那一刻......

git reflog

并将当前分支重置为它(通常需要注意的是在使用--hard选项重置之前要绝对确定)。

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

git reset --hard HEAD@{2}

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

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

git log HEAD@{2}您只需执行( Windows: git log "HEAD@{2}" )即可检查候选老头的历史记录。

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

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

[core]
    logAllRefUpdates = true
于 2008-09-25T19:56:28.343 回答
1741

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

git reset --hard ORIG_HEAD

但是,resetrebaseallmerge将您的原始HEAD指针保存到ORIG_HEADso 中,如果您在尝试撤消 rebase 后执行了这些命令中的任何一个,那么您将不得不使用 reflog。

于 2009-03-28T13:24:50.743 回答
450

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

git rebase --abort

清理之后reset

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

于 2009-07-27T18:21:54.227 回答
107

将分支重置为其旧提示的悬空提交对象当然是最好的解决方案,因为它无需花费任何努力即可恢复先前的状态。但是如果你碰巧丢失了这些提交(例如,因为你同时垃圾收集了你的存储库,或者这是一个新的克隆),你总是可以再次重新设置分支。关键是--onto开关。

假设您有一个想象性地称为的主题分支,当提交的尖端是topic您分支的时候。在分支上的某个时刻,你做到了。现在您要撤消此操作。就是这样:mastermaster0deadbeeftopicgit rebase master

git rebase --onto 0deadbeef master topic

这将接受所有topic未打开的提交master并在0deadbeef.

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

玩得开心。:-)

于 2008-09-26T02:08:44.970 回答
95

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

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
于 2015-09-28T12:43:48.797 回答
75

实际上,在执行任何重要操作之前,我在分支上放置了一个备份标记(大多数变基都是微不足道的,但如果它看起来很复杂,我会这样做)。

然后,恢复就像git reset --hard BACKUP.

于 2009-05-12T20:57:24.453 回答
48
git reset --hard origin/{branchName}

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

于 2019-05-06T08:04:45.020 回答
29

使用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
于 2012-02-20T13:59:06.350 回答
16

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

于 2008-09-25T21:36:50.693 回答
14

如果您成功地针对远程分支重新定位并且不能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
于 2016-06-23T09:23:45.167 回答
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)
$
于 2015-03-11T21:26:47.550 回答
11

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

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

git reflog

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

git checkout HEAD@{57}

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

git checkout -b new_branch_name
于 2019-05-29T17:56:53.927 回答
4

假设我将 master 重新定位到我的功能分支,我得到了 30 个新的提交,这些提交破坏了一些东西。我发现通常最容易删除错误的提交。

git rebase -i HEAD~31

最后 31 次提交的交互式变基(如果你选择太多也没关系)。

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

于 2017-02-09T12:25:35.240 回答
4

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

git reset --hard @{1}

不仅有 HEAD 的参考日志(通过 获得git reflog),每个分支也有 reflogs(通过 获得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_HEAD如果您git reset在交互式rebase.

于 2019-01-10T12:21:58.307 回答
4

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

与其他解决方案一样,您使用 reflog 来找到正确的起点。

git reflog

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

然后您注意对提交 SHA 的引用(例如:)e86a52b851e

最后,您使用 git branch 命令。

git branch recover-branch e86a52b851e

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

于 2021-07-01T22:47:25.017 回答
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"

您应该能够对此进行调整,以允许很容易地返回任意数量的变基(处理 args 是最棘手的部分),如果您快速连续地执行多个变基并在此过程中搞砸了一些事情,这将很有用。

注意事项

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

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

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

我没有这样做的原因是因为我不是 100% 的变基总是从结帐开始。谁能证实这一点?

:[如果您对函数开头的null ( ) 命令感到好奇,这是为别名设置 bash 补全的一种方式]

于 2020-07-19T22:47:40.903 回答
2

我通常做的是 git reset #commit_hash

到我认为 rebase 无效的最后一次提交。

然后 git pull

现在,您的分支应该与 master 完全匹配,并且 rebased 提交不应该在其中。

现在可以只挑选这个分支上的提交。

于 2019-06-19T14:39:49.543 回答
1

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

于 2020-02-16T19:06:45.363 回答
-5

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

于 2016-03-09T09:19:08.793 回答