Git subtree

本文轉載於https://blog.csdn.net/kinginblue/article/details/78290955

零、前言
既然你已經在找 git subtree 相關的東西了,那麼我可以假定你的目的和大家的都差不多:把一個項目作爲子項目,在多個項目中共享&維護。

還是舉個例子吧:

假設你有一個在線商城項目 Shop,這個項目下有個訂單模塊 order,這個 order 模塊很通用,你在下一個團購系統 Groupon,也要用到這個 order 模塊,最簡單的方式就是把整個 order 模塊 copy 過來。

然而,這種 copy 方式,會很難維護:order 模塊修改了一個Bug,然後又要複製更新到所有用了 order 模塊的項目裏。

這時就需要 git subtree 來管理這個 order 模塊了:把 order 模塊單獨作爲一個 git 倉庫,在需要用到 order 模塊的項目,通過使用 git subtree 把 order 模塊當作一個 git 項目來引入,這就解決了 order 模塊的共享和維護問題。

零零、相關命令
git subtree --help 可以查看 git subtree 命令的幫助文檔。

git subtree 命令中,都會用到一個參數 --prefix=<prefix>,可以簡寫成 -P <prefix>,本文的命令都是這樣使用的。

git subtree add 添加項目作爲子樹
git subtree add -P <子樹名> <子倉庫地址> <分支>
1
執行以上命令後,項目下就會新創建一個名爲 <子樹名> 的目錄。

如果提前使用 git remote add <子倉庫名> <子倉庫地址> 添加了子項目的遠程倉庫地址(建議按此方式,下文都基於此),那麼也可以這樣:

git subtree add -P <子樹名> <子倉庫名> <分支>
1
以上命令可以多加一個 --squash 參數:

git subtree add -P <子樹名> <子倉庫名> <分支> --squash
1
--squash 參數含義是:把 subtree 的改動合併成一次commit,這樣就不用拉取子項目完整的歷史記錄。

git subtree pull 從子倉庫拉取子樹更新
先 fetch:

git fetch <子倉庫名> <分支>
1
後 pull:

git subtree pull -P <子樹名> <子倉庫名> <分支>
1
以上命令也可以多加一個 --squash 參數:

git subtree pull -P <子樹名> <子倉庫名> <分支> --squash
1
--squash 參數含義同上。

git subtree push 推送子樹更新到子倉庫
git subtree push -P <子樹名> <子倉庫名> <分支>
1
一、場景一:把其他已有項目,添加爲子樹
場景假設:新建了一個團購系統項目 Groupon,也需要用到 order 模塊,那麼按以下步驟即可:

添加子項目的遠程倉庫地址:

git remote add order-repo https://github.com/xxx/order.git
1
在 Groupon 項目裏進行添加項目作爲子樹:

cd Groupon
git subtree add -P order order-repo master --squash
git subtree pull -P order order-repo master
1
2
3
二、場景二:把項目裏的某個目錄,分割出去作爲子樹維護
場景假設:現在在開發 Shop 項目有一段時間了,發現裏面的 order 模塊非常通用,着手使用 git subtree 把 order 作爲一個子項目單獨維護。

2.1 方式一:分割出去,並清理 commit 記錄
命令過程:

cd Shop
git subtree split -P shop -b order-branch    //1

cd ../                                      //2
mkdir tempDir                               //2
cd tempDir                                  //2
git init                                    //2
git pull ../Shop order-branch               //2

git remote add order-repo https://github.com/xxx/order.git  //3
git push -u order-repo master                               //3

cd ../              //4
rm -rf tempDir      //4

cd Shop                                                                                                      //5
git filter-branch -f --index-filter "git rm -r -f -q --cached --ignore-unmatch order" --prune-empty HEAD     //5 注意:這裏是 order,那個子目錄(-P 對應的值)

git branch -D order-branch      //6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
流程說明: 
1. 在 Shop 項目裏把 order 模塊分割成一個臨時分支 order-branch 
2. 項目外新建一個臨時目錄 tempDir 並創建 git 倉庫,拉取這個 order 模塊的臨時分支 order-branch 
3. 在臨時目錄裏,添加 order 子項目的遠程倉庫地址,並 push 到該遠程倉庫 
4. 刪除臨時目錄 tempDir 
5. 清理掉原來的 order 模塊的 commit 記錄 
6. 按需刪除臨時分支 order-branch

當然,把 order 模塊抽離出去之後,這個 Shop 項目還是需要用到 order 模塊的,重新走一遍 《場景一(把其他已有項目,添加爲子樹)》 的流程就可以了:

cd Shop
git remote add order-repo https://github.com/xxx/order.git
git subtree add -P order order-repo master --squash
git subtree pull -P order order-repo master
1
2
3
4
2.2 方式二:直接作爲子樹提交到子倉庫,不清理 commit 記錄
git subtree --help 查看文檔,git subtree push 命令本身就會進行 git subtree split 操作:

