Git Submodule 使用

himg

git 的 submodule 作為一個獨立的 repo, 其擁有普通 repo 全部的功能, 我們可以完全按照普通的 repo 管理命令來進入 submodule 中進行手動管理. 不過如果存在多個 submodule 位于同一 superproject 下時, 掌握一些 git submodule ... 命令就變得尤為重要了.

本文列出了常用的一些 git submodule 管理命令, 并舉出實際應用中遇到的問題及解決方案.

submodule 介紹

在 git 倉庫 superproject 的目錄中使用 git submodule add https://github/HanleyLee/C 即可將 https://github/HanleyLee/C 作為一個 submodulesuperproject 依賴與管理.

submodule 被修改時我們可以在 superproject 中得到通知:

  • submodule 中添加了新文件:

    himg
  • 修改了 submodule 中的內(nèi)容 (沒有 new commit):

    himg
  • 在 submodule 中產(chǎn)生了 new commit:

    himg

submodule 特點

repo Test 作為 submodulesuperproject 管理后:

  • 我們?nèi)匀豢梢赃M入 repo Test 的目錄中對相關內(nèi)容進行修改, 然后通過常用的 git 命令進行操作.
  • superproject 下可以通過 git submodule *** 命令來管理其下的所有子倉庫, 使其與遠程庫保持同步或推送到遠程庫.

submodule 的版本如何被管理的 (大致思路)

添加 git submodule 的方法很簡單, 使用 git submodule add <repo url> 即可. 添加完之后, 在 superproject 的目錄下會產(chǎn)生一個 .gitmodule 文件, 文件的結(jié)構(gòu)如下:

[submodule "C"]
    path = C
    url = git@github.com:HanleyLee/C.git
[submodule "Cpp"]
    path = Cpp
    url = git@github.com:HanleyLee/Cpp.git

可以看到, .gitmodule 文件中標記了每一個 submodulepathurl.

然后我們進入 ./C:

$ cd ./C
$ ls -l
$ ls -lhia

    35107110 drwxr-xr-x   9 hanley  staff   288B May  7 21:15 .
    35107043 drwxr-xr-x  14 hanley  staff   448B May  7 20:45 ..
    35107127 -rw-r--r--   1 hanley  staff    26B May  7 19:59 .git

$ cat .git

    gitdir: ../.git/modules/C

我們發(fā)現(xiàn) ./C/.git 竟然是一個文件 (常規(guī) git 目錄中的 .git 是文件夾), 然后其內(nèi)容指向了另一個文件夾 (類似于指針), 我們再去到那個文件夾:

$ cd ../git/modules/C
$ ls -lhia

    35107128 drwxr-xr-x  16 hanley  staff   512B May  7 21:17 .
    35107126 drwxr-xr-x   9 hanley  staff   288B May  7 19:59 ..
    35112722 -rw-r--r--   1 hanley  staff    17B May  7 21:17 COMMIT_EDITMSG
    35109064 -rw-r--r--   1 hanley  staff     0B May  7 21:44 FETCH_HEAD
    35109063 -rw-r--r--   1 hanley  staff    16B May  7 21:44 FETCH_LOG
    35112529 -rw-r--r--   1 hanley  staff    21B May  7 20:25 HEAD
    35116056 -rw-r--r--   1 hanley  staff    41B May  7 21:15 ORIG_HEAD
    35114647 -rw-r--r--   1 hanley  staff   319B May  7 20:47 config
    35107131 -rw-r--r--   1 hanley  staff    73B May  7 19:59 description
    35107132 drwxr-xr-x  15 hanley  staff   480B May  7 19:59 hooks
    35116224 -rw-r--r--   1 hanley  staff   1.7K May  7 21:17 index
    35107129 drwxr-xr-x   3 hanley  staff    96B May  7 19:59 info
    35107178 drwxr-xr-x   4 hanley  staff   128B May  7 19:59 logs
    35107159 drwxr-xr-x   9 hanley  staff   288B May  7 21:40 objects
    35107174 -rw-r--r--   1 hanley  staff   112B May  7 19:59 packed-refs
    35107146 drwxr-xr-x   5 hanley  staff   160B May  7 19:59 refs

