git subtree

Posted zyfd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了git subtree相关的知识,希望对你有一定的参考价值。

此文已由作者张磊授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

前言

目前对 git 仓库拆分的已有实现之一。这里 git subtree 并不是 subtree merge strategy,这两个不是一个东西。


准备工作

  1. 首先创建主仓库 subrepo-master,随意提交一次文本,接着拉取到本地

  2. 建立子仓库 subrepo,随意提交一次文本,同时准备多个分支进行任意提交备用。


操作

  1. 运行 git remote add subtree1 <url> 添加子仓库链接

  2. 添加子仓库 git subtree add --prefix=subtree/subtree1 subtree1 master,这里的 prefix 指向的是本地存放子仓库的目录, subtree1 是第一步添加的远端链接 ,master 是远端分支。添加完成后,就得到了第一个子仓库。

  3. 运行 git status 会发现没有本地修改,接着运行 git log,会发现多了一次提交信息,看起来 git subtree 在添加的时候会自动提交一次,现在可以选择把提交推送到远端。

     commit 6cd935426f68cd670d50a7fb02065af9a0cded19 Merge: fbc33ec afdc5bf     Add ‘subtree/subtree1/‘ from commit ‘afdc5bf559beacb08032e23d22a2beaa65d3ca9c‘
    
         git-subtree-dir: subtree/subtree1
         git-subtree-mainline: fbc33ec2739057789595c13d2313b87848bf25c0
         git-subtree-split: afdc5bf559beacb08032e23d22a2beaa65d3ca9c
  4. 接着会做一些操作,模拟各种情况,如主仓库子仓库修改推送、子仓库远端拉取合并等。

  5. 主仓库子仓库修改推送到远端

    首先对主仓库子仓库的文件做一些修改并本地提交(记住提交的 message),接着可以直接推送到远端。观察远端主仓库会发现修改顺利提交,subrepo 没有发生改变,这时候就可以体会出一点 subtree 的设计了。如果想推送子仓库,需要使用命令 git subtree push --prefix=subtree/subtree1 subtree1 master。再次观察远端,会发现修改被推送上去了,而且 message 一致。当然你可以选择不推送到 master 分支,随意找一个 git subtree push --prefix=subtree/subtree1 subtree1 master2 也是可以的。观察远端会发现多出一个 master2 分支。

  6. 远端子仓库有修改

    对远端子仓库修改。然后拉取此次提交合并到主仓库。运行此命令拉取即可 git subtree pull --prefix=subtree/subtree1 subtree1 master2,这时候如果有冲突,就需要解决冲突,分别推送主仓库子仓库。然后观察远端仓库,会发现主仓库、子仓库都有了提交以及解决冲突的操作。

  7. 远端子仓库做了大量提交

    希望从远端拉取合并到主仓库 git subtree pull --prefix=subtree/subtree1 subtree1 master2,再运行 git log 然后会发现主仓库的提交日志多了很多,是子仓库的提交日志 + 1 条,如果不希望子仓库污染主仓库的提交日志,可以使用 --squash 这个命令。git subtree pull --prefix=subtree/subtree1 subtree1 master2 --squash,就得到干净了日志了(一次是 squash 整理的提交,一次是合并),但是合并的时候有冲突需要解决。

  8. 本地子仓库合并远端子仓库 branch、tag、commitid

    如果分支没有在本地拉取,则需要先 git fetch subtree1,接着再

     git subtree merge --prefix=subtree/subtree1 subtree1/a
     // or
     git subtree merge --prefix=subtree/subtree1 v2.0
     // or
     git subtree merge --prefix=subtree/subtree1 e1e9aef94c0ce5ede4716d3c1e48cc58c15b7ffe
  9. 本地子仓库改变分支

    可以通过 git subtree pull --prefix=subtree/subtree1 subtree1 b 的方式,但是方式的缺点显而易见,需要手工再次合并代码等等。还有另一种方案,先删去目录,然后重新添加进来。


技巧

  1. 命令表

     git subtree add   -P <prefix> <commit>
     git subtree add   -P <prefix> <repository> <ref>
     git subtree pull  -P <prefix> <repository> <ref>
     git subtree push  -P <prefix> <repository> <ref>
     git subtree merge -P <prefix> <commit>
     git subtree split -P <prefix> [OPTIONS] [<commit>]
  2. 如果想要历史记录干净一点,可以使用 --squash,可用于 add, merge, push, pull 命令。但是加了 --squash 也有自己的问题,上面已做描述,这个最好一开始就统一使用一种。当然有人也有解决方案 https://stackoverflow.com/questions/9777564/git-subtree-pull-complications


缺点

  1. 合并策略的学习成本

  2. 返回历史版本稍显复杂

  3. 不要混合提交主仓库、子仓库代码

  4. 将子仓库推送到远端很慢,相当于对主仓库下某个子仓库的目录的提交记录进行分割,以找出子仓库的修改,这个过程有点慢,如果推送周期比较长倒是可以尝试。

  5. 需要添加多个远端,子仓库和远端没有地方存储映射关系。由命令 git subtree pull --prefix=subtree/subtree1 subtree1 master2 可以看出来,可以推送子仓库的代码到任意能推送的地方。

  6. 改子仓库的分支略坑


优点

  1. 拷贝主仓库后,可以直接使用

  2. 使用者可以不关注子树依赖,对使用者无感知,不需要子仓库权限

  3. 子树不像子模块会添加多余的文件,对仓库无污染

  4. 对子仓库的同步可交由单独的维护者


参考

  1. https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt

  2. https://developer.atlassian.com/blog/2015/05/the-power-of-git-subtree/

  3. https://www.atlassian.com/blog/git/alternatives-to-git-submodule-git-subtree

  4. https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec


免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击


相关文章:
【推荐】 一个只有十行的精简MVVM框架
【推荐】 巧用Scrum与Kanban





















以上是关于git subtree的主要内容,如果未能解决你的问题,请参考以下文章

git subtree:无缝管理通用子项目

git subtree 使用

Git 进阶 - 子仓库 subtree

使用 git-subtree 添加远程仓库的子目录

Git应用详解第十讲:Git子库:submodule与subtree

git subtree submodule