學(xué)習(xí)背景
問(wèn)題實(shí)例(真實(shí)訴求)
一個(gè)工具類庫(kù),有以下兩個(gè)目標(biāo):
- 不與業(yè)務(wù)相關(guān),便于復(fù)用
- 方案:maven 作為依賴引用,使用方便,但更新繁瑣
- 優(yōu)點(diǎn):使用方便
- 缺點(diǎn):1. 不易更新,發(fā)現(xiàn)工具類不符合需求時(shí),直接要更改源倉(cāng)庫(kù)處理,update 使用;2.gradle 引用后,在沒(méi)有 download 源碼的情況下,看不到注釋,注釋對(duì)于一個(gè)工具類還是很重要的
- 方案:maven 作為依賴引用,使用方便,但更新繁瑣
- 需要快速迭代更新
- 方案:直接引用 lib 源碼,更新便捷實(shí)時(shí),但不適合多項(xiàng)目的使用
如果直接使用 Git 管理這個(gè)lib 添加到這個(gè)項(xiàng)目來(lái)呢,單獨(dú)維護(hù)??赡芫蜁?huì)出現(xiàn)每一次更新 repo 就要更新多個(gè) repo 的情況。對(duì)于有很多開(kāi)發(fā)協(xié)同者來(lái)說(shuō),簡(jiǎn)直是災(zāi)難。
git subtree 是什么?
git subtree 可以實(shí)現(xiàn)一個(gè)倉(cāng)庫(kù)作為其他倉(cāng)庫(kù)的子倉(cāng)庫(kù),能夠相對(duì)較好的解決上面兩難問(wèn)題。
subtree
有個(gè)和 git subtree 概念類似的功能 git submodule,雖然都沒(méi)有用過(guò),但目前來(lái)看 git subtree 比 git submodule 更加強(qiáng)大,是可以替代 submodule 的方案。
-
git submodule在本地可能存在多個(gè) git 代碼倉(cāng)庫(kù) -
git subtree只有一個(gè)代碼庫(kù),也就是說(shuō)在項(xiàng)目?jī)?nèi)部依賴外部獨(dú)立項(xiàng)目的時(shí)候,是完全無(wú)感知的操作。
subtree 的作用就是可以實(shí)現(xiàn)一個(gè)倉(cāng)庫(kù)作為其他倉(cāng)庫(kù)的子倉(cāng)庫(kù),對(duì)于主項(xiàng)目來(lái)說(shuō),另一個(gè)項(xiàng)目只作為主項(xiàng)目的一個(gè)子目錄而存在。

