我有一个包含 10 个提交的分支。现在 master 更改了,我想将我的分支重新设置为新 master 的 HEAD。然而,一些新的主提交甚至使我的分支的第一次提交无法编译(没有合并冲突)。如果您的所有提交最终都无法编译,那么重新设置分支对我来说似乎毫无意义。
我想要做的是告诉 get “做一个 rebase,但在从我的分支重新设置每个提交后等待”。这样,我可以检测每次提交后代码是否仍然编译,使其编译(如果需要),然后提交并继续。
这可能吗?是否有干净的变基替代方案,以便每次提交仍将编译?
是的,这是可能的。
最简单的方法可能是使用git rebase -i并将每个更改pick为edit. 在 Git 完成每个挑选操作之后,它会回到命令行。您现在可以尝试构建(并运行测试),当出现故障时,修复它。一旦一切正常,运行git add -u并git commit --amend在适当的时候,然后git rebase --continue按顺序应用下一个提交。
在你熟悉了这个方法之后(不要马上开始!)--exec,如果你的 Git 支持它,也可以考虑使用它。
注意:如果要复制的提交——不管它是否被标记pick或edit——有合并冲突,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的樱桃挑选提交I给I'附加H",然后,因为你说“编辑”再次-stops尚未:
...--G--H--I--J <-- branch1
\
K--L <-- branch2
|\
| H' [abandoned]
\
H"-I' <-- HEAD
Run Code Online (Sandbox Code Playgroud)
等等。