无论你如何实现结果,当你完成后,你将不会使用原来的三个提交。如果你被允许 100% 单独离开A,你可以保留原来的A,但如果你必须触摸B,你将不再拥有原来的B,因此必须做一个C 的新副本。
到目前为止,这只是事实陈述,而不是关于如何实现您想要的建议。 想要的方法通常是使用git rebase -i。
假设你现在在分支feature:
...--o--o--o--o <-- main
\
A--B--C <-- feature (HEAD)
你只需运行git rebase -i main,Git 就会提供一个指令表,告诉 Git 将三个提交保持原样:
# instructions
pick <hash-of-A> <subject-of-A>
pick <hash-of-B> <subject-of-B>
pick <hash-of-C> <subject-of-C>
将第二个 pick 更改为 edit 并写回指令表并退出您的编辑器。1 Git 现在将尝试直接复制提交 A 开始,这将成功。然后它将继续尝试复制提交B,这也会成功,但现在它将在复制过程中停止:
...--o--o--o--o <-- main
\
A--B <-- HEAD
\
C <-- feature
您将处于分离 HEAD 模式,HEAD 选择提交 B。
您现在可以更改要更改的文件git add,然后运行git commit --amend。 --amend 将让 Git 进行 new 提交——我们称之为 B'——使用提交 A 作为其父级,而不是提交 B。结果如下所示:
...--o--o--o--o <-- main
\
A--B' <-- HEAD
\
B--C <-- feature
您现在可以运行 git rebase --continue 以使 Git 继续执行 pick C 命令。这将挑选提交C,创建一个我们称之为C' 的新提交。 这里可能会发生一些合并冲突,因为cherry-pick实际上是一个合并。如果是这样,您需要修复它们并再次恢复,然后才能提交 C'。 但是,如果没有发生冲突,我们现在处于这种状态:
...--o--o--o--o <-- main
\
A--B'-C' <-- HEAD
\
B--C <-- feature
这完成了交互式变基要执行的一组操作,所以它现在执行 any 变基的最后一个技巧,即将分支名称拉到“这里”(无论@987654351 @现在)并重新附加您的HEAD:
...--o--o--o--o <-- main
\
A--B'-C' <-- feature (HEAD)
\
B--C [abandoned]
如果您想查看原始提交,它们仍然存在:您只需找到原始提交的哈希 ID C。这适用于:
-
ORIG_HEAD,只是短暂的时间(因为ORIG_HEAD 不断被覆盖);
-
HEAD 的 reflog,默认情况下至少多 30 天;和
- 分支
feature 的 reflog,默认情况下至少多 30 天。
reflog 条目具有数字后缀名称:feature@{1}。您还可以使用与时间相关的名称,例如 HEAD@{yesterday}。通常,如果某个名称在任何给定时间段内发生了不止一次更改,那么您将希望运行 git reflog,而不是尝试猜测诸如“yesterday.10.am”之类的内容。
1如果您有一个长时间运行的编辑器(emacs、atom 等的一些变体),请使用它必须向等待的 Git 发回这个文件现在已完成的信号,并且Git 应该会恢复。