git filter branch和git subtree有什么区别?

14

在Stack Overflow上搜索了这个问题。发现了这个较旧的帖子,似乎没有给出任何答案。重新启动该帖子,希望有人知道!

有人可以告诉我git subtree和git filter-branch之间的区别吗? 我将为此使用原始问题中的相同示例:

git subtree split --prefix=some_subdir -b some_branch

git filter-branch --subdirectory-filter some_subdir some_branch
2个回答

7

2016年:是的,git subtree(一个contrib/ shell)可以用于拆分存储库,如Stu Campbell所描述的“使用Git subtrees进行存储库分离”。

不过,您需要删除在拆分文件夹中重复的代码(另请参见theamk答案):

git subtree split --prefix=path/to/code -b split
git push ~/shared/ split:master
git rm -r path/to/code
git commit -am "Remove split code."

与原生 Git 命令 git filter-branch 不同,它会重写存储库历史记录,仅选择实际影响特定子目录内容的提交。

意思是一旦运行了 filter-branch,就没有代码可以使用 git rm
git filter-branch 不像 git subtree split 一样复制提交记录:它删除(“过滤掉”)所有不符合某个条件的内容(这里是子文件夹路径)。
同样,有关更新,请参见 theamkanswer:在使用新分支时不会出现重复: git subtree split --prefix=some_subdir -b some_branch


2021年更新:

git filter-repo 可以 提取所需路径及其历史记录(剥离其他所有内容)。

 git switch -c some_branch
 git filter-repo --path some_subdir/ --refs some_branch

2
现在这个说法已经不准确了,因为git subtree现在已经成为git的官方组成部分。 - Shane Gannon
2
区别还在于,如果您有几个(n)子文件夹,您想让它们各自成为自己的存储库,使用git filter-branch需要先克隆n次,而使用subtree需要进行n次git rm。 - Qiulang
那个答案是不正确的!如果你使用“git branch”或“git checkout -b”复制分支,那么你就不需要“克隆n次”,而且你会有一个可以“git rm”的分支。在推送后,只需执行“git checkout”到原始分支即可。 - theamk
当有一个内置的工具可用时,我会犹豫推荐第三方工具(“git filter-repo”)。特别是因为大多数关于git filter-branch的注意事项不适用于此用例,因为我们不提供任何shell命令,也不会触及标签。 - theamk
@theamk,现在包含的已经过时了。 “我们不提供任何shell命令”:虽然我不确定我是否理解了这个。 - VonC

1

当按照原样执行时,差异非常小:

  • 您的“子树拆分”命令将从HEAD开始,并将结果放入some_branch中,该分支以前不能存在
  • 您的“过滤分支”命令将从some_branch开始,并将结果放回some_branch,用新内容覆盖some_branch
  • 在我的测试中,“git filter-branch”速度约为 ~50倍(在一个非常旧的仓库中,只有少数提交涉及所选路径)

换句话说,只要没有找到特殊的subtree rejoin提交,下面的两个代码片段完全相等。

git subtree split --prefix=some_subdir -b some_branch
git checkout some_branch

并且

git checkout -b some_branch
git filter-branch --subdirectory-filter some_subdir some_branch

你可能会问,为什么要使用“git subtree”?因为它支持原始作者使用的特定工作流程,包括--rejoin--onto选项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接