Does a split (see below) using the <prefix> supplied and then does a git push to push the result to the repository and ref. 
This can be used to push your subtree to different branches of the remote repository.
1
2
所以簡單點就 git subtree push 完事。

命令過程:

cd Shop

git remote add order-repo https://github.com/xxx/order.git  //1

git subtree push -P order order-repo master  //2
1
2
3
4
5
流程說明: 
1. 添加 order 子項目的遠程倉庫地址 
2. order 模塊作爲 order 子樹 push 到遠程倉庫

三、場景三:在現有項目裏,新建了一個子模塊(子目錄),準備當作子樹維護
場景假設:現在在開發 Shop 項目,剛新建了個 order 模塊(還未提交到git),準備把這個 order 模塊當作一個子項目維護。

3.1 方式一:子模塊(子目錄)單獨提交到遠程倉庫,刪除子模塊(子目錄)後,重新引入
網上這這個場景的資料比較少,以至於我一開始是先提交這個 order 模塊,然後再走場景二的流程。

後來發現可以簡單點:git 允許在 git 倉庫的子目錄下再創建 git 倉庫,所以一切都好辦了:

命令過程:

cd Shop/order                                               //1
git init                                                    //1
git add .                                                   //1
git commit -m "add order ..."                                //1
git remote add order-repo https://github.com/xxx/order.git       //1
git push -u order-repo master

cd ../                                                      //2
rm -rf order                                                //2

git remote add order-repo https://github.com/xxx/order.git       //3
git subtree add -P order order-repo master --squash              //3
1
2
3
4
5
6
7
8
9
10
11
12
流程說明: 
1. 進入 order 模塊創建倉庫、提交、添加遠程倉庫地址、push 
2. 刪除 order 模塊 
3. 添加 order 子項目遠程倉庫地址,git subtree add 添加 order 子項目作爲子樹

3.2 方式二:先把子模塊(子目錄)提交,然後 git subtree push
這就和 場景二 裏的 《2.2 方式二:直接作爲子樹提交到子倉庫,不清理 commit 記錄》 一樣了。

四、日常一:刪除子樹
場景假設:突然有一天,Shop 項目不再開放下單功能,以後也僅僅做靜態展示,很確定 order 子模塊可以刪除了,那麼有以下兩種刪除途徑。

4.1、刪除子模塊目錄,並commit
git rm -r <子模塊目錄名>
git commit -m "remove <子模塊目錄名> ..."
1
2
此方式的缺點就是 git log 裏還有留着 order 子模塊的 commit 歷史。

4.2、使用 filter-branch
git filter-branch -f --index-filter "git rm -r -f -q --cached --ignore-unmatch order" --prune-empty HEAD    //注意:這裏是 order,那個子模塊(-P 對應的值)
1
此方式可以把order 子模塊的 commit 歷史一併刪除。

五、日常二:重命名子樹
場景假設:突然有一天,空降了一個領導,他對 Shop 項目裏的 order 子項目的目錄命名非常看不順眼,命令我們改成拼音 xiadan,雖然很扯,但是不得不照做。

但是要按實際情況來:

5.1、不影響子樹內的文件內容時
直接重命名子樹的目錄名,並提交:

cd shop
mv order xiadan
git add .
git commit -m "reanme order -> xiadan"
1
2
3
4
只是以後 pull 和 psuh 子樹的命令要改變少少:

git subtree pull -P xiadan order-repo master    //原來的 -P 參數值也由 order 改成 xiadan
git subtree push -P xiadan order-repo master    //原來的 -P 參數值也由 order 改成 xiadan
1
2
5.1、會影響子樹內的文件內容時
重命名子樹後,會影響到子樹內的文件內容時(比如 Java,改一下目錄名,類文件裏的 import 就出問題了),那就不能像上一步那樣直接改了,因爲會影響到其他使用 order 子樹的項目!

那就只能走 《日常一:刪除子樹》 流程,先刪除子樹,然後重新引入了!

先刪除(把 order 的本地歷史記錄也一併刪了):

git filter-branch -f --index-filter "git rm -r -f -q --cached --ignore-unmatch order" --prune-empty HEAD
1
然後重新引入:

git remote add xiadan-repo https://github.com/xxx/order.git  // 乾脆把 order 的遠程倉庫也命名成 xiadan-repo 吧!
git subtree pull -P xiadan xiadan-repo master    //原來的 -P 參數值也由 order 改成 xiadan
git subtree push -P xiadan xiadan-repo master    //原來的 -P 參數值也由 order 改成 xiadan
1
2
3
好像沒什麼好寫了 ):

附、參考資料
git subtree --help
使用git subtree集成項目到子目錄
Git Subtree 的介紹及使用
使用git的subtree將已有項目的某個目錄分離成獨立項目
git subtree: possible to change subtree branch/path in a forked repository?
How to remove previously added git subtree and its history
--------------------- 
作者:kinginblue 
來源:CSDN 
原文:https://blog.csdn.net/kinginblue/article/details/78290955 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章