我如何组合Git存储库?

时间:2018-02-10 05:11:59

标签: git git-branch git-rebase git-history-graph .git-info-grafts

我试图通过嫁接历史将2个存储库合并为1。我认为这是获得干净线性历史的最简单方法。

我试过将另一个作为远程数据库添加到初始存储库中来实现:

git init    
echo "Hello" > Hello.txt
git add -A
git commit -m "initial commit"
git remote add b c:\pathToB
git replace --graft master b/master   

树看起来不错,问题是我没有在当前目录中获取repo B的内容。

我也试过这个(提交哈希是b / master的提示)

git filter-branch -f --parent-filter 'sed "s~^\$~-p b34fc98295273c41aeb203213ad5fe4f95ba205b~"'

当我检查树时,我可以看到每个提交都包含它的更改,但主repo中的第一个提交基本上是删除了repo B带来的所有更改:

repos

原始提交都没有删除文件。

我错过了什么,我使用过滤器分支和移植物错了吗?或者我是否只需要使用cherry-pick或rebase来保留当前目录中的所有更改?

1 个答案:

答案 0 :(得分:1)

TL; DR

你需要结合树木。例如,您可以使用git merge。如果你的Git足够新,你将需要--allow-unrelated-histories标志。这样的合并将使用空树作为合并基础,因此它认为从merge base到 L 的更改是"在commit L 中添加所有文件"并且从合并库到 R 的更改为"在commit R "中添加所有文件(其中 L R 的定义方式我想为git merge定义;请参阅,例如this answer)。

提交是快照。 (这部分,我希望,没有争议。)

Git的git replace个对象实际上是替换。也就是说,每当Git要通过其哈希标识1234567...(或其他)查​​找对象时,Git会首先检查:是否在1234567...中为refs/replace/列出了替换项?如果有这样的替换,Git会通过将refs/replace/1234567...解析为不同的哈希ID并读取该对象来读取替换对象。

所以:

git init    
echo "Hello" > Hello.txt
git add -A
git commit -m "initial commit"

此序列首先创建一个新的,完全空的存储库(假设还没有Git存储库,以便git init进行创建)。 echo命令在工作树中创建一个文件; git add -A将工作树文件添加到索引(其副作用是将文件的数据作为 blob 对象存储到存储库中,尽管这样做了这里不重要)。最后一步git commit ...创建一个对象来保存快照 - 其中包含一个文件Hello.txt,其中包含您放入其中的内容 - 然后创建一个提交对象,例如1234567...,将您列为作者和提交者,具有消息" initial commit",使用创建的树来保存快照,并且 - 因为它是第一个commit ever-没有父提交:它是一个新的root提交。

现在我们有:

git remote add b c:\pathToB

这只会为新的远程fetch添加网址(和b设置)。

缺少一步:

git fetch b

调用另一个Git(在本地机器上c:\pathToB是本地的 - 通常我们会在另一台机器上调用Git,通过HTTPS或SSH或其他类似的,但这很好)并且从中下载对象。具体来说,它获得了他们没有提交的任何提交(这是他们的所有提交)以及完成这些提交所需的任何对象(这些提交都是他们的其他对象)并将它们复制到您的存储库中。这些都有一些 not 1234567...的ID,因为每次提交都有一个保证唯一的哈希ID。

最后:

git replace --graft master b/master

这告诉你的Git设置其中一个替换。特别是,它表示它应该将master标识的提交(我们上面已经说过1234567...)复制到就像原始的,除了它有一个哈希,它是提交b/master标识的任何东西。让我们说b/master标识提交fedcba9...

让我们说git replace提交的新提交具有ID 8888888...。其内容如下:

  • 你作为作者和提交者,从1234567...复制或重新创建(这并不重要);
  • 1234567...复制或重新创建的日期戳(这并不重要);
  • 1234567...;
  • 复制的邮件
  • 1234567... 复制的树(快照)(此部分至关重要);和
  • fedcba9...的父哈希。

您现有的master仍然标识1234567...,但现在当您要求Git 显示1234567...时,您的Git会看到refs/replace/1234567...存在并且说'不要使用那个,而是使用8888888...而不是#34;。因此,您的Git会查找对象8888888...,并找到您使用1234567...保存的树,其中只有一个文件。在之前提交 - 替换为1234567...替换 - 具有不同的文件,因此从那时到现在的更改必须是:删除所有这些文件,并创建Hello.txt代替。

要使下一个保存的快照以某种方式使用两个树,您需要将master的树与{{1}的树结合使用}}。这永远不会是b/master(尽管它是git replace还是其他/不同的东西取决于你)。