Git submodule - Git子模塊簡介

目錄

  1. 建立倉庫
    1.1 創建主倉庫
    1.2 創建子倉庫
  2. 提交內容
    2.1 提交到主工程的倉庫
    2.2 提交到子模塊的倉庫
  3. 克隆帶子模塊的倉庫到本地
  4. 更新子倉庫
  5. 總結
  6. 參考文檔

正文

軟件開發中有一個DRY(Don’t Repeat yourself)原則,或者說DIE(Duplication Is Evil)原則,指的是儘可能減少一切重複工作,重用一切可能重用的東西,小到提取重複性代碼,大到重用一個模塊。時間就是金錢,效率就是生命。
使用Git管理項目的時候,如果涉及到模塊重用,比如你需要用到別的倉庫提供的功能,雖然你可以直接把別人倉庫(當然也可以是自己的倉庫)的代碼複製到你的工程目錄下,但是這樣當別的倉庫更新了,我們也想相應的更新我們所依賴的代碼,或者我們對依賴的代碼做了些更改想要合併到原倉庫,這時候事情就比較麻煩了。所以,我們希望主模塊和子模塊的的管理是分開的,也就是主模塊的更改、提交等,是不涉及子模塊的,反過來子模塊也一樣。但是又希望他們之間有一個依賴關係,怎麼辦呢?
Git爲了這種困境提供了一個解決方案:子模塊(submodule)。
爲了便於理解,我們把當前工作工程倉庫成爲主倉庫,主倉庫所依賴的子模塊倉庫成爲子倉庫。

建立倉庫

創建主倉庫

mkdir demo && cd demo && git init

創建子倉庫

創建子倉庫用到的命令是git submodule add <repo> [<path>]。其中repo是你要添加爲子模塊的倉庫URL,path是主工程下的一個路徑,就相當與你在主工程下創建的一個專門用於保存子倉庫代碼的文件夾,名字是任意的,只不過習慣上用third_party利於區分和理解。例如我們將pybind11添加爲子模塊,其相對路徑爲third_party/pybind11,我們可以使用以下命令:

git submodule add https://github.com/pybind/pybind11 third_party/pybind11

值得注意的是,pybind11這個目錄在在使用命令前是不能存在與third_party目錄之下的。並且,此命令執行完成以後,子倉庫的代碼就被拉取到third_party/pybind11之中了。

提交內容

主倉庫和子倉庫之間,除了子倉庫位於主倉庫內,主倉庫對子倉庫的代碼有所依賴以外,他們之間是沒有其他任何聯繫的。他們呢就相當於兩個倉庫,主倉庫不會跟蹤子倉庫內容的變化,反過來子倉庫也不去跟蹤子倉庫的任何信息。就類似古代周邊某些附屬小國,雖然名面上朝貢、附屬,但實際上小國的治理和天朝是分開的。

提交到主工程的倉庫

對主工程內容的提交操作,與一般無子工程的倉庫操作並無二致。

提交到子模塊的倉庫

如果有需要對子模塊的內容進行修改並提交到其倉庫,可以進入到子模塊倉庫所在目錄,再進行相應的操作。例如,我們使用cd third_party/pybind11進入到子模塊倉庫,這時候我們可以使用git add, git commit等對更改進行操作,這些操作之對子模塊倉庫產生影響。

克隆帶子模塊的倉庫到本地

當我們需要克隆一個帶子倉庫的倉庫時,我們希望子倉庫的內容也是跟主倉庫一起保存在本地的。當使用git clone xxxx.git將主倉庫克隆到本地後,子倉庫所在目錄只有一個空目錄,子倉庫內容其實併爲下載到本地。有兩種方法:

  1. 在克隆主倉庫時加上--recurse-submodules,使用這種方法,子倉庫內容也會同時下載下來,如果子倉庫還包含子倉庫,也會被同時下載下來。
git clone xxxx.git --recurse-submodules
  1. 第二種方法是使用下面兩條命令:
git submodule init
git submodule update

值得注意的是,不管使用以上那兩種方法,子倉庫的內容雖然下載下來了,但是此時子倉庫的狀態是處於一種HEAD detached的狀態,也就是此時,你對子倉庫的更改,就算你已經commit但是當你下次使用git submodule update你所作的更改也會丟失。所以,你學要checkout`到一個工作分支,例如:

git checkout master

更新子倉庫

更新子倉庫內容有兩種方法,一種是進入到子倉庫所在目錄,進行常規的拉取和合並操作;

cd ./third_party/pybind11 
git fecth 
git merge

另一種是使用git submodule update --remote

git submodule update --remote 
git submodule update --remote <submodule ame>

兩條命令的區別是,如果不帶子倉庫名,默認會更新所有子倉庫,如果只想更新其中某個,需要指定需要更新的子倉庫名。

總結

對於帶子倉庫的倉庫,有兩種情況:

  1. 本地新建倉庫,需要建立與遠程子倉庫的依賴關係;
  2. 克隆已有帶子倉庫的倉庫到本地。
    第一種情況:
git submodule add <repo> [<path>]

第二種情況:

git submodule init [<path>]
git submodule update
git checkout <branch>

至此,依賴關係建立起來了,兩個倉庫之間便可以獨自操作。
可以使用git add, git commit, git status等各自操作。一句話,說的底盤聽水的:在主倉庫目錄下,操作的是主倉庫內容;cd third_party/sumdir進入到子倉庫,操作的便是子倉庫內容。

References

  1. Git-Tools-Submodules
  2. Manual: man git submodule

本文首發於個人公衆號TensorBoy。如果你覺得內容還不錯,歡迎分享並關注我的公衆號TensorBoy,掃描下方二維碼獲取更多精彩原創內容!
公衆號二維碼

發佈了26 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章