我們發(fā)現(xiàn)這個文件夾才是 submodule 的真實 .git 文件夾, 我們對于 submodule 的所做的 commit 信息也都保存在這里.

submodule 常用命令

  • git submodule: 顯示所有 submodule, 等同于git submodule status

  • 添加 submodule 到現(xiàn)有項目

    1. Run git submodule add -b <branch> --name <name> <repo-url> <local dir>
    2. Commit both files on the superproject
  • 從當前項目移除 submodule

    1. git submodule deinit -f <submodule_path>
    2. rm -rf .git/modules/<submodule_path>
    3. git rm -f <submodule_path>
  • 復制含 submodule 項目到本地

    1. Clone the superproject as usual
    2. Run git submodule init to init the submodules
    3. Run git submodule update to have the submodules on a detached HEAD

    或者直接執(zhí)行 git clone --recurse-submodules <repo-url>

  • git submodule init: 將本項目所依賴的 submodule 進行初始化

  • git submodule update: 將本項目所依賴的 submodule 更新到本地最新版本

  • git submodule update --init: 前面兩個命令的合并

  • git submodule update --init --recursive: 前面三個命令的合集, --recursive 是為了保證即使 submodule 又嵌套了 sub-submodule, 也可以被執(zhí)行到. 這個命令比較全面, 會經(jīng)常使用

  • git submodule update: 更新 submodule 為 superproject 本次 commit 所記錄的版本 (本地版本為舊版本的話那么就與舊版本保持同步!)

  • git submodule update --remote: 更新 submodule 為遠程項目的最新版本 (更為常用!)

  • git submodule update --remote <submodule-name>: 更新指定的 submodule 為遠程的最新版本

  • git push --recurse-submodules=

    • check: 檢查 submodule 是否有提交未推送, 如果有, 則使本次提交失敗
    • on-demand: 先推送 submodule 的更新, 然后推送主項目的更新(如果 submodule 推送失敗, 那么推送任務直接終止)
    • while: 所有的 submodule 會被依次推送到遠端, 但是 superproject 將不會被推送
    • no: 與 while 相反, 只推送 superproject, 不推送其他 submodule
  • git pull --recurse-submodules: 拉取所有子倉庫 (fetch) 并 merge 到所跟蹤的分支上

  • git diff --submodule: 查看 submodule 所有改變

  • git submodule foreach '<arbitrary-command-to-run>': 對所有 submodule 執(zhí)行命令, 非常有用, 如 git submodule foreach 'git checkout main'

為什么 superprojectgit pull 之后 submodule 沒有切到最新節(jié)點?

默認情況下, git pull 命令會遞歸地抓取子模塊的更改 (fetch), 然而, 它不會將 submodule merge 到所跟蹤的分支上. 因此我們還需要執(zhí)行 git submodule update.

如果我們想一句話解決, 那么可以使用 git pull --recurse-submodule, 這個可以在拉取完 submodule 后再將其 merge 到所跟蹤的分支上.

如果我們想讓 Git 總是以 --recurse-submodules 拉取, 可以將配置選項 submodule.recurse 設置為 true. 具體命令為 git config --global submodule.recurse true. 此選項會讓 Git 為所有支持 --recurse-submodules 的命令使用該選項 (除 clone 以外).

git pull --recurse-submodule 會讓我們的pull命令遞歸地用于所有 submodule, 如果你的 submodule 數(shù)量過多的話可能會等較長時間. 這時可以使用 git pull && git submodule update --init --recursive 一句話命令來只拉取更新了的 submodule 并更新到最新 commit, 使用 git config --global alias.sdiff '!'"git diff && git submodule foreach 'git diff'" 為此命令設置 alias

submodule 沒有提交commit的情況下推送 superprojectcommit

如果我們在主項目中提交并推送但并不推送子模塊上的改動, 其他嘗試檢出我們修改的人會遇到麻煩, 因為他們無法得到依賴的子模塊改動. 那些改動只存在于我們本地的拷貝中.

