首页 > 解决方案 > git rebase 之后的变化怎么办?

问题描述

我正在将一个分支重新feature建立在另一个分支上master。在 rebase 期间,一些文件会以一种在 rebase 完成时导致编译错误的方式自动合并。我在现在重新建立的分支上修复了这些错误feature,因此如果更改了文件,则有一组。

理想情况下,我希望提交日志保存来自 的提交master,然后是来自feature(而不是其他提交)的提交,但是更改必须在某个地方进行。

处理因变基而导致的此类更改的“最佳实践”是什么?您是否将它们放在单独的提交中feature?将它们压缩到现有的提交中feature(无论如何我都会强制推送)?

或者有没有办法完全避免这个问题?例如,有没有一种方法可以在应用最后一次提交之后feature停止变基,但 git 将变基注册为已完成之前?如果有我可以在这个时候构建和修复,然后做一个最终的git rebase --continue

标签: gitworkflowrebase

解决方案


请记住,rebase 通过复制提交来工作。原始提交保持不变。例如,假设您有以下一系列提交:

...--G--H--K--L   <-- master
         \
          I--J   <-- feature

在这里,Alice 进行了提交I,并且J一个接一个地提交H(这些字母中的每一个都代表一些丑陋的 Git 哈希 ID)。大约在同一时间(不久之前和/或之后),Bob 做出了提交KL在 master 之上。

某人——最好的情况通常是这个“某人”就是 Alice 自己——现在被赋予了提出一些新的和改进的提交的工作,我们将其称为I'and ,这与提交J'非常相似IJ但是:

  • 追随K-和- L
  • 有不同的快照,因为它们基于 Kand L; 和
  • 需要进行任何其他更改以使其正常工作。

爱丽丝可以运行:

git checkout feature
git rebase master

Git 会尽最大努力自己做出新的I'提交J'

                I'-J'  <-- feature
               /
...--G--H--K--L   <-- master
         \
          I--J   [abandoned]

如果Git认为情况不妙,Git将停止并要求 Alice 修复Git在此复制过程中检测到的任何合并冲突,然后 Git 会移动分支名称以定位 commit 。但是 Git 不是很聪明,如果 Git 认为一切进展顺利,Git 就会继续运行并完成 rebase,生成这些实际上不起作用的副本。featureJ'

如果是这样的话,Alice 的工作(或者任何做 rebase 的人)来控制 Git。例如,她可以使用命令git rebase -i替换一个或所有pick命令edit。然后,Git 将在每次挑选后停止——请记住,rebase 的提交复制是一系列git cherry-pick操作——并允许 Alice修复提交。她可以构建和测试系统,定位任何错误,进行一些编辑,并运行git addgit commit --amend根据需要修复它们,例如:

                I'  <-- HEAD
               /
...--G--H--K--L   <-- master
         \
          I--J   <-- feature

和:

                I'  [abandoned]
               /
              | I"  <-- HEAD
              |/
...--G--H--K--L   <-- master
         \
          I--J   <-- feature

然后运行git rebase --continue让 Git 继续进行樱桃采摘JJ'然后由于另一个原因再次停止edit

                I'  [abandoned]
               /
              | I"-J'  <-- HEAD
              |/
...--G--H--K--L   <-- master
         \
          I--J   <-- feature

如果有必要,Alice 现在可以git commit --amend像以前一样使用(连同预提交步骤)替换J'J".

最终结果可能是一系列替换提交。当 rebase 完成时,Git 将名称移动feature到最后一个复制的提交:

                I'  [abandoned]
               /
              | I"-J'  <-- feature
              |/
...--G--H--K--L   <-- master
         \
          I--J   [abandoned]

从这张图片中删除废弃的(和不可见的)提交,我们现在有一个完全可用的更新feature. 新副本的哈希 ID I"(修改 fromI'以使其工作)和J'(毕竟立即工作)与原始副本的哈希 ID 不同,I并且J同样不可见,因为没有注意到这些哈希 ID。

(但是请注意,Git 会注意到哈希 ID——事实上,这是 Git真正关心的——所以 Alice和其他所有人都小心不要重新引入原始IJ提交,这一点很重要。只有 Alice 有任何临时提交在rebase-and-edit 过程,所以只有 Alice 必须小心不要重新引入这些,Alice 不太可能会意外这样做。但是如果提交I并被J分发给其他 Git 用户,而其他 Git 用户现在拥有它们,那些其他 Git 用户很容易意外地重新引入。IJ

这不是您唯一的选择

如果你是爱丽丝,你可以:

  • 一次完成整个变基;
  • 最后只检查一次错误;
  • 定位这些错误;和
  • 用于git rebase -i选择要修改的特定提交。

您还可以使用 进行“修复”提交git commit --fixup,然后使用git rebase -i --autosquashGit 帮助更新交互式变基命令表。这是实现与上述相同结果的更高级方法。

(请注意,如果最终提交以某种方式修复了它,那么这种方式很容易错过错误的中间提交。)

额外的变基技巧

如果您有可以发现这些问题的自动化测试(这可能就像编译失败一样简单),请考虑添加到 rebase。这使用了交互式机制——换句话说,你可以在这里使用——在每个命令之后运行一个命令(或 pick-and-fixup 等;有关详细信息,请参阅文档)。如果提供的命令失败,rebase 将自动停止。如果没有,它将继续下一个。-x commandgit rebase -ipickpick

拥有良好的自动化测试在这里非常有帮助。

如果测试非常慢,请考虑执行完整的变基,然后进行单个测试,如果失败,则使用git bisect查找故障点。


推荐阅读