👉️URL: https://www.atlassian.com/git/tutorials/git-subtree
✍️Author: Nicola Paolucci
📝Description:
Git subtree 让你把一个仓库嵌套在另一个子目录中。它是 Git 可以管理项目依赖关系的几种方式之一。
git 分支的图解
互联网上有很多关于为什么你不应该使用 Git submodule 的文章。虽然 submodule 在一些使用情况下很有用,但它们确实有一些缺点。
有替代品吗?答案是:有!有(至少)两个工具可以帮助跟踪你项目中的软件依赖历史,同时允许你继续使用 Git。
git subtree
- Google repo
在这篇文章中,我们将看看git subtree
,并说明为什么它比 git submodule 有进步–尽管不是很完美。
什么是git subtree
,我为什么要使用它?
git subtree
让你把一个仓库嵌套在另一个子目录中。它是 Git 项目管理项目依赖关系的几种方式之一。
图中显示了使用 Git Subtree 前后两个仓库之间的互动
为什么你可能要考虑git subtree
?
- 简单工作流的管理很容易。
- 支持老版本的 Git(甚至比 v1.5.2 更老)。
- 子项目的代码在父级项目的克隆完成后就可以使用。
git subtree
不需要你的仓库的用户学习任何新东西。他们可以忽略你使用git subtree
来管理依赖关系的事实。git subtree
不会像 git submodule 那样添加新的元数据文件(即.gitmodule
)。- 模块的内容可以被修改,而不需要在其他地方有单独的依赖关系的仓库副本。
缺点(但在我们看来,这些缺点基本可以接受)。
- 你必须学习新的合并策略(即
git subtree
)。 - 为子项目向上游贡献代码稍显复杂。
- 在提交中不混合父级项目和子项目代码的责任在于你。
如何使用 git subtree
git subtree
自 2012 年 5 月起在 Git 的库存版本中可用 - v1.7.11 及以上。homebrew 软件在 OSX 上安装的版本已经将 subtree 正确地连接起来,但在某些平台上,你可能需要按照安装说明进行安装。
下面是一个使用git subtree.
tracking vim 插件的典型例子。
没有 remote tracking 的快速和肮脏的方法
如果你只想剪切和粘贴几句单句,请阅读这一段。首先在指定的前缀文件夹下添加git subtree
。
git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squash BASH |
(通常的做法是不把子项目的全部历史保存在主版本库中,但如果你想保存它,只需省略 --squash
标志)。
上述命令产生了这样的输出。
git fetch https://bitbucket.org/vim-plugins-mirror/vim-surround.git main warning: no common commits remote: Counting objects: 338, done. remote: Compressing objects: 100% (145/145), done. remote: Total 338 (delta 101), reused 323 (delta 89) Receiving objects: 100% (338/338), 71.46 KiB, done. Resolving deltas: 100% (101/101), done. From https://bitbucket.org/vim-plugins-mirror/vim-surround.git * branch main -} FETCH_HEAD Added dir '.vim/bundle/tpope-vim-surround' BASH |
正如你所看到的,这是通过将 vim-surround 版本库的全部历史压缩成一个单一的历史来记录一个合并提交。
1bda0bd [3 minutes ago] (HEAD, stree) Merge commit 'ca1f4da9f0b93346bba9a430c889a95f75dc0a83' as '.vim/bundle/tpope-vim-surround' [Nicola Paolucci] ca1f4da [3 minutes ago] Squashed '.vim/bundle/tpope-vim-surround/' content from commit 02199ea [Nicola Paolucci] N1QL |
如果过了一段时间,你想从上游仓库更新插件的代码,你可以只做一个 git subtree pull。
git subtree pull --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squash BASH |
这是非常快速和无痛的,但命令略显冗长,难以记忆。我们可以通过添加子项目作为 remote 来使命令更短。
将子项目添加为 remote
将 subtree 作为一个 remote 添加,可以让我们以更短的形式来引用它。
git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git VIM |
现在我们可以添加 subtree(和以前一样),但现在我们可以用简短的形式来引用远程。
git subtree add --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squash VIM |
以后更新子项目的命令变成:
git fetch tpope-vim-surround main git subtree pull --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squash CSS |
回馈上游
现在我们可以自由地提交我们的修正到本地工作目录中的子项目。当需要向上游项目做出贡献时,我们需要分叉该项目并将其作为另一个远程项目。
git remote add durdn-vim-surround ssh://git@bitbucket.org/durdn/vim-surround.git BASH |
现在我们可以像下面这样使用子树推送命令。
git subtree push --prefix=.vim/bundle/tpope-vim-surround/ durdn-vim-surround main git push using: durdn-vim-surround main Counting objects: 5, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 308 bytes, done. Total 3 (delta 2), reused 0 (delta 0) To ssh://git@bitbucket.org/durdn/vim-surround.git 02199ea..dcacd4b dcacd4b21fe51c9b5824370b3b224c440b3470cb -} main BASH |
在这之后,我们就准备好了,我们可以向软件包的维护者发出 pull-request。
我可以不使用 git subtree
命令来做这个吗?
是的!是的,可以。git subtree
与 subtree merge 策略不同。即使由于某种原因 git subtree
不可用,你仍然可以使用合并策略。以下是你如何去做的。
将依赖关系作为一个简单的 git remote
添加。
git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git BASH |
在将依赖关系的内容读入版本库之前,记录一个合并是很重要的,这样我们就可以跟踪到此为止的整个插件树历史。
git merge -s ours --no-commit tpope-vim-surround/main BASH |
输出为:
Automatic merge went well; stopped before committing as requested BASH |
然后,我们将最新的 tree-object 的内容读入插件库,进入我们的工作目录,准备提交。
git read-tree --prefix=.vim/bundle/tpope-vim-surround/ -u tpope-vim-surround/main BASH |
现在我们可以提交了(这将是一个合并提交,将保留我们所读的树的历史)。
git ci -m"[subtree] adding tpope-vim-surround" [stree 779b094] [subtree] adding tpope-vim-surround BASH |
当我们想更新项目时,我们现在可以使用 git subtree
合并策略进行拉动。
git pull -s subtree tpope-vim-surround main CSS |
Git subtree
是一个很好的选择
在使用了一段时间的 git submodule 之后,你会发现 git subtree 解决了很多 git submodule 的问题。像往常一样,对于所有 Git 的东西,要想充分利用这个功能,都有一个学习曲线。
在 Twitter 上关注我 @durdn,了解更多关于 Git 的事情和东西。如果你正在寻找一个好的工具来管理你的 Git 仓库,请查看 Atlassian Bitbucket。