git rebase 通过提交提交

Joh*_*nes 2 git git-rebase

我有一个包含 10 个提交的分支。现在 master 更改了,我想将我的分支重新设置为新 master 的 HEAD。然而,一些新的主提交甚至使我的分支的第一次提交无法编译(没有合并冲突)。如果您的所有提交最终都无法编译,那么重新设置分支对我来说似乎毫无意义。

我想要做的是告诉 get “做一个 rebase,但在从我的分支重新设置每个提交后等待”。这样,我可以检测每次提交后代码是否仍然编译,使其编译(如果需要),然后提交并继续。

这可能吗?是否有干净的变基替代方案,以便每次提交仍将编译?

tor*_*rek 5

是的,这是可能的。

最简单的方法可能是使用git rebase -i并将每个更改pickedit. 在 Git 完成每个挑选操作之后,它会回到命令行。您现在可以尝试构建(并运行测试),当出现故障时,修复它。一旦一切正常,运行git add -ugit commit --amend在适当的时候,然后git rebase --continue按顺序应用下一个提交。

在你熟悉了这个方法之后(不要马上开始!)--exec,如果你的 Git 支持它,也可以考虑使用它。

注意:如果要复制的提交——不管它是否被标记pickedit——有合并冲突,git rebase则以该合并冲突停止。即使您确实标记了它edit,Git 也不会在解决冲突后再次停止,因此如果您必须解决某些问题并更改其他内容,您应该在这里同时进行(并且不要使用,git commit --amend因为您仍在制作第一个复制)。

如果您有兴趣/好奇,请提供详细信息

Git 改变任何现有提交在物理上是不可能的,因为每个提交的真实名称——它的哈希 ID——是所有内容的加密校验和该提交的,包括你作为作者/提交者的姓名、时间戳和当然还有快照附带的所有源代码。

然而,对于 Git 来说,复制一个提交是很容易的——好吧,只要它是一个普通的非合并提交,只有一个父提交。给定一些哈希 ID 为H 的提交,Git 可以将H(快照)转换为针对H的父项的更改集。把git show它想象成是做什么的:它提取父的快照,然后提取提交的快照,无论它们之间有什么不同(git diff <parent-of-H> <H>),这就是改变的东西。然后可以通过检查其他提交将这些相同的更改应用于其他提交,然后提交结果。也就是说,如果我们有两个分支branch1并且branch2,我们可以查看第二个分支的提示提交并创建一个新的临时分支:

...--G--H--I--J   <-- branch1
      \
       K--L   <-- branch2, temp (HEAD)
Run Code Online (Sandbox Code Playgroud)

然后,我们将提交H转换为更改集,将更改集应用于 commit L,并进行具有新的不同哈希 ID 的新提交。这个新提交非常像H我们称之为H'说明的:

...--G--H--I--J   <-- branch1
      \
       K--L   <-- branch2
           \
            H'  <-- temp (HEAD)
Run Code Online (Sandbox Code Playgroud)

此复制操作是一个git cherry-pick. (从技术上讲,每个挑选操作都是完整的三向合并,而不仅仅是应用更改集样式的补丁,但我们不需要担心这一点,除非并且直到出现各种并发症。)

如果我们对所有正在进行的提交重复挑选樱桃,branch1我们会得到:

...--G--H--I--J   <-- branch1
      \
       K--L   <-- branch2
           \
            H'-I'-J'  <-- temp (HEAD)
Run Code Online (Sandbox Code Playgroud)

如果我们现在的“剥标签”branch1关闭J并将其连接到J'代替,完全丢弃的临时名称,我们最终有:

...--G--H--I--J   [abandoned]
      \
       K--L   <-- branch2
           \
            H'-I'-J'  <-- branch1 (HEAD)
Run Code Online (Sandbox Code Playgroud)

因此,重新定位实际上是一系列挑选操作。一个交互式的rebase更加明确:每次提交哈希ID变成了pick一个脚本命令。

pickto更改为edit告诉 Git,在执行了各种挑选步骤之后,它应该停止并返回到命令行。(请注意,如果出现合并冲突,Git也会自行停止并返回到命令行。)运行git rebase --continue告诉 Git 查询它留下的控制文件——这些文件由 Git 内部调用的排序器管理——查看其他提交仍然需要任何类型的处理。因此,如果您将每个提交标记为“待编辑”,Git 会在复制H到后停止H',以便您拥有:

...--G--H--I--J   <-- branch1
      \
       K--L   <-- branch2
           \
            H'  <-- HEAD
Run Code Online (Sandbox Code Playgroud)

(我已经更新了绘图以依赖 Git 真正执行此操作的方式:Git 没有尝试发明一个临时分支名称,而是使用“分离的 HEAD”模式来进行复制。)

此时,如果您进行更改并运行git add -u && git commit --amend,Git 会再次进行新的提交——我们称之为 H-prime-prime 或H"——其父级与H'的父级相同:

...--G--H--I--J   <-- branch1
      \
       K--L   <-- branch2
          |\
          | H'  [abandoned]
           \
            H"  <-- HEAD
Run Code Online (Sandbox Code Playgroud)

现在,当您运行git rebase --continue,Git的樱桃挑选提交II'附加H",然后,因为你说“编辑”再次-stops尚未:

...--G--H--I--J   <-- branch1
      \
       K--L   <-- branch2
          |\
          | H'  [abandoned]
           \
            H"-I'  <-- HEAD
Run Code Online (Sandbox Code Playgroud)

等等。