如何将额外的父级添加到旧的Git提交记录中?

26
我有一个包含两个分支的项目:master 和 gh-pages。它们本质上是两个不同的项目,其中 gh-pages 项目依赖于 master 项目(而不是相反)。可以将其视为“master 包含源代码,gh-pages 包含从这些源文件构建的二进制文件”。定期地,我会将在 master 中累积的更改提取出来,并使用提交消息“将与主提交 xxxxxxxx 对齐”的新提交到 gh-pages 分支中。

how the network graph currently looks

做了一段时间后,我意识到如果gh-pages提交“Bring into line with master commit xxxxxxxx”实际上将xxxxxxx作为其在git存储库中的父级将会很好。像这样(糟糕的MSPaint艺术):

how it would ideally look

有没有办法让代码库看起来像上面第二张图片那样?我知道如何使新的提交遵循这种模式:我可以执行 "git merge -s ours master"(设置一个否则为空的提交的父级),然后执行 "git commit --amend adv550.z8"(其中 adv550.z8 是实际更改的二进制文件)。但是 Git 是否能够轻松地回溯并向旧提交添加新的父级呢?
一旦我让本地仓库正确地工作,我完全可以执行 "git push -f" 并清除 Github 代码库的当前历史记录。问题是,我是否能够让本地仓库正常工作呢?
多年后进行编辑: 我最终放弃了使gh-pages的git历史看起来像那样的尝试;我决定这是为零收益而付出太多努力。我的新做法是积极地压缩对gh-pages的提交,因为在我的情况下保存这些提交消息并不重要。(它只是一长串“将其与主分支保持一致”的提交,其中没有任何历史上有趣的内容。)然而,如果我需要再次这样做,我会听从那些回答的建议。
git merge $intended_parent_1 $intended_parent_2
git checkout $original_commit -- .
git commit --amend -a -C $original_commit
5个回答

22
git replace --graft $commit $parent1 $optional_parent2
git replace --graft $original_commit \
    $(git show --pretty=%P $original_commit) \
    $additional_parent

解释: git replace --graft 允许重新指定给定提交的父提交。它通过编写一个新的提交,并编写一个替换引用来实现,每当访问原始提交时,引用会使git查找新的提交而不是原始提交。

git show --pretty=%P $original_commit 只列出原始父提交。


4
这几乎是正确的答案,但需要加上git show --pretty=%P $original_commit | head -n1 这行命令——因为我的git(版本号为2.11.1)输出了很多不只是父提交记录那一行。 - kgadek
1
这是来自末日未来的信息,告诉你们两个让我的生活变得简单了许多,我非常感激。 - therightstuff
1
使用 git show --pretty="format:%P" --no-abbrev-commit --no-patch ${original_commit} 命令来避免使用 head -n 1 - Maddes
2
请注意,以这种方式添加的父级文件夹不会显示在Github上。 - wrongusername
1
我发现使用 git filter-branch $original_parent..HEAD 命令会使嫁接永久化,因此也会在 Github 上显示。但需要注意的是:我要添加父级的提交是最新的(HEAD),并且我只向一个原始父级的提交添加了1个父级。 - Emoun
显示剩余2条评论

9

以下是您的魔法词汇:

git merge origin/master --strategy ours

gh-pages分支中执行此操作,以记录与master的关系,而不实际更改任何内容。当我创建--orphangh-pages分支时,这对我起作用,例如此答案

您甚至可以在以后使用--amend来修改此空合并提交,以引入您实际想要进行的更改“页面”。请参见https://github.com/krlmlr/pdlyr/network,了解GitHub上的实际示例。


这个结合了在编辑中添加的信息(例如 git commit --amend -a -C ... 等)对我非常有用。谢谢。 - lindes
2
现在需要使用 --allow-unrelated-histories 标志才能工作,因为自 Git 2.9 起,默认情况下 Git 不再允许合并不相关的历史记录。 - jitin

