我有三个不相关的存储库,我想通过将每个存储库移动到不同的子目录来重写到单个存储库中。我正在做这样的事情:
some_url=git@github.com/blah/"
repos='a b c d e f g'
git init
git commit --allow-empty -m 'Unified repo base commit'
for repo in $repos; do
git fetch $some_url/$repo
git checkout -b rewrite-$repo
# prefix commit messages with original repo name
git filter-branch -f --msg-filter "/bin/echo -n '${repo}: ' && cat"
# the rewrite just does `mv * $repo/` for all files in each $repo
git filter-branch -f --tree-filter "mkdir -p ${repo}; find -mindepth 1 -maxdepth 1 ! -name ${repo} | -exec -- mv '{}' ${repo} ';'"
git checkout master
# rebase the rewritten branch in
git rebase rewrite-$repo
done
但是,我在rebase上遇到了合并冲突。据我所知,这些冲突不在不同的回购中,而是在为一个回购重绕历史时。它几乎看起来没有以正确的顺序应用补丁(例如,在冲突点,文件处于与提交之前的原始仓库中的状态不同的状态)。
我无法理解这是怎么发生的 - 天真地,因为所有的回购都被重写为使用不同的子目录,似乎没有重叠的可能性,并且对rebase的重绕不应该改变任何东西。我尝试了一个类似的解决方案,使用git format-patch和git am导入,但同样的事情发生了。尝试使用cpan的Git::FastExport::Stitch
时再次相同。
我最终决定重复正常合并所有回购(令人恼火的是,如果没有共同的祖先,似乎不可能进行章鱼合并),但我仍然很想知道发生了什么以及如何正确地做到这一点。
答案 0 :(得分:1)
更新 - 添加了一些关于为什么通过合并进行变基数会出现问题的问题,以及基于评论的其他一些说明
我的猜测是个人回购'历史不是严格线性的(即有分支和合并点)?如果是这样的话,rebase
可能会造成混乱(见下文)。重新整理任何非平凡的历史往往是一个坏主意。
如果你真的想要将一个(看似随意的)线性顺序强加给回购项目的项目,你可能需要做更多的filter-branch
工作。给定
A --- B --- C <--(repo1)
D --- E --- F <--(repo2)
\ /
G ---- H
你可以filter-branch
repo2
使用tree-filter
添加C
的子目录加parent-filter
来移植D
到C
。重复每个回购。
如果你想要章鱼合并,请将repo分支在空的&#34;初始提交&#34; (您将使用commit --allow-empty
创建)而不是独立生根每个。 (但是,如果你需要保留提交ID,那当然不是一个选项;在这种情况下,获得章鱼合并最多是困难的。)
回到为什么rebase可能成为一个问题:基本上有两个问题。
首先,它最多移动一个分支头。如果您有其他参考(标签,多个分支),您必须单独移动它们。 (我说&#34;手动&#34;,但是如果有很多这样的话你可以找到一种方法来编写脚本...但是显而易见的解决方案 - 运行多个rebase操作 - 没有做你想要的事。)
更重要的是,它并没有很好地处理合并。默认情况下,它想要产生一个线性历史记录,它似乎无法跟踪它在回到&#34;另一方面时所做的事情。合并。
您可以通过指定--preserve-merges
来修复大约80%的问题,通过合并进行变基,这会尝试修剪和删除子树&#34;因为它是&#34;而不是将子树中的历史线性化。但如果合并未通过默认合并策略100%自动完成,则会发生以下两种情况之一:
如果您很幸运,当rebase尝试重做合并时,它会因冲突而失败,并且您将被咨询以重做冲突解决方案(当然,这可能是由其他人完成的,或者其他什么,但至少你有机会修复它)。最糟糕的情况是合并不会因冲突而失败,但仍然不对(因为原始合并是通过--no-commit
编辑完成的,或者是使用默认合并以外的其他方式完成的战略导致不同的结果)。在这种情况下,rebase
不知道它是不对的,并且会在你的历史被打破的情况下默默地继续下去。
出于这个原因,如果你确实改变了一个非平凡的历史,你可能不得不使用--preserve-merges
和彻底验证最终结果,例如:通过提交将新子树与旧子树进行比较。 (这并不容易,但在你的情况下,它只是比较一个特定的子树,所以至少是可行的。)