23

我有一堆 git 存储库,每个都包含一个文件。我想将它们全部合并在一起,最好是一步完成。我的目标是这张图:

*----¬ mergedrepo/master
| \ \ \
| | | * repoA/master
| | * repoB/master
| | |
| | * repoB/...
| * repoC/master
* repoD/master
|
* repoD/...

我试过了git merge,但似乎章鱼策略不适用于不相交的树

$ git merge a/master b/master c/master d/master
Unable to find common commit with a/master
Automatic merge failed; fix conflicts and then commit the result.

我也被告知这git merge --squash会有所帮助,但这给出了同样的错误。

这会生成正确的图表,但会丢失所有文件:

$ git merge -s ours a/master b/master c/master d/master

我该怎么做呢?

4

4 回答 4

21

我已经设法解决了不相关分支的章鱼合并问题。不幸的是,以下仅适用于不存在真正合并冲突的相当简单的情况。

  1. 按照 OP 中的描述进行合并。

    git merge --allow-unrelated-histories a/master b/master c/master d/master

    它将“失败”声称冲突。但是已经执行了合并并记录了这一事实,尽管索引没有变化。

  2. read-tree使用以下命令将分支的内容添加到索引中:

    git read-tree a/master b/master c/master d/master

    这不会影响工作树,只会更新索引。(您可能希望将当前分支添加到末尾。您需要在一个命令中添加所有分支。)

    如果分支不是完全独立的,则调整它们的顺序,记住后者将覆盖前分支的内容。

  3. 正常提交。( git commit -m "octopus-merged remote 'a', 'b', 'c', 'd'")
  4. 执行硬重置 ( git reset --hard) 以获得一致的工作树。

我想以后可以编辑和修改这个提交,但我个人没有尝试过。

于 2015-07-02T14:02:35.157 回答
4

创建一个空提交

git commit -m "Common commit" --allow-empty

查看它的哈希log -1并将其添加到没有任何父母的移植文件中

echo HASH_OF_COMMON_COMMIT >> .git/info/grafts

然后找到所有其他根,log --max-parents=0并将它们的哈希添加到嫁接文件中,并将上述哈希作为父级

each HASH_OF_ROOT HASH_OF_COMMON_COMMIT >> .git/info/grafts

现在,合并!

移植文件是一种更改提交的父级的方法,一旦您的所有存储库都有一个共同的提交,您的存储库应该接受合并。

于 2012-11-28T06:23:39.463 回答
4

我有很多不相关的分支要从旧版 SVN 结构合并到新初始化的 Git 存储库中。Vertigo的回答让我大部分时间到达那里,但git read-tree一次最多只能读取 8 棵树。

我的解决方案是在每次读取后编写一棵新树,然后在下一次读取时使用该新树:

tree_head=HEAD
to_merge="a/master ... z/master"

# If you're using a variable here you want word splitting, so don't use quotes.
git merge --allow-unrelated-histories $to_merge

for merging in $to_merge; do
    git read-tree "$tree_head" "$merging"
    tree_head=$(git write-tree)
done

git checkout-index -fua
git commit -m "All repos merged."
于 2019-03-05T13:41:00.390 回答
3

虽然它看起来更复杂,但我认为@akuhn 的解决方案是唯一真正按照 Git 预期的方式工作的解决方案。同样对我来说,其他解决方案仅在我合并一次不相关的分支时才有效。在我的用例中,我想对不相关分支的不同版本进行连续合并。其他解决方案不会引发错误,但文件状态会变得混乱。

git replace自从引入命令的 Git 1.6.5 以来,概述的解决方案实际上变得容易得多。不过这个想法还是一样的:你让 Git 认为你的提交有一个共同的提交来使合并工作。为此,您需要找出当前分支初始提交的 SHA-1:

common_commit=$(git rev-list --max-parents=0 HEAD)

一旦你有了它,你告诉 git 你想要合并的每个分支都来自那个提交:

for branch in a/master b/master c/master d/master
do
  branch_initial_commit=$(git rev-list --max-parents=0 $branch)
  git replace --graft $branch_initial_commit $common_commit
done

之后,您可以简单地运行合并命令。Git 不会抱怨,因为所有分支现在都源自同一个共同提交。

git merge a/master b/master c/master d/master
于 2020-07-09T16:01:19.070 回答