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

时间:2017-10-11 01:13:27

标签: git

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

A -- B -- C

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

A -- X -- B -- C

注意,在how to insert a commit in the past上存在类似的问题,但在我的情况下它有点不同:X引入的任何更改都不会传播到B,在A之间插入版本X之后应保持不变和B.

1 个答案:

答案 0 :(得分:3)

如果你想添加提交,但是它对源没有影响,那么是的,你需要一个不同于交互式rebase的路径。

没有专门针对此设计,但使用git replace相对容易:

  1. 检查提交A(作为分离的HEAD,或在新分支上,但新分支很快就会无用):git checkout <hash-of-A>
  2. 提交X(但您希望它出现)。
  3. 运行git replace --graft <hash-of-B> HEAD
  4. 您现在拥有这段实际历史:

      X--B'    <-- refs/replace/<hash-of-B>
     /
    A--B--C   <-- whatever-branch-this-is
    

    这些&#34;替换&#34;有什么特别之处?对象是每当Git几乎可以对任何对象做任何事情时 - 包括&#34;使用提交用于任何目的&#34;,例如-Git将查看是否存在refs/replace/名称对象的哈希ID。由于 B的替代品,因此Git现在将改为B'。因此,git log和其他Git命令将表现为历史记录:

    A--X--B'--C
    

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

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

    此已过滤的分支包含实际(不仅仅是嫁接)历史记录,该历史记录会遍历C'B'X,所以现在如果您克隆已过滤存储库,克隆中看到的历史记录同样从A开始,然后从C'返回到B'X