Git:冲突将多个存储库合并到一个保留历史记录的目录中

时间:2017-10-24 21:20:44

标签: git merge merge-conflict-resolution

我有几个(~20个)Git存储库,它们的文件不重叠。我想将他们的主分支组合在一个(新的)存储库中。

经过一番阅读后,我想出了以下过程。

  1. 创建目标存储库(git init)并将其更改为
  2. git remote add <name> <url>
  3. git fetch <name>
  4. git merge <name>/master --allow-unrelated-histories -m "Imported"
  5. git remote rm <name>
  6. 重复2-5直到合并所有存储库
  7. 第一个存储库很好地合并,历史记录完好无损,但后来我遇到了合并冲突。

    E.g。对于不同目录中具有相同名称的不同文件(并且我没有重命名):

    CONFLICT (rename/rename): Rename "Splittermond_CharGen_JFX/.project"->"BootloaderPlugin/.project" in branch "HEAD" rename "Splittermond_CharGen_JFX/.project"->"Splittermond_Zhoujiang/.project" in "splimo-common/master"
    

    E.g。从我在项目历史中移动的文件(以及树中剩下的版本是最近的位置):

    CONFLICT (rename/delete): Splittermond_BuU/src/org/prelle/rpgframework/splittermond/buu/BestienUndUngeheuerPlugin.java deleted in HEAD and renamed to Splittermond_BuU/src/main/java/org/prelle/rpgframework/splittermond/buu/BestienUndUngeheuerPlugin.java in splimo-common/master. Version splimo-common/master of Splittermond_BuU/src/main/java/org/prelle/rpgframework/splittermond/buu/BestienUndUngeheuerPlugin.java left in tree.
    

    我认为Gits跟踪文件的能力可能是问题所在,但我对此并不熟悉,也不知道如何解决这个问题。

    感谢任何帮助或提示。

    [更新] 看起来我至少有两个存储库 - 虽然不再重叠 - 一旦重叠。我有一个git repo A抱怨它删除了现在在repo B中的文件。我有一个repo B,曾经包含现在在repo A中的文件。 有没有办法合并两者,保留所有尚未删除的文件的历史记录?

3 个答案:

答案 0 :(得分:2)

可能是重命名检测会产生错误的结果。然后,您可以尝试通过向合并命令添加-Xno-renames来避免它:

...
git merge <name>/master --allow-unrelated-histories -m "Imported" -Xno-renames
...

它不应该因为你正在合并不相关的历史并且不期望任何重命名而受到伤害。

答案 1 :(得分:1)

我一点也不清楚发生了什么,我需要访问有问题的存储库以及重现这一点的命令。但是,在考虑如何使这一切成功时,请记住两个关键点:

  • 在Git中,历史提交(或者更明确地,&#34;提交是历史记录&#34;)。如果您想保留历史记录,这意味着您希望保留现有提交。
  • 合并(动词形式,合并)意味着在Git中找到两个(可能是长的)提交链之间的公共基础提交,以便比较&#34;我们在我们的分支机构做了什么&#34;他们在他们的分支机构做了什么&#34; 自那个共同点

正常合并有两个&#34;边和#34;。我称他们为 L 为左,本地或--ours R 为右,远程或--theiRs。它还有这个合并基础提交,这是我们和他们在开始做自己的事情之前开始的共同点。 Git结合了我们所做的&#34;用&#34;他们做了什么&#34;通过运行:

git diff --find-renames B L   # base to left/local: what we did
git diff --find-renames B R   # base to right: what they did

例如,如果&#34;我们&#34;和&#34;他们&#34;修改了相同文件的相同行,或者我们添加了文件path/to/new.txt,但他们添加了相同的path/to/new.txt但内容不同,或者我们删除了path/to/old.txt并修改了path/to/old.txt }。

当你使用--allow-unrelated-histories时,你告诉Git,如果没有常见的提交 - 这在这里经常是真的--Git应该假装有一个共同的基础,包含一个提交根本没有文件。也就是说,对于两个git diff命令中的 B ,Git应该在the empty tree中替换,以便每个文件都是新的。

现在,你说:

  

... [一些相当多的] Git存储库,它们的文件中没有重叠

如果是这种情况,那么 L R 中都不会有path/to/new.txt。如果双方都有新文件,则文件重叠。

此外,如果历史记录确实无关,则无法获取重命名/重命名或重命名/删除冲突,因为没有合并库,Git将为使用空树B 每一次。您遇到此类冲突的事实表明历史记录相关,因此Git找到了一个公共合并库,而该公共合并库中的git diff正在查找重命名操作另一方面,可以使用不同的重命名或删除。

因为这种情况,不能使用如何更容易地合并所有这些无关历史的明显答案:有些文件 重叠,这种方法不会起作用容易。但如果它们真的都是非重叠的,那么合并它们的方法就是从所有存储库中获取所有提交,然后构建一个master&#34; octopus merge&#34; commit(这里我使用 merge 作为形容词或名词,而不是动词),通过在所有适当的分支提示上使用git read-tree -m来生成树,以构建合并索引,并且通过运行git write-tree然后git commit-tree(带有适当的标志)生成提交。

但是,我对于为此提供配方犹豫不决,因为如果它能够起作用,你真的需要无关的输入,而你所看到的失败告诉我你没有无关的输入。 / p>

答案 2 :(得分:0)

感谢toreks的帮助,我提出了以下解决方案:

  1. 使用git init
  2. 初始化新存储库
  3. git remote add <name> <url>
  4. git fetch <name>
  5. git merge <name>/master --allow-unrelated-histories -m "Reimported"
  6. git remote rm <name>
  7. git ls-files > /tmp/keep-these.txt
  8. git filter-branch --force --index-filter "git rm --ignore-unmatch --cached -qr . ; cat /tmp/keep-these.txt | xargs git reset -q \$GIT_COMMIT --" --prune-empty --tag-name-filter cat -- --all
  9. 对每个存储库重复步骤2-7
  10. 添加的步骤6-7取自new-repo-with-copied-history-of-only-current-tracked-files

    我希望有所帮助。