3
您无法回到过去并更改现有的提交记录。即使您执行像 git commit --amend 这样的操作,实际上也没有更改提交记录;您只是在树的相同位置创建了一个新的提交记录,并包含原始内容(加上您的更改)。您会注意到,在执行 --amend 后,提交哈希值会发生更改,而原始提交记录仍然存在于您的存储库中——您可以通过使用 git reflog 返回到它。

另一方面,您可以回到过去,创建一个新的平行宇宙。基本上,您将返回到您的 gh-pages 分支点,并重新创建整个项目(例如,使用 git cherry-pick 或其他方式)作为平行分支。哈希值会发生更改,因为提交记录是不同的对象。

(我很好奇为什么您的存储库设置为单独的分支,而不是同一分支中的单独目录。这似乎会让代码 -> 构建流程变得繁琐。)


1
“你会注意到,在--amend之后,提交哈希值会发生变化。” 只有当内容发生更改时才会发生变化,对提交日志消息进行更改似乎不会更改哈希值,我希望更改父级也不会更改哈希值。“为什么要分开分支?” 这只是GitHub使用他们的“GitHub Pages”功能的方式,我正在使用它来托管http://quuxplusone.github.com/Advent/play-550.html。您需要创建一个名为“gh-pages”的新分支,其中包含的任何内容都会自动镜像到实时网页上。这有点奇怪,但在这种情况下,我认为它有一定的道理。 - Quuxplusone
1
基本上,您需要返回到gh-pages分支点并重新创建整个内容。我可以接受这种方法。但是,如何保留原始提交的时间戳?我不想失去它们。这就是为什么我问如何回到过去的原因。 - Quuxplusone
即使使用空索引进行commit --amend -C,我仍然会得到一个新的哈希值。 - ellotheth
我错了;提交哈希值取决于时间戳,而 git commit --amend 会更改时间戳。这个项目 利用了这一点巧妙地实现了美化效果。 我不认为标签解决了我关心的任何问题。请注意,所有提交到 gh-pages 的提交 已经 在提交消息中包含了它们将要成为父级的哈希值。我特别希望这些信息也能反映在它们实际的父级集合中,原因纯粹是出于美学考虑。 离题:SO 的 markdown 没有任何方法插入段落分隔符?!那太糟糕了。 - Quuxplusone
3
提交哈希值涵盖了与该提交有关的所有内容,包括内容、父参考、评论和日期/时间。如果您更改提交中的任何一个比特位,将生成一个新的哈希值。 - wadesworld
显示剩余2条评论

1

@rumpel给出了正确的答案。让我分享一下我使用的片段。

首先,我创建了一个孤儿的master分支:

git checkout --orphan master
git commit --allow-empty -m 'Init'

我的使用案例略有不同,我需要的站点位于_site目录下的develop分支。因此我会这样做:

git checkout master
git rm -rf .
git read-tree develop^{tree}:_site
git checkout -- .
git commit -m "Update from develop SHA1:$(git rev-parse --short develop) ($(git log -1 --format=%cd develop))"
git replace --graft @ $(git show --pretty=%P @ | head -n1) develop

请注意,在上一个命令中,我必须使用| head -n1进行过滤,因为我的git输出的不仅仅是父级。

使用 git show --pretty="format:%P" --no-abbrev-commit --no-patch ${original_commit} 命令来避免使用 head -n 1 - Maddes

-1

你可以重写提交记录,但需要从第一个需要额外父级的提交记录开始重写整个分支,直到分支末端。这就像使用rebase一样,创建了一个具有相同内容的新分支。

诀窍在于使用commit-tree,它以相当不实用的方式获取所有内容(提交者/作者信息、时间戳、提交消息、父级列表)。然后进行一些脚本编写即可完成工作。


2
如果你的第二段不是如此奇怪地含糊不清,你会得到一个赞。 - Quuxplusone
我知道。但是那需要一些工作,而且我现在不需要那个脚本。 - Andreas Krey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接