一. 為什么要使用submodule?
面對(duì)比較復(fù)雜的項(xiàng)目葫录,我們有可能會(huì)將代碼根據(jù)功能拆解成不同的子模塊挺邀。主項(xiàng)目對(duì)子模塊有依賴關(guān)系蝠嘉,卻又并不關(guān)心子模塊的內(nèi)部開(kāi)發(fā)流程細(xì)節(jié)。這種情況下荚守,可以使用git 的submodule來(lái)建立當(dāng)前項(xiàng)目和子項(xiàng)目的依賴關(guān)系珍德。
二. submodule的操作
2.1 submodule的創(chuàng)建
通過(guò) git submodule add <submodule_url> 可以創(chuàng)建一個(gè)submodule,也可以通過(guò)其他git圖形化工具便捷創(chuàng)建矗漾。
創(chuàng)建成功后锈候,會(huì)多出一個(gè)包含了子模塊的相關(guān)信息的.gitmodules 文件,同時(shí)會(huì)把子模塊下載到當(dāng)前目錄中缩功。
2.2 submodule的拉取
有三種方式更新項(xiàng)目?jī)?nèi)的submodule:
- 主項(xiàng)目的 fetch 晴及,pull 操作不會(huì)更新到子模塊,所以我們可以在這些操作后面加上 --recurse-submodules嫡锌, 這樣就可以同步到子模塊。
- 當(dāng)然最簡(jiǎn)單的還是切到子模塊的目錄下琳钉,通過(guò)正常的拉取操作就ok势木。
- 在主項(xiàng)目中直接通過(guò) git submodule update 來(lái)更新子模塊的代碼。
2.3 submodule 的提交
最好直接到子模塊的目錄下歌懒,按照正常的git操作對(duì)子模塊進(jìn)行正常的提交流程啦桌。
三. 重頭戲:submodule的坑
3.1 submodule游離態(tài)分支下的提交丟失
如果主工程中進(jìn)行git submodule update操作 ,會(huì)把子模塊的當(dāng)前分支切換成游離態(tài) "Detached Head"及皂,而非任何已有的分支甫男!例如下圖中的分支名稱為游離態(tài)的的@72b2861 這種格式.
很多時(shí)候我們沒(méi)有切換過(guò)分支,會(huì)在沒(méi)注意的情況下把修改提交到了這個(gè)游離態(tài)分支上验烧。然后如果切了master(或者其他已有的)分支后板驳,這個(gè)游離態(tài)分支和本次的commit都消失不見(jiàn)了,特別是用的圖形化git工具(如github客戶端碍拆,sourcetree等)若治,沒(méi)法找到這個(gè)游離態(tài)分支了。
這個(gè)時(shí)候可能大家有點(diǎn)慌了感混,我的提交怎么被遁入虛空了端幼?我一天的心血白費(fèi)了?
但是你先別慌弧满,要相信git的強(qiáng)大和可靠性婆跑。我們既然提交了那么就一定有記錄,只要我們找到并且恢復(fù)就沒(méi)事庭呜。
解決方案1:
當(dāng)前分支如果還是游離態(tài)分支滑进,可以查看當(dāng)前提交的commit的change-id犀忱,然后到正常的分支上cherry-pick這個(gè)commit即可。具體操作如下:
- 用 git checkout master 將 HEAD 從游離狀態(tài)切換到 master 分支 , 這時(shí)候郊供,git 會(huì)報(bào) Warning 說(shuō)有一個(gè)提交沒(méi)有在 branch 上峡碉,記住這個(gè)提交的 change-id(假如 change-id 為 aaaa);
- 用 git cherry-pick aaaa 來(lái)將剛剛的提交作用在 master 分支上驮审;
- 用 git push 將更新提交到遠(yuǎn)程版本庫(kù)中鲫寄;
命令行操作記錄如下:
? ui_common git:(df697f9) git checkout master
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
df697f9 forget to check out master
If you want to keep them by creating a new branch, this may be a good time
to do so with:
git branch new_branch_name df697f911e5a0f09d883f8f360977e470c53d81e
Switched to branch 'master'
? ui_common git:(master) git cherry-pick df697f9
解決方案2:
如果使用圖形化git工具,有些在切換分支到其他分支時(shí)沒(méi)有方案1里面提示的warning(例如github客戶端)疯淫,所以切到其他分支后就不知道commit的change-id地来。
在這種情況下,我們只需要再回到游離態(tài)分支熙掺,然后查看提交的記錄就ok了未斑。
- 首先通過(guò)在主工程中進(jìn)行git submodule update操作,把當(dāng)前分支重置到游離態(tài)分支币绩;
- 使用git log 或圖形化工具查看commit列表蜡秽,找到丟失的commit,萬(wàn)事大吉缆镣!
- 萬(wàn)事大吉個(gè)屁芽突,我發(fā)現(xiàn)git log里面根本沒(méi)有我們丟失的commit記錄。我知道你很慌董瞻,但是先別慌寞蚌。因?yàn)槲抑纆it還有另外一個(gè)更詳盡的git操作記錄:git reflog,我們?cè)趓eflog中再找找钠糊。
- 果然我們?cè)趃it reflog中可以找到丟失的commit挟秤,在master分支中cherry-pick這個(gè)提交,萬(wàn)事大吉抄伍!
解決方案2的手把手圖形化工具教程
如果是git命令行老手艘刚,使用命令行工具可以很快處理submodule的commit丟失問(wèn)題。
但是如果是不會(huì)使用git命令行的新手逝慧,可以按照下面的流程昔脯,手把手教你恢復(fù)。下面是恢復(fù)流程:
安裝毫無(wú)爭(zhēng)議的世界第一的git工具:tortoisegit(小烏龜)笛臣,后面的流程是基于此工具的云稚。安裝流程略過(guò);
-
在主項(xiàng)目目錄中使用submodule update沈堡,可以再次把子模塊重置回游離態(tài)静陈。
image.png -
轉(zhuǎn)到子模塊的目錄,打開(kāi)RefLog彈窗。
image.png -
在RefLog目錄應(yīng)該可以看到自己提交的不見(jiàn)的commit了鲸拥!
image.png 到這里我們便知道了丟失的commit的change-id拐格,最方便的還是使用git命令行直接cherry-pick丟失的commit,然后后面的流程就可以忽略了刑赶,萬(wàn)事大吉捏浊!
但如果不會(huì)使用git命令行,就接著往下看吧撞叨。
因?yàn)閠ortoisegit工具的cherrypick功能只能從已有分支中選擇金踪,無(wú)法找到游離態(tài)的分支,所以我們可以通過(guò)創(chuàng)建一個(gè)分支的方法來(lái)曲線救國(guó)牵敷。-
右鍵這個(gè)commit胡岔,從丟失的commit創(chuàng)建一個(gè)分支TestA;
image.png -
切換到master分支,打開(kāi)Git Show Log.
image.png -
在git log界面把界面顯示的分支切到TestA枷餐,然后將丟失的commit cherry-pick到master分支就可以了靶瘸!
image.png 上傳前記得把臨時(shí)的TestA分支刪掉,萬(wàn)事大吉毛肋!