将 git 子树移动到不同的存储库

mic*_*has 5 git git-subtree

我尝试将目录及其所有历史记录从存储库移动到另一个存储库。

提取目录的完整历史记录很容易git subtree split

这会创建一个新分支,可以轻松地将其提取到其他存储库。

现在我曾经git subtree add将目录粘贴回第二个存储库。

如果我看gitkgit log --decorate --graph一切看起来都很好。所有提交都按预期存在。此外,所有文件都按预期存在。

但是,当我尝试使用的是看一个移植文件的历史记录git log -- transplanted_dir/somefile,我只看到了一个“合并”承诺,从产生的git subtree add

为什么我在上面的 gitk 中看到提交,但在单个文件的日志中没有?

如果我做一个简单的git merge,我可以看到每个文件的历史记录,但是这些文件当然不会存在于子文件夹中。

将移动的提交集成到另一个存储库中的正确方法是什么?

重现情况的详细示例命令:

#create two repositories:
git init a
git init b

# create directory dir with some history
cd a
mkdir dir
echo 1 > dir/file
git add .
git commit -am 1
echo 2 > dir/file
git commit -am 2
echo 3 > dir/file
echo 3 > otherfile
git add .
git commit -am 3

#split subtree
git subtree split --prefix dir -b split

#create a commit on repo b
cd ../b
mkdir otherdir
touch otherdir/file
git add .
git commit -am init

#fetch split branch of repo a
git fetch ../a split
git co -b split FETCH_HEAD
git log --decorate --graph --name-status 
git co master

# add commits to repo b
git subtree add --prefix somedir split

# this looks fine:
git log --decorate --graph --name-status

# no history here - Why?
git log --decorate --graph --name-status somedir/file
git log --decorate --graph --name-status --follow somedir/file
Run Code Online (Sandbox Code Playgroud)

mic*_*has 3

好吧,阅读源代码就清楚了。

git subtree add非常丑陋:它首先用于将没有任何历史记录的当前版本git read-tree添加到给定目录中。然后,它用于创建一个假合并提交来附加包含无前缀文件的旧历史记录。git commit-tree

另一方面,现在 HEAD 中的带前缀文件和 HEAD^2 中的无前缀文件应该完全相同,并且应该被识别为 的移动--follow

不幸的是,它并没有得到这样的认可。不知道为什么。

最好的解决方案可能是添加显式提交,将文件移动到新目录并进行正常合并。- 另一种方法是重写移植目录的历史记录,如如何重写历史记录中所述,以便所有文件(除了我已经移动的文件)都位于子目录中?

对于我的情况git subtree add很糟糕,git merge具有正确准备的子树的法线似乎是完全正确的事情。