如何在过去任意两个版本之间注入一个版本?

Pav*_*l P 6 git

假设我的本地分支上有以下版本历史记录:

A -- B -- C
Run Code Online (Sandbox Code Playgroud)

如何在 A 和 B 之间插入新版本 X,以便版本历史记录如下所示:

A -- X -- B -- C
Run Code Online (Sandbox Code Playgroud)

请注意,过去有一个关于如何插入提交的类似问题,但是,在我的情况下有点不同:X 引入的任何更改都不会传播到 B,在版本 X 插入 A 之间后,B 应该保持不变和B。

tor*_*rek 7

如果您想添加提交,但使其对源没有影响,那么是的,您确实需要与交互式变基不同的路径。

\n\n

没有专门为此设计的东西,但它相对容易做到git replace

\n\n
    \n
  1. 检查提交A(作为分离的 HEAD,或者在新分支上,但新分支很快就会变得无用):git checkout <hash-of-A>
  2. \n
  3. 进行提交X(但是您希望它出现)。
  4. \n
  5. 跑步git replace --graft <hash-of-B> HEAD
  6. \n
\n\n

你现在有了这样的真实历史:

\n\n
  X--B\'    <-- refs/replace/<hash-of-B>\n /\nA--B--C   <-- whatever-branch-this-is\n
Run Code Online (Sandbox Code Playgroud)\n\n

这些“替换”对象的特别之处在于,每当 Git 准备对几乎任何对象\xe2\x80\x94 执行几乎任何操作时,包括“出于任何目的使用提交”,例如 \xe2\x80\x94,Git 都会查找查看是否存在refs/replace/带有对象哈希 ID 的名称。由于有替代品B,Git 现在将寻找B\'. 因此,git log其他 Git 命令的行为就像历史记录一样:

\n\n
A--X--B\'--C\n
Run Code Online (Sandbox Code Playgroud)\n\n

但请注意,真实的历史记录仍然存在于该存储库中。当且仅当refs/replace/名称位于存储库\xe2\x80\x94 中(当然是在存储库\xe2\x80\x94 中)并且启用替换(默认情况下)时,才会使用替代历史记录。但是,如果您在其他地方克隆或推送此存储库,则获取或推送过程通常不会传输任何refs/replace/名称;因此该存储库的克隆将切换回旧历史记录。(您还可以通过禁用替换来查看原始历史记录,git --no-replace-objects log ...例如使用。)

\n\n

如果您愿意,现在可以运行git filter-branch,它只是复制提交。默认情况下,git filter-branch遵循替换规则。这意味着当它复制分支上的提交时,它将以 开始A,然后复制X,然后复制B\',然后复制C指向B\'AX、 和的副本B\'将与原始版本逐位相同,因此实际上会重复使用原始版本;但 的副本C会略有不同:它将用作B\'其真正的父级,而不是作为替代的嫁接父级。因此,提交C将被复制到新的提交C\',并且分支名称(无论它是什么)都将指向新副本。

\n\n

这个过滤后的分支具有实际的(不仅仅是嫁接的)历史记录,可以遍历到 to 因此B\'现在如果您克隆过滤后的存储库,克隆中看到的历史记录同样会从到 开始并返回到to 。XAC\'B\'XA

\n