爲什麼要使用subtree
在實際的項目開發過程中,公共的代碼或者模塊是必定會出現的,爲了不重複寫相同的代碼;普遍的做法就是將其抽取成一個公共模塊,這個模塊由不同的使用者引用;作爲java工程師,可能會選擇將這一部分打包封裝成一個jar,並且將其推送到Maven的私有倉庫,各個使用者將其添加到pom文件即可;但是有沒有更好的方式呢?因爲使用這種方式,對使用者來說,並不是透明的,當前可能已經更新版本了,但是我作爲使用者並不知道當前已經更新了,知道更新了可能也不知道最新版本是多少,我還得通過諮詢模塊開發人員或者說到私有倉庫去查看才能知道,那有沒有更好的方式呢?
接下來,就一起探討一種更好的管理方式:git subtree
,如果說你現在還不知道git是啥或者怎麼用?強力建議去學習一下。
什麼是git subtree?有啥優勢?
- git subtree可以將一個倉庫作爲倉庫的子倉庫
- 各個倉庫之前的版本管理是相對獨立的
- 對於使用者來說,是透明的,可能使用者根本都不知道有子倉庫的存在;
- 主子倉庫的分支同步,即你切換主項目分支的時候,關聯的子倉庫也會同步切換
缺點
- 需要學習新的操作指令,git subtree有自己的一套指令
- 指令的複雜度比較高,相比於常規的操作指令,其更加的複雜;
- 子倉庫操作的時候,由於關聯了其他倉庫,因此指令的響應速度沒有單倉庫快
- 子倉庫的分支管理比較麻煩
指令列表
git subtree add --prefix=<prefix> <commit>
git subtree add --prefix=<prefix> <repository> <ref>
git subtree pull --prefix=<prefix> <repository> <ref>
git subtree push --prefix=<prefix> <repository> <ref>
git subtree merge --prefix=<prefix> <commit>
git subtree split --prefix=<prefix> [OPTIONS] [<commit>]
幾條指令而已,再複雜也只有這麼幾條,所以相對於他的優點來說,上面說的缺點也就只是微乎其微了
操作說明
在碼雲上面創建了三個倉庫用於做測試:praent(主倉庫), childa、childb(子倉庫)
-
引入子倉庫
git remote add -f <倉庫別名> <倉庫地址> #如 git remote add -f childa https://gitee.com/pengfeilu/subtree-childa.git
這條指令不是git subtree的指令,只是爲了方便後續的操作,把倉庫引入到當前項目作爲一個remote,並且給其取了個別名,後續的操作 childa = https://gitee.com/pengfeilu/subtree-childa.git
- 添加子倉庫
git subtree add --prefix=<prefix> <repository> <ref> #如: git subtree add --prefix=childa childa master --squash #等價於: git subtree add --prefix=childa https://gitee.com/pengfeilu/subtree-childa.git master --squash
- 第一個參數
--prefix=modulea
指明子倉庫放在父倉庫存放的路徑,--prefix
可以使用大寫的-P
簡寫;這裏是放在childa目錄,也允許設置多級目錄,如childa/a/b/c - 第二個參數
modulea
子遠程倉庫地址,由於上面一個做了關聯,所以這裏直接使用的別名,直接使用遠端地址也是可以的 - 第三個參數
master
: 添加的子倉庫的分支名稱,這裏使用標籤或者commitId也是可以的 - 第四個參數
--squash
: 只將本次操作在主倉庫生成一條commit記錄,子倉庫的歷史記錄並不會合並進來,可以根據實際情況使用
- 推送更新到子倉庫
git subtree push --prefix=<prefix> <repository> <ref> #如:git subtree push --prefix=childa childa master #等價於: git subtree push --prefix=childa https://gitee.com/pengfeilu/subtree-childa.git master
參數說明等價於上面添加的參數
- 更新子倉庫代碼
測試:git subtree pull --prefix=<prefix> <repository> <ref> #如:git subtree pull --prefix=childa childa master --squash #等價於: git subtree pull --prefix=childa https://gitee.com/pengfeilu/subtree-childa.git master --squash
- 子倉庫childa添加文件並上傳
- 主倉庫基於分支獲取最新的 childa的提交
- 子倉庫childa添加文件並上傳
- 對已有的項目目錄進行拆分
以上的操作是我們從一開始就考慮好那一部分是子倉庫,從一開始就將子倉庫定義好了,這種場景比如在RPC(thrift、grpc等)相關框架自動生成的代碼,那麼這個子倉庫就是用於保存自動生成的那部分代碼,而且從一開始就有了,客戶端和服務端直接引用就好了;但是業務開發,可能會出現做到一半,發現某一部分可以抽離出來作爲一個公共的子模塊,那該怎麼做呢?
如當前我的項目下有個文件夾git subtree split --prefix=<prefix> [OPTIONS] [<commit>]
myfile
,我需要將其剝離成一個新的子項目childb
- 第一步,將myfile目錄剝離成一個新的分支
git subtree split -P myfiles -b childb
- 在主項目的同級目錄創建一個用於保存這個分支的文件夾
# 創建文件夾 mkdir ../subtree-childb # 切到對應的文件夾 cd ../subtree-childb/ # 初始化成一個git倉庫 git init
- 將剝離出來的分支併到當前目錄來
# ../subtree-praent 爲主倉庫的路徑 # childb 爲第一步剝離出來的分支名稱 git pull ../subtree-praent childb
- 將新的倉庫關聯到遠端倉庫
git remote add origin https://gitee.com/pengfeilu/subtree-childb.git
- 推送到遠端代碼
git push -u origin master
到此!git subtree的常規操作都覆蓋了,具體可以在實際使用中去體會!