将git子树移动到其他存储库中 [英] Moving a git subtree into different repository
问题描述
我尝试将目录及其所有历史记录从存储库移动到另一个存储库.
I try to move a directory and all its history from repository to another repository.
使用git subtree split
可以轻松提取目录的完整历史记录.
Extracting the complete history of the directory is easy with git subtree split
.
这将创建一个新分支,可以轻松将其提取到另一个存储库中.
This creates a new branch, which can easily be fetched to the other repository.
现在,我使用git subtree add
将该目录粘贴回第二个存储库中.
Now I used git subtree add
to paste the directory back into the second repository.
如果我查看gitk
或git log --decorate --graph
,一切看起来都很好.所有提交均按预期方式存在.此外,所有文件都按预期方式显示.
If I look at gitk
or git log --decorate --graph
everything looks fine. All commits are present as expected. Also all the files are present as expected.
但是,当我尝试使用git log -- transplanted_dir/somefile
查看已移植文件的历史记录时,我只能看到由git subtree add
引起的一次合并"提交.
But when I try to see the history of a transplanted file using git log -- transplanted_dir/somefile
, I only see the one "merge" commit, resulting from the git subtree add
.
为什么我在上面的gitk中看到提交,但在单个文件的日志中却看不到?
Why do I see the commits in gitk above, but not in the log of a single file?
如果我做一个简单的git merge
,我可以看到每个文件的历史记录,但是这些文件当然不会存在于子文件夹中.
If I do a simple git merge
, I can see the history of each file, but the files will, of course not live in a subfolder.
将移动的提交整合到其他存储库中的正确方法是什么?
What is the right way to integrate the moved commits into the other repository?
重现情况的详细示例命令:
Detailed example commands to reproduce situation:
#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
推荐答案
好的,阅读源代码可以清除一切.
Alright, reading the source cleared things up.
git subtree add
非常难看:它首先使用git read-tree
将最新版本添加到给定目录中,而没有任何历史记录.之后,它使用git commit-tree
创建一个伪合并提交,以附加包含未添加前缀文件的旧历史记录.
git subtree add
is pretty ugly: It first uses git read-tree
to add the current version without any history into the given directory. Afterwards it uses git commit-tree
to create a fake merge commit to attach the old history containing the unprefixed files.
另一方面,现在HEAD的前缀文件和HEAD ^ 2的未前缀文件应该完全相同,并且应该被--follow
识别为移动.
On the other hand, now the prefixed file at HEAD and the unprefixed one in HEAD^2 should be exactly the same and should be recognized as a move by --follow
.
不幸的是,它不是这样识别的.不知道为什么.
Unfortuately it is not recognized as such. No idea why.
最好的解决方案可能是添加显式提交,将文件移动到新目录并进行常规合并. -一种替代方法是按照
The best solution is probably to add an explicit commit moving the files to the new directory and do a normal merge. - An alternative is to rewrite the history of the transplanted directory as described in How can I rewrite history so that all files, except the ones I already moved, are in a subdirectory?.
对于我的情况git subtree add
不好,正常的git merge
带有正确准备的子树似乎完全正确.
For my situation git subtree add
is bad, a normal git merge
with a correctly prepared subtree seems to be exactly the right thing.
这篇关于将git子树移动到其他存储库中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!