需要注意的是 rebase 操作并不会重写历史或移动提交记录,Git 中的提交记录是无法改变的。相反,它会创建新的历史记录并称一直以来都是那样的。例如,当你从以下提交记录开始:
4-5-6(feature)
|
1-2-3(master)
|
7(bugfix)
而当你执行
git rebase bugfix feature
命令时,实际上发生的是这样的:
4-5-6
|
1-2-3(master)
|
7(bugfix)-4A-5A-6A(feature)
三个新的提交被创建,分别是4A、5A和6A。原始的提交还在那里,但没有任何指向它们的内容。它们最终将被清理,但它们会保留一段时间。
这意味着您可以撤消一个 rebase 操作,这就是您想要做的事情。您需要找到在 rebase 之前的 feature。可以使用 git reflog 来完成此操作,它会跟踪每次 HEAD 移动的情况。这发生在 checkout、commit、reset 和 rebase 中。git reflog 可能是这样的:
65e93ca (HEAD -> feature) HEAD@{0}: rebase finished: returning to refs/heads/feature
65e93ca (HEAD -> feature) HEAD@{1}: rebase: 3 feature
6d539a3 HEAD@{2}: rebase: 2 feature
3cd634f HEAD@{3}: rebase: 1 feature
b84924b (bugfix) HEAD@{4}: rebase: checkout bugfix
a9fd2f1 HEAD@{5}: commit: 3 feature
29136bc HEAD@{6}: commit: 2 feature
60543b0 HEAD@{7}: commit: 1 feature
c487530 (master) HEAD@{8}: checkout: moving from master to feature
这告诉我 a9fd2f1 是在 feature 分支被 rebase 之前的最后一次提交。我可以将 feature 分支移回来,而不需要重新做 rebase。
git checkout feature
git reset --hard a9fd2f1
在未来,如果您在做变基之前使用
git tag
标记功能的原始位置,这样的事情会变得更加容易。然后,您可以使用
git reset
回到该标记,而无需搜索reflog。
至于您特定的问题,问题在于变基之后您的存储库现在看起来像这样:
6A [feature]
|
5A
|
4A
|
7 [bugfix]
|
3 [master]
|
2
|
1
当你执行
git rebase master feature
时,Git会注意到master已经是feature的祖先,因此不会进行任何操作。即使bugfix在中间也没有关系。
相反,你需要告诉Git只想要将4A、5A和6A变基,而忽略7。这可以使用
--onto
语法来实现。
git rebase --onto master bugfix feature
这句话意思是将 bugfix
到 feature
但不包括bugfix
的部分进行变基(rebase)到主分支 master
。
我建议使用 git reset
而不是尝试重新进行变基。特别是如果有冲突,第二次变基不能保证结果会相同。而使用 git reset
时,显式地回到了该仓库的旧状态。