如何合并两个Git历史记录?

13

我有两个Git代码库,它们有某种联系。其中一个的内容是另一个的前身。我想以某种方式将代码库A的完整历史记录插入到代码库B之前,这样A的末尾就会成为代码库B的第一个变更集的父节点吗?它们两个的历史记录都相当线性。

这种操作是否可行?

1个回答

13
你可以尝试使用嫁接文件(.git/info/grafts),其中可以覆盖提交的父级关系(例如,将projectB的第一个提交设置为projectA的最新提交的父级)。
另请参阅".git/info/grafts是什么?"和"如何在git存储库中添加过去的提交记录?"以了解更多相关操作。

skalee comments 关于文章 "Git: Grafting repositories"(来自SO用户Ben Straub)的具体示例。

现在我们想要做的是更改“nuevo”仓库中的第一个提交(“New commit #1”),使其父提交为“old”仓库中的最后一个提交(“Old #3”)。是时候施展一些巫术了:

git fetch ../old master:ancient_history

Git可以从任何其他git存储库获取数据,无论这个存储库是否与它有关!太棒了!这让我们得到了这个:

enter image description here

请注意我们将旧的主分支重命名为"ancient_history"。如果我们没有这样做,git会尝试合并这两个分支,但很可能会因此放弃。现在我们仍然有一个问题。这两个树没有连接,事实上,git pull甚至无法获取"ancient_history"分支。我们需要一种方法来建立两者之间的联系。Git有一个称为graft的工具,它可以在两个提交之间伪造一个父链接。要创建一个graft,只需按照以下格式在.git/info/grafts文件中插入一行:
[ref] [parent]

这两个都需要是相关提交的完整哈希值。因此,让我们找到它们:
$ git rev-list master | tail -n 1
d7737bffdad86dc05bbade271a9c16f8f912d3c6

$ git rev-parse ancient_history
463d0401a3f34bd381c456c6166e514564289ab2

$ echo d7737bffdad86dc05bbade271a9c16f8f912d3c6 \
       463d0401a3f34bd381c456c6166e514564289ab2 \
       > .git/info/grafts

(由ssokolow建议,在一行中完成)

echo $(git rev-list master | tail -n 1) $(git rev-parse ancient_history) > .git/info/grafts 

现在我们的历史记录如下:

enter image description here

克隆该存储库会得到以下结果:

enter image description here

糟糕,看来移植只对本地仓库生效。我们可以通过巧妙地应用git fast-import来解决这个问题:

$ git fast-export --all > ../export

$ mkdir ../nuevo-complete

$ cd ../nuevo-complete

$ git init

$ git fast-import < ../export
git-fast-import statistics: [...]

(由ssokolow建议,建议改为一行)

git filter-branch $(git rev-parse ancient_history)..HEAD 

这实际上将我们的“伪造”历史链接转换为真正的链接。
所有工程师都需要从这个新仓库重新克隆,因为哈希值将全部不同,但这是为了不中断服务和完整的历史记录付出的小代价。

enter image description here

正如Qixbelow所评论:

fast-import 似乎只是导入 git 信息,但不会检出任何内容。
git init 最初将您放置在主分支上,因此在执行 fast-import 后,需要使用git reset --hard HEAD 来实际检出文件


1
然后,您可以使用 git filter-branch 重写历史记录,以使移植带来的更改永久化...但这会重写历史记录。 - Jakub Narębski
这篇简短而简洁的文章真正帮助我理解了什么是grafts,以及如何逐步加入这些历史记录:http://ben.straubnet.net/post/939181602/git-grafting-repositories - skalee
@skalee 不错的文章。我已经在答案中包含了主要命令。 - VonC
太简单了。也应该提到,需要执行 git reset --hard HEAD,因为 fast-import 不会帮你检出主分支的头部(所以立即执行 git status 会显示你删除了一切)。 - Qix - MONICA WAS MISTREATED
1
@Qix 很好的观点。我已经将您的评论包含在答案中以增加可见性。 - VonC
显示剩余8条评论

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