在這篇文章中脑豹,我們來講解一下 git submodule
的實戰(zhàn)用法,包括:
- 注冊 git 子模塊
- 從已有的文件創(chuàng)建 git 子模塊
- 向上同步主倉庫
- 向下同步子模塊倉庫
- 疑難雜癥
注冊 git
子模塊
假設(shè)我們有主倉庫main-module.git
钥勋,遠程地址 https://github.com/bitmingw/main-module.git,目錄結(jié)構(gòu)
.
└── main.txt
以及倉庫 sub-module.git
,遠程地址 https://github.com/bitmingw/sub-module.git法瑟,目錄結(jié)構(gòu)
.
└── sub.txt
如果想要將倉庫sub-module.git
注冊成為主倉庫main-module.git
的一個子模塊秽浇,可以使用如下指令:
main-module/
git submodule add https://github.com/bitmingw/sub-module.git
git commit -m "add submodule version 1.0"
git
會自動從遠程服務(wù)器 clone sub-module.git
浮庐,之后 main-module.git
的目錄會變成這個樣子
.
├── main.txt
└── sub-module
└── sub.txt
由于添加git
子模塊的操作本身也是一個提交,因此它僅僅對main-module.git
的當(dāng)前分支有效柬焕,另外的分支不會感知到這一變化审残。
從已有的文件創(chuàng)建 git 子模塊
大多數(shù)時候,git 子模塊
不是憑空創(chuàng)建的斑举,而是從項目中已有的文件拆分出來的搅轿。從已有的文件創(chuàng)建git 子模塊
需要做三件事:首先為拆分出來的文件創(chuàng)建新的 git 倉庫
,然后從主倉庫中將獨立出去的文件移除富玷,最后再注冊git 子模塊
例如璧坟,假設(shè)main-module.git
的目錄結(jié)構(gòu)如下所示
.
├── main.txt
└── sub-module
└── sub.txt
它有v1.0
和 v2.0
兩個分支,在 v2.0
分支中赎懦,我們想讓 sub-module
文件夾變成sub-module.git
子模塊雀鹃。
,為
sub-module
創(chuàng)建一個單獨的 git
倉庫:
git checkout v2.0
cd sub-module
git init
git add sub.txt
git commit -m "version 1.0 of sub-module"
git remote add origin https://github.com/bitmingw/sub-module.git
git push -u origin master
励两,從
main-module.git
中刪除 sub-module
文件夾:
cd .. # main-module/
git rm -r sub-module
git commit -m "remove sub-module directory"
黎茎,將
sub-module.git
注冊為main-module.git
的子模塊
main-module/
git submodule add https://github.com/bitmingw/sub-module.git
git commit -m "add submodule version 1.0"
向下同步子模塊倉庫
如果你是主倉庫的開發(fā)者,你可能不想使用最新版本的子模塊当悔,而是使用主倉庫中指定版本的子模塊傅瞻,此時可以使用下面的指令:
git submodule update
在使用該指令前,主倉庫和子模塊的git status
分別是:
~/main-module$ git status
On branch v2.0
Your branch is up-to-date with 'origin/v2.0'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: sub-module (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
========
~/main-module/sub-module$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
使用了git submodule update
之后盲憎,兩個倉庫的 git status
信息變成了這個樣子:
~/main-module$ git status
On branch v2.0
Your branch is up-to-date with 'origin/v2.0'.
nothing to commit, working directory clean
========
~/main-module/sub-module$ git status
HEAD detached at 359bce6
nothing to commit, working directory clean
這樣嗅骄,主倉庫的開發(fā)者就可以從一個干凈的空間開始工作了。
疑難雜癥
還記得我們是從v2.0
分支引入子模塊的么焙畔?假如現(xiàn)在要查看v1.0
分支掸读,會發(fā)生什么呢?
還記得我們是從 v2.0 分支引入子模塊的么?假如現(xiàn)在要查看 v1.0 分支儿惫,會發(fā)生什么呢澡罚?
~/main-module$ git checkout v1.0
error: The following untracked working tree files would be overwritten by checkout:
sub-module/sub.txt
Please move or remove them before you can switch branches.
Aborting
難道有了子模塊之后我們就回不去了?肾请?情況沒有那么糟糕留搔,我們可以通過 git checkout -f v1.0
強行回去。
~/main-module$ git checkout -f v1.0
warning: unable to rmdir sub-module: Directory not empty
Switched to branch 'v1.0'
Your branch is up-to-date with 'origin/v1.0'.
不過這個時候要注意铛铁,由于sub-module
沒有被移除隔显,因此切換到 v1.0 分支
以后,你看到的sub-module
文件夾依然是個子模塊饵逐。也就是說括眠,子模塊穿越了時空來到了v1.0 分支
…… 嗯這個行為似乎不是我們期望的那個樣子。
如果你真的想回到v1.0 分支
的非子模塊的 sub-module
倍权,那你不得不在切換分支前把這個子模塊卸載掉:
git rm -r sub-module
git commit -m "remove submodule"
git checkout v1.0
如果你想從v1.0 分支
回到v2.0
掷豺,也會遇到一些問題。
~/main-module$ git checkout v2.0
M sub-module
Switched to branch 'v2.0'
Your branch is up-to-date with 'origin/v2.0'.
~/main-module$ git status
On branch v2.0
Your branch is up-to-date with 'origin/v2.0'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
(commit or discard the untracked or modified content in submodules)
modified: sub-module (modified content)
no changes added to commit (use "git add" and/or "git commit -a")
經(jīng)過了git checkout -f v1.0
和git checkout v2.0
之后薄声,子模塊的文件竟然被 git
刪掉了挺据。而且這個時候無論是 git submodule update
還是 git checkout -- sub-module
都不好使了搁拙。到底應(yīng)該怎么辦呢?
答案是在子模塊內(nèi)部使用 git reset
。
~/main-module/sub-module$ git reset --hard HEAD
HEAD is now at 359bce6 version 1.0 of sub-module
~/main-module/sub-module$ git status
HEAD detached at 359bce6
nothing to commit, working directory clean
從這一部分的演示可以看出悔据,git submodule
的設(shè)計對從已有文件拆分出來的子模塊來說是非常糟糕的窿凤∏Ч幔或許這會成為大家盡量避免使用git 子模塊
的原因之一吧孕似。