在子目录中合并git存储库

我想合并一个远程git仓库在我的工作git仓库作为它的子目录。 我希望生成的存储库包含两个存储库的合并历史logging,并且合并存储库中的每个文件都保留其在远程存储库中的历史logging。 我尝试使用如何使用子树合并策略中提到的子树策略 ,但在遵循该过程后,尽pipe生成的存储库确实包含两个存储库的合并历史logging,但来自远程文件的单个文件并没有保留其历史logging(他们中的任何一个“git日志”只显示一条消息“合并分支…”)。

另外我不想使用子模块,因为我不希望这两个组合的git存储库分开了。

是否有可能合并另一个远程git存储库作为子目录与来自远程存储库保存其历史的个别文件?

非常感谢您的帮助。

编辑:我目前正在尝试一个解决scheme,使用git filter-branch来重写合并存储库的历史logging。 它似乎工作,但我需要再testing一下。 我会回来报告我的发现。

编辑2:希望我让自己更清楚我给了我用git的子树战略,这导致远程存储库的文件的历史明显丢失的确切命令。 让A是我目前工作的git repo,B是git repo,我想把它作为子目录并入到A中。 它做了以下事情:

git remote add -f B <url-of-B> git merge -s ours --no-commit B/master git read-tree --prefix=subdir/Iwant/to/put/B/in/ -u B/master git commit -m "Merge B as subdirectory in subdir/Iwant/to/put/B/in." 

在这些命令进入目录subdir / Iwant / to / put / B / in后,我看到B的所有文件,但是git log其中的任何一个都只显示提交消息“合并B作为subdir / Iwant / /把/ B /中“。 它们在B中的文件历史logging丢失。

什么似乎工作(因为我是一个初学者,我可能是错的)是以下几点:

 git remote add -f B <url-of-B> git checkout -b B_branch B/master # make a local branch following B's master git filter-branch --index-filter \ 'git ls-files -s | sed "s-\t\"*-&subdir/Iwant/to/put/B/in/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new \ git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD git checkout master git merge B_branch 

上面的filter-branch命令是从git help filter-branch ,其中我只改变了subdirpath。

得到了更完整的解释后,我想我明白了,无论如何,最后我有一个解决方法。 具体来说,我相信正在发生的事情是重命名检测正在被–prefix的子树合并愚弄。 这是我的testing案例:

 mkdir -pz/az/b cd z/a git init echo A>A git add A git commit -m A echo AA>>A git commit -a -m AA cd ../b git init echo B>B git add B git commit -m B echo BB>>B git commit -a -m BB git commit -a -m BB cd ../a git remote add -f B ../b git merge -s ours --no-commit B/master git read-tree --prefix=bdir -u B/master git commit -m "subtree merge B into bdir" cd bdir echo BBB>>B git commit -a -m BBB 

我们制作git目录a和b,每个提交一个提交。 我们做一个子树合并,然后我们在新的子树中做最后的提交。

运行gitk (z / a)显示历史确实出现,我们可以看到它。 运行git log显示历史确实出现。 但是,看一个特定的文件有一个问题: git log bdir/B

那么,我们可以玩的一个技巧。 我们可以使用–follow来查看特定文件的预重命名历史logging。 git log --follow -- B 这是好的,但不是很好,因为它没有链接预合并的历史和合并后的历史。

我试着玩-M和-C,但是我不能让它跟随一个特定的文件。

所以,我认为解决scheme是告诉git有关将作为子树合并的一部分进行的重命名。 不幸的是,git-read-tree对于子树的合并非常挑剔,所以我们必须通过一个临时目录,但是在我们提交之前这个目录可能会消失。 之后,我们可以看到完整的历史。

首先,创build一个“A”仓库并进行一些提交:

 mkdir -pz/az/b cd z/a git init echo A>A git add A git commit -m A echo AA>>A git commit -a -m AA 

其次,创build一个“B”存储库并进行一些提交:

 cd ../b git init echo B>B git add B git commit -m B echo BB>>B git commit -a -m BB 

这个工作的诀窍是 :强制Git通过创build一个子目录并将内容移动到其中来识别重命名。

 mkdir bdir git mv B bdir git commit -a -m bdir-rename 

返回存储库“A”并获取并合并“B”的内容:

 cd ../a git remote add -f B ../b git merge -s ours --no-commit B/master git read-tree --prefix= -u B/master git commit -m "subtree merge B into bdir" 

为了表明他们现在合并:

 cd bdir echo BBB>>B git commit -a -m BBB 

为了certificate完整的历史被保存在一个连接的链中:

 git log --follow B 

我们在这样做之后得到了历史,但问题是,如果实际上保留旧的“b”回购协议并偶尔合并(假设它实际上是第三方单独维护的回购协议),那么自第三方将不会做重命名。 你必须尝试合并新的变化到你的版本与重命名,我担心,不会顺利。 但是,如果b离开,你赢了。

git-subtree是一个脚本,专门用于将多个存储库合并为一个,同时保留历史logging(和/或分割子树的历史logging,尽pipe这似乎与此问题无关)。 它是自1.7.11版以来作为git树的一部分发布的 。

要将版本<rev>的存储库<repo>合并为子目录<prefix> ,请使用git subtree add ,如下所示:

 git subtree add -P <prefix> <repo> <rev> 

git-subtree以更友好的方式实现了子树合并策略 。

如果你真的想把东西缝在一起,看起来嫁接。 你也应该使用git rebase --preserve-merges --onto 。 还有一个选项可以保留提交者信息的作者date。

你有没有尝试添加额外的存储库作为一个git子模块? 它不会将历史与包含的存储库合并,事实上,它将是一个独立的存储库。

我提到它,因为你没有。

我发现以下解决scheme对我可行。 首先我进入项目B,创build一个新的分支,其中所有的文件将被移动到新的子目录。 然后我推动这个新的分支来源。 接下来我去项目A,添加和获取B的远程,然后我签出移动的分支,我回到主和合并:

 # in local copy of project B git checkout -b prepare_move mkdir subdir git mv <files_to_move> subdir/ git commit -m 'move files to subdir' git push origin prepare_move # in local copy of project A git remote add -f B_origin <remote-url> git checkout -b from_B B_origin/prepare_move git checkout master git merge from_B 

如果我去子目录子目录,我可以使用git log --follow ,仍然有历史。

我不是一个混帐专家,所以我不能评论这是一个特别好的解决scheme,或者如果它有警告,但到目前为止,似乎一切正常。