為了確保這不會發(fā)生, 我們可以讓 Git 在推送到主項目前檢查所有 submodule 是否已推送. git push 命令接受可以設置為 checkon-demand--recurse-submodules 參數(shù). 如果任何提交的 submodule 改動沒有推送那么 check 選項會直接使 push 操作失敗.(此外還有 demand, while, no 選項, 參考前節(jié)命令列表進行理解)

為了以后方便, 我們可以設置默認檢查 git config --global push.recurseSubmodules check

為什么每次 update 后 submodule 的 HEAD 狀態(tài)變?yōu)榱?detached?

很多人用了 git submodule 后, 都發(fā)現(xiàn)每次 update 之后, submodule 中的 HEAD 都是 detached 狀態(tài)的, 即使本次 git checkout master 后, 下次更新仍然恢復原樣, 難道就沒有辦法使其固定在某個 branch 上嗎? 經(jīng)過研究, 參考 stackoverflow 的答案, 我發(fā)現(xiàn)是可以解決的.

問題的關鍵在于 .gitmodule 的配置:

[submodule "C"]
    path = C
    url = git@github.com:HanleyLee/C.git
    update = rebase
[submodule "Cpp"]
    path = Cpp
    url = git@github.com:HanleyLee/Cpp.git
    update = rebase

我們需要添加 update = rebase 這行, 根據(jù) git official 的說明

checkout
    the commit recorded in the superproject will be checked out in the submodule on a detached HEAD.

    If --force is specified, the submodule will be checked out (using git checkout --force), even if the commit specified in the index of the containing repository already matches the commit checked out in the submodule.

rebase
    the current branch of the submodule will be rebased onto the commit recorded in the superproject.

merge
    the commit recorded in the superproject will be merged into the current branch in the submodule.

submodule 的 update 有多種選擇, 默認情況下是 checkout, 其會根據(jù) superproject 所記錄的 submodulecommit 進行 checkout. 類似于 git checkout 4eda5fgrd, 這必然導致 submoduleHEAD 處于 detached 狀態(tài). 解決辦法就是使用 rebase(merge 也可以), 這樣當我們對 submodule 設置了一個初始的 branch 后, 其以后都只會在這個 branch 上對遠程的最新 commit 進行 rebase, 不會導致 detached 狀態(tài)的產(chǎn)生.

submodule 的目錄為 ./C/ 為例. 具體的解決步驟如下:

$ cd C/
$ git checkout main
$ cd ..
$ git config -f .gitmodules submodule.C.update rebase

此時, 以后再使用 git submodule update 就不會有 detached 狀態(tài)的產(chǎn)生了

另外, 在 .gitmodule 文件中也可以指定 branch, 這里指定的 branch 表示跟蹤的遠程倉庫的分支, 如果不指定, 則默認為跟蹤遠程的 HEAD 所指向的 branch

參考

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衣迷,一起剝皮案震驚了整個濱河市狰晚,隨后出現(xiàn)的幾起案子然评,更是在濱河造成了極大的恐慌茬高,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坐求,居然都是意外死亡趴荸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門中跌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咨堤,“玉大人,你說我怎么就攤上這事漩符∫淮” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凸克。 經(jīng)常有香客問我议蟆,道長,這世上最難降的妖魔是什么萎战? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任咐容,我火速辦了婚禮,結(jié)果婚禮上蚂维,老公的妹妹穿的比我還像新娘戳粒。我一直安慰自己,他們只是感情好虫啥,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布蔚约。 她就那樣靜靜地躺著,像睡著了一般涂籽。 火紅的嫁衣襯著肌膚如雪苹祟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天评雌,我揣著相機與錄音苔咪,去河邊找鬼。 笑死柳骄,一個胖子當著我的面吹牛团赏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耐薯,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼舔清,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了曲初?” 一聲冷哼從身側(cè)響起体谒,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎臼婆,沒想到半個月后抒痒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡颁褂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年故响,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颁独。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡彩届,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出誓酒,到底是詐尸還是另有隱情樟蠕,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站寨辩,受9級特大地震影響吓懈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜靡狞,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一耻警、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耍攘,春花似錦、人聲如沸畔勤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庆揪。三九已至式曲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缸榛,已是汗流浹背吝羞。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留内颗,地道東北人钧排。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像均澳,于是被迫代替她去往敵國和親恨溜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容