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

agyaoht7  于 2022-11-20  发布在  Git
关注(0)|答案(2)|浏览(204)

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

A -- B -- C

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

A -- X -- B -- C

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

kknvjkwl

kknvjkwl1#

如果你想添加提交,但使它对源代码没有影响,那么是的,你确实需要一个不同于交互式重定基的路径。
没有为此专门设计的代码,但是使用git replace相对容易:

  1. checkout 提交A(作为分离的HEAD,或者在一个新的分支上,但是新的分支很快就没用了):git checkout <hash-of-A> .
    1.提交X(无论您希望它以何种方式出现)。
    1.运行git replace --graft <hash-of-B> HEAD
    您现在拥有以下实际历史记录:
X--B'    <-- refs/replace/<hash-of-B>
 /
A--B--C   <-- whatever-branch-this-is

这些“replace”对象的特殊之处在于,每当Git要对几乎任何对象执行任何操作时--例如“使用提交来实现任何目的”--Git都会查看是否存在一个带有对象哈希ID的refs/replace/名称。由于B有一个替换,Git现在会转而查看B'。因此,git log和其他Git命令将按照如下方式执行:

A--X--B'--C

然而,请注意,真实的的历史仍然存在于这个仓库中。* 当且仅当 * refs/replace/名称在仓库中时,才使用替代历史--当然,它在 * 这个 * 仓库中--并且启用了替换(默认情况下是这样的)。但是,如果您将这个仓库克隆或推送到其他地方,获取或推送过程通常不会传输任何refs/replace/名称;因此这个存储库的克隆将切换回旧的历史记录。(您还可以通过禁用替换来查看原始历史记录,例如使用git --no-replace-objects log ...。)
如果你愿意,现在可以运行git filter-branch,它只复制提交,默认情况下,git filter-branch遵循替换规则,这意味着当它复制分支上的提交时,它将从A开始,然后复制X,再复制B',然后将C复制到B'AXB'的副本将与原始副本完全相同,因此实际上将重用原始副本;但是C的副本将稍有不同:它将使用B'作为它的真实的父节点,而不是作为替代的、嫁接的父节点。因此,提交C将被复制到新的提交C',并且分支名称,无论它是什么,都将指向新的副本。
这个过滤后的分支有 actual(不仅仅是嫁接的)历史记录,它从B'X再到A,所以现在如果你克隆过滤后的仓库,克隆中看到的历史记录同样会从C'开始,从B'X再到A

hc2pp10m

hc2pp10m2#

在@torek的回答的基础上,我在分支C的提交AB之间插入了一个旧版本的文件F(保存在F.verX中):

git checkout A
cp -pf F.verX F
git add F
olddate=$(LC_ALL=C date -r F)
LC_ALL=C GIT_AUTHOR_DATE="$olddate" GIT_COMMITTER_DATE="$olddate" \
  git commit -m "[old version inserted $(date +%F)] commit message for version X"
git replace --graft B HEAD
git filter-branch HEAD..C
git checkout C
git push -f

这将根据文件修改日期设置旧提交的作者和提交日期。如果没有这个设置,提交将具有今天的日期,并且如果按日期排序,将显示在日志的顶部olddate被设置为git正确格式的日期。当然,你也可以将其设置为任何其他的日期,例如date -d "23 Jan"而不是date -r F
我在提交消息中添加了一条带有当前日期的注解,但这当然不是必需的。
git filter-branch会在插入的提交之后为分支上的所有内容创建新的提交哈希。这就是为什么你需要git push -f。**警告:**这会打乱其他人在该分支上的更改。实际的提交将与之前相同。

相关问题