圖片來(lái)自 :https://segmentfault.com/a/1190000012002151
使用
$ git subtree -h
usage: git subtree add --prefix=<prefix> <commit>
or: git subtree add --prefix=<prefix> <repository> <ref>
or: git subtree merge --prefix=<prefix> <commit>
or: git subtree pull --prefix=<prefix> <repository> <ref>
or: git subtree push --prefix=<prefix> <repository> <ref>
or: git subtree split --prefix=<prefix> <commit>
-h, --help show the help
-q quiet
-d show debug messages
-P, --prefix ... the name of the subdir to split out
-m, --message ... use the given message as the commit message for the merge commit
options for 'split'
--annotate ... add a prefix to commit message of new commits
-b, --branch ... create a new branch from the split subtree
--ignore-joins ignore prior --rejoin commits
--onto ... try connecting new tree to an existing one
--rejoin merge the new branch back into HEAD
options for 'add', 'merge', and 'pull'
--squash merge subtree changes as a single commit
在主項(xiàng)目中添加子項(xiàng)目
創(chuàng)建一個(gè)git repo GitStudy
創(chuàng)建一個(gè) lib repo commonToolsCopy
使用 subtree 命令,將 tools 放到 gitStudy 目錄下(作為lib)
下面 commonTools
$ git subtree add --prefix=commonTools http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git master --squash
--squash參數(shù)表示不拉取歷史信息,而只生成一條 commit 信息。
=后面的 commonTools 是子項(xiàng)目 clone 后在本地的目錄名,可以是多級(jí),比如 lib/xxx
master指的是子項(xiàng)目的分支名
上面命令執(zhí)行后,就可以將 commonTools 倉(cāng)庫(kù)中 master 上的更新更新到本地
$ git subtree add --prefix=commonTools http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git master --squash
git fetch http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git master
warning: no common commits
remote: Enumerating objects: 242, done.
remote: Counting objects: 100% (242/242), done.
remote: Compressing objects: 100% (99/99), done.
remote: Total 242 (delta 44), reused 242 (delta 44)
Receiving objects: 100% (242/242), 51.03 KiB | 4.25 MiB/s, done.
Resolving deltas: 100% (44/44), done.
From http://git.ninebot.cn:8888/tingtingtina/commontoolscopy
* branch master -> FETCH_HEAD
Added dir 'commonTools'
之后會(huì)生成兩條日志信息
$ git log
commit a0a743a92c1fc6eddc204abbcfbab0ac530d3c46 (HEAD -> master)
Merge: a8b13f3 23e60fb
Author: liting <xxlt0310@163.com>
Date: Thu Apr 15 17:25:46 2021 +0800
Merge commit '23e60fbfdaa2ce6e63b4cc666ed59cd373d33c1e' as 'commonTools'
commit 23e60fbfdaa2ce6e63b4cc666ed59cd373d33c1e
Author: liting <xxlt0310@163.com>
Date: Thu Apr 15 17:25:46 2021 +0800
Squashed 'commonTools/' content from commit d25f3bd
git-subtree-dir: commonTools
git-subtree-split: d25f3bd8f7ab886c8806f031a17d4a841671a21a
commit a8b13f3d1cba3c5402821d613b9e0ab29f028998 (origin/master)
Author: liting <xxlt0310@163.com>
Date: Thu Apr 15 17:13:05 2021 +0800
init
添加之后 commonTools 就是主項(xiàng)目的一個(gè)普通文件夾,如果這時(shí)候 commonTools 內(nèi)容更新之后,正常 git push 即可,子項(xiàng)目對(duì)于主項(xiàng)目來(lái)說(shuō)完全是透明的。
推送到子項(xiàng)目倉(cāng)庫(kù)
在主項(xiàng)目 git push 之后,對(duì)子項(xiàng)目修改的內(nèi)容是不會(huì)直接更新到子項(xiàng)目自身的
需要執(zhí)行 git subtree push
git subtree push --prefix=commonTools http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git master
子項(xiàng)目倉(cāng)庫(kù)更新
如果單獨(dú)對(duì)子項(xiàng)目做了更新,主項(xiàng)目就需要手動(dòng)更新下了
$ git subtree pull --prefix=commonTools http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git master --squash
執(zhí)行之后,仍然會(huì)在主項(xiàng)目中生成相關(guān)的 commit 記錄
在 subtree 相關(guān)命令經(jīng)常會(huì)用到 <repository> 每次都寫(xiě)地址還是比較麻煩,這里可以用 git remote 命令簡(jiǎn)化寫(xiě)法,為這個(gè)遠(yuǎn)程地址定義一個(gè) “別名”
$ git remote add utils http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git
比如使用 subtree push 的時(shí)候就可以使用如下命令
$ git subtree push --prefix=commonTools utils master
移除子項(xiàng)目(切換子項(xiàng)目分支)
在添加 subtree 的時(shí)候是指定了分支的,如果要切換分支直接移除 subtree,重新加入子項(xiàng)目的分支
git rm <subtree>
git commit
git subtree add --prefix=<subtree> <repository_url> <subtree_branch>
驗(yàn)證1:其他人 clone 該項(xiàng)目對(duì) sub repo是無(wú)感知的
驗(yàn)證2:在主項(xiàng)目中修改 sub repo 的內(nèi)容 push,在 app 中會(huì)形成 commit 在 sub repo 中不會(huì)有 commit
驗(yàn)證3:使用一下命令,可以push 到 sub repo 中 推送修改到源倉(cāng)庫(kù)
git subtree push --prefix=commonTools http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git master
驗(yàn)證4:直接在 sub repo 項(xiàng)目中更新內(nèi)容
那么 main repo 需要還是需要 pull 一下 從源倉(cāng)庫(kù)拉取更新
git subtree pull --prefix=commonTools http://git.ninebot.cn:8888/tingtingtina/commontoolscopy.git master --squash
非原理性提示 不加 --squash 不可以,
在 pull 的過(guò)程中可能需要處理沖突
驗(yàn)證5:修改的內(nèi)容同時(shí)包含主項(xiàng)目和子項(xiàng)目, 使用 git push 再使用 git subtree push 會(huì)做挑揀,但如果混雜的內(nèi)容很多的話,這個(gè)過(guò)程也會(huì)變得復(fù)雜,so 建議 盡可能分開(kāi)提交,減少這種沖突。
參考
https://segmentfault.com/a/1190000012002151
http://einverne.github.io/post/2020/04/git-subtree-usage.html