0

我试图通过嫁接历史将 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 B 带来的所有更改:

回购

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

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

4

1 回答 1

1

TL;博士

您需要合并树木。例如,您可以使用git merge. 如果你的 Git 足够新,你将需要这个--allow-unrelated-histories标志。这样的合并将使用一棵空树作为合并基,因此它认为从合并基到L的更改是“添加提交L中的所有文件”,从合并基到R的更改是“添加提交R中的所有文件"(其中LR的定义方式是我喜欢定义它们的方式git merge;例如,参见这个答案)。

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

Git 的git replace对象,顾名思义,就是替代品。也就是说,每当 Git 要通过其哈希 ID 1234567...(或其他)查​​找对象时,Git 首先检查:是否列出了in的替代项?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命令在工作树中创建一个文件;将工作树文件添加到索引中(这具有将文件的数据作为blobgit add -A对象存储到存储库中的副作用,尽管这在这里并不重要)。最后一步,创建一个对象来保存快照——其中有一个文件,以及你放入其中的内容——然后创建一个提交对象,例如将你列为作者和提交者,有消息“初始提交”,使用创建的树来保存快照,并且——因为它是有史以来的第一次提交——没有父提交:它是一个新的根提交。git commit ...Hello.txt1234567...

现在我们有:

git remote add b c:\pathToB

这只是fetch为新的远程添加 URL(和设置)b

少了一个步骤:

git fetch b

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

最后:

git replace --graft master b/master

这会告诉您的 Git 设置其中一个替换项。特别是,它说它应该将由(master我们在上面说过是)标识的提交复制到与原始提交一样1234567...的新提交,除了它有一个哈希,它是提交标识的任何内容。假设标识了 commit 。b/masterb/masterfedcba9...

假设提交的新提交git replace具有 ID 8888888...。它的内容是:

  • 你作为作者和提交者,复制1234567...或重新创建(这并不重要);
  • 从复制1234567...或重新创建的日期戳(这也无关紧要);
  • 消息复制自1234567...
  • 1234567...(这部分很关键)复制的树(快照);和
  • 的父哈希fedcba9...

您现有的master仍然可以识别1234567...,但是现在当您要求 Git 向您展示1234567...,您的 Git 会看到refs/replace/1234567...存在并说“不要使用那个,8888888...而是使用”。因此,您的 Git 查找对象8888888...并找到您使用 保存的树1234567...,其中只有一个文件。在此之前的提交(替换替换为 for)具有1234567...不同的文件,因此从那时到现在的更改必须是:删除所有这些文件,然后创建Hello.txt

要使您的下一个保存的快照以某种方式使用这两种树,您需要将您master的树与b/master. 那永远不会发生git replace(尽管它是git merge或不同/更高级的东西取决于你)。

于 2018-02-10T06:19:29.013 回答