如何在旧的git提交中添加其他父项?

时间:2012-05-30 00:00:45

标签: git git-rewrite-history

我有一个包含两个分支的项目:master和gh-pages。它们本质上是两个不同的项目,其中gh-pages项目依赖于主项目(反之亦然)。可以把它想象成“master包含源代码,gh-pages包含从这些源文件构建的二进制文件”。我定期地接受在master中累积的更改,并使用提交消息“与主提交xxxxxxxx一致”对gh-pages分支进行新提交。

how the network graph currently looks

经过一段时间的这样做,我意识到如果gh-pages提交“与主提交xxxxxxxx一致”实际上将xxxxxxxx作为其git存储库中的父级将会很好。像这样(糟糕的MSPaint艺术):

how it would ideally look

有没有办法让存储库看起来像上面的第二张图片?我知道如何使新的提交遵循这种模式:我可以做“git merge -s our 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 个答案:

答案 0 :(得分:7)

git replace --graft $original_commit \
    $(git show --pretty=%P $original_commit) \
    $additional_parent

说明: git replace --graft允许重新指定哪个是给定提交的父级。这通过编写具有相应更改的新提交并编写替换引用来工作,该替换引用使git在访问时查找新提交而不是原始提交。

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

答案 1 :(得分:5)

这些是你的神奇话语:

git merge origin/master --strategy ours

gh-pages分支中执行此操作,以便记录与master的关系,而不实际更改任何内容。当我将gh-pages分支创建为--orphan时,这对我有用,就像在this answer中一样。

之后您甚至可以--amend此空合并提交,以便将您实际想要进行的更改引入您的"页面"。有关GitHub的实际示例,请参阅https://github.com/krlmlr/pdlyr/network

答案 2 :(得分:2)

您无法及时返回并更改现有提交。即使您执行git commit --amend之类的操作,也不会实际更改提交;你在树的同一个地方创建一个新的,包含原始内容(加上你的更改)。您会注意到提交哈希值在--amend之后发生更改,并且原始邮件仍然存在于您的回购邮件中 - 您可以使用git reflog返回它。

另一方面,可以及时返回并创建备用Universe。从本质上讲,您将返回到gh-pages分支点并重新创建整个事物(例如git cherry-pick或其他东西)作为并行分支。哈希会改变,因为提交是不同的对象。

(我很好奇为什么你把你的repo设置为单独的分支,而不是在同一分支中的单独目录。看起来代码 - >构建过程会变得乏味。)

答案 3 :(得分:1)

您可以重写提交,但它需要从第一次提交开始重写整个分支,这需要一个额外的父级到分支提示。是(和rebase一样)是一个新的分支,只有相同的内容。

诀窍是使用commit-tree,它接受所有内容(提交者/作者信息,时间戳,提交消息,父母列表),尽管这是一种相当不实用的方式。那时候会有一些脚本编写。

答案 4 :(得分:0)

@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输出比父母更多。