使用子模塊和子樹來管理 Git 項目
如果你參與了開源項目的開發,那麼你很可能已經用了 Git 來管理你的源碼。你可能遇到過有很多依賴和/或子項目的項目。你是如何管理它們的?
對於一個開源組織,要實現社區和產品的單一來源文檔和依賴管理比較棘手。文檔和項目往往會碎片化和變得冗餘,這致使它們很難維護。
必要性
假設你想把單個項目作為一個存儲庫內的子項目,傳統的方法是把該項目複製到父存儲庫中,但是,如果你想要在多個父項目中使用同一個子項目呢?如果把子項目複製到所有父項目中,當有更新時,你都要在每個父項目中做修改,這是不太可行的。這會導致父項目中的冗餘和數據不一致,使更新和維護子項目變得很困難。
Git 子模塊和子樹
如果你可以用一條命令把一個項目放進另一個項目中,會怎樣呢?如果你隨時可以把一個項目作為子項目添加到任意數目的項目中,並可以同步更新修改呢?Git 提供了這類問題的解決方案:Git 子模塊 和 Git 子樹 。創建這些工具的目的是以更加模塊化的水平來支持共用代碼的開發工作流,旨在 Git 存儲庫 源碼管理 (SCM)與它下面的子樹之間架起一座橋樑。
![Cherry tree growing on a mulberry tree](/data/attachment/album/202005/23/201448jcxlcci1f1z4c2l2.jpg "Cherry tree growing on a mulberry tree")
生長在桑樹上的櫻桃樹
下面是本文要詳細介紹的概念的一個真實應用場景。如果你已經很熟悉樹形結構,這個模型看起來是下面這樣:
![Tree with subtrees](/data/attachment/album/202005/23/201451xllv5o14lc4344tp.png "Tree with subtrees")
Git 子模塊是什麼?
Git 在它默認的包中提供了子模塊,子模塊可以把 Git 存儲庫嵌入到其他存儲庫中。確切地說,Git 子模塊指向子樹中的某次提交。下面是我 Docs-test GitHub 存儲庫中的 Git 子模塊的樣子:
![Git submodules screenshot](/data/attachment/album/202005/23/201452dliztziziialcmbq.png "Git submodules screenshot")
文件夾@提交 Id 格式表明這個存儲庫是一個子模塊,你可以直接點擊文件夾進入該子樹。名為 .gitmodules
的配置文件包含所有子模塊存儲庫的詳細信息。我的存儲庫的 .gitmodules
文件如下:
![Screenshot of .gitmodules file](/data/attachment/album/202005/23/201454khhen8n8cpe698hp.png "Screenshot of .gitmodules file")
你可以用下面的命令在你的存儲庫中使用 Git 子模塊:
克隆一個存儲庫並載入子模塊
克隆一個含有子模塊的存儲庫:
$ git clone --recursive <URL to Git repo>
如果你之前已經克隆了存儲庫,現在想載入它的子模塊:
$ git submodule update --init
如果有嵌套的子模塊:
$ git submodule update --init --recursive
下載子模塊
串列地連續下載多個子模塊是很枯燥的工作,所以 clone
和 submodule update
會支持 --jobs
(或 -j
)參數:
例如,想一次下載 8 個子模塊,使用:
$ git submodule update --init --recursive -j 8
$ git clone --recursive --jobs 8 <URL to Git repo>
拉取子模塊
在運行或構建父項目之前,你需要確保依賴的子項目都是最新的。
拉取子模塊的所有修改:
$ git submodule update --remote
使用子模塊創建存儲庫:
向一個父存儲庫添加子樹:
$ git submodule add <URL to Git repo>
初始化一個已存在的 Git 子模塊:
$ git submodule init
你也可以通過為 submodule update
命令添加 --update
參數在子模塊中創建分支和追蹤提交:
$ git submodule update --remote
更新子模塊的提交
上面提到過,一個子模塊就是一個指向子樹中某次提交的鏈接。如果你想更新子模塊的提交,不要擔心。你不需要顯式地指定最新的提交。你只需要使用通用的 submodule update
命令:
$ git submodule update
就像你平時創建父存儲庫和把父存儲庫推送到 GitHub 那樣添加和提交就可以了。
從一個父存儲庫中刪除一個子模塊
僅僅手動刪除一個子項目文件夾不會從父項目中移除這個子項目。想要刪除名為 childmodule
的子模塊,使用:
$ git rm -f childmodule
雖然 Git 子模塊看起來很容易上手,但是對於初學者來說,有一定的使用門檻。
Git 子樹是什麼?
Git 子樹 ,是在 Git 1.7.11 引入的,讓你可以把任何存儲庫的副本作為子目錄嵌入另一個存儲庫中。它是 Git 項目可以注入和管理項目依賴的幾種方法之一。它在常規的提交中保存了外部依賴信息。Git 子樹提供了整潔的集成點,因此很容易復原它們。
如果你參考 GitHub 提供的子樹教程來使用子樹,那麼無論你什麼時候添加子樹,在本地都不會看到 .gittrees
配置文件。這讓我們很難分辨哪個是子樹,因為它們看起來很像普通的文件夾,但是它們卻是子樹的副本。默認的 Git 包中不提供帶 .gittrees
配置文件的 Git 子樹版本,因此如果你想要帶 .gittrees
配置文件的 git-subtree 命令,必須從 Git 源碼存儲庫的 /contrib/subtree 文件夾 下載 git-subtree。
你可以像克隆其他常規的存儲庫那樣克隆任何含有子樹的存儲庫,但由於在父存儲庫中有整個子樹的副本,因此克隆過程可能會持續很長時間。
你可以用下面的命令在你的存儲庫中使用 Git 子樹。
向父存儲庫中添加一個子樹
想要向父存儲庫中添加一個子樹,首先你需要執行 remote add
,之後執行 subtree add
命令:
$ git remote add remote-name <URL to Git repo>
$ git subtree add --prefix=folder/ remote-name <URL to Git repo> subtree-branchname
上面的命令會把整個子項目的提交歷史合併到父存儲庫。
向子樹推送修改以及從子樹拉取修改
$ git subtree push-all
或者
$ git subtree pull-all
你應該使用哪個?
任何工具都有優缺點。下面是一些可能會幫助你決定哪種最適合你的特性:
- Git 子模塊的存儲庫佔用空間更小,因為它們只是指向子項目的某次提交的鏈接,而 Git 子樹保存了整個子項目及其提交歷史。
- Git 子模塊需要在伺服器中可訪問,但子樹是去中心化的。
- Git 子模塊大量用於基於組件的開發,而 Git 子樹多用於基於系統的開發。
Git 子樹並不是 Git 子模塊的直接可替代項。有明確的說明來指導我們該使用哪種。如果有一個歸屬於你的外部存儲庫,使用場景是向它回推代碼,那麼就使用 Git 子模塊,因為推送代碼更容易。如果你有第三方代碼,且不會向它推送代碼,那麼使用 Git 子樹,因為拉取代碼更容易。
自己嘗試使用 Git 子樹和子模塊,然後在評論中留下你的使用感想。
via: https://opensource.com/article/20/5/git-submodules-subtrees
作者:Manaswini Das 選題:lujun9972 譯者:lxbwolf 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive