問題背景
隨著公司業(yè)務(wù)線的增加,不同的業(yè)務(wù)線不可避免的有些相似,甚至相同的邏輯,比如營銷方略下有營銷概覽,數(shù)據(jù)中心下也有一個(gè)同樣的營銷概覽模塊,以后可能直投下也會(huì)添加一個(gè)類似的模塊。它們的數(shù)據(jù)來源是相同的,交互也是大同小異。每個(gè)業(yè)務(wù)線都copy一遍代碼,造成了大量的代碼冗余,且后續(xù)修改也要挨個(gè)進(jìn)行一遍,所以這顯然不是一個(gè)好辦法。
本文要介紹的git子模塊,就是解決這個(gè)問題的一個(gè)方案,希望能夠拋磚引玉。
git子模塊定義
子模塊允許你將一個(gè)Git倉庫作為另一個(gè)Git倉庫的子目錄。
它能讓你將另一個(gè)倉庫克隆到自己的項(xiàng)目中,同時(shí)還保持提交的獨(dú)立。
子模塊適用于主項(xiàng)目對(duì)子模塊有依賴關(guān)系,卻又并不關(guān)心子模塊的內(nèi)部開發(fā)的流程和細(xì)節(jié);適用于整體復(fù)用的情況;
比如我上面描述的問題背景,就是典型的案例,營銷方略主模塊不關(guān)心營銷概覽子模塊的實(shí)現(xiàn),流程只要和數(shù)據(jù)中心保持一致即可;
下面以這個(gè)需求為例,分別簡單介紹一下submodule和subtree的使用;
已知,子模塊的項(xiàng)目地址是:https://xxx.com/ads-fe/marketing-overview-submodule.git
使用子模塊的主項(xiàng)目是:https://xxx.com/ads-fe/jzt-strategy.git
git submodule
首先介紹一下submodule的使用。
添加子模塊
進(jìn)入主項(xiàng)目所在目錄,添加子模塊到指定目錄下:
//語法: git submodule add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
git submodule add https://xxx.com/ads-fe/marketing-overview-submodule.git src/Overview
執(zhí)行完添加后,頁面會(huì)多出2個(gè)子目錄,如圖所示:

除了這2處外,.git目錄下也有變化,用于記錄子模塊的變更記錄:

協(xié)同開發(fā)的問題
當(dāng)有協(xié)同人員開發(fā)人員同一項(xiàng)目時(shí)需要拉取代碼:
git clone https://xxx.com/ads-fe/jzt-strategy.git

注意:此時(shí)目錄是空的,需要執(zhí)行以下代碼:
git submodule init
git submodule update
子模塊拉取最新代碼
git submodule update --remote src/Overview
//更新多個(gè)子模塊
git submodule foreach 'git pull origin master'
刪除子模塊
當(dāng)需求變動(dòng)或者添加錯(cuò)誤的時(shí)候,需要?jiǎng)h除子模塊:
git submodule deinit -f src/Overview
上述命令刪除的只是src/Overviews下的文件,此時(shí),這些文件仍然存在,需要?jiǎng)h除.git/module/src/Overview下的內(nèi)容和修改.gitmodules

git subtree
使用subtree,同樣可以實(shí)現(xiàn)在一個(gè)項(xiàng)目中引用其他項(xiàng)目的數(shù)據(jù);但是和submodule方式不同的是,使用subtree外部的版本庫會(huì)作為一個(gè)目錄被整個(gè)復(fù)制到本版本庫中,并且復(fù)制到本版本庫中的子目錄下的數(shù)據(jù)可以和原版本庫數(shù)據(jù)建立跟蹤關(guān)聯(lián)。
添加子模塊
使用下面的代碼把子倉庫的地址作為一個(gè)remote,方便記憶;
git remote add MarketingOverview https://xxx.com/ads-fe/marketing-overview-submodule.git
此時(shí),git config文件會(huì)多出一條記錄:
[remote "MarketingOverview"]
url = https://xxx.com/ads-fe/marketing-overview-submodule.git
fetch = +refs/heads/*:refs/remotes/MarketingOverview/*
拉取子模塊代碼
進(jìn)入主項(xiàng)目所在目錄,執(zhí)行:
//語法:git subtree add --prefix=<prefix> <repository> <ref>
git subtree add --prefix=src/Overview MarketingOverview master –squash
添加之后的src/Overview就是主項(xiàng)目jzt-strategy的一個(gè)普通文件夾,如果這時(shí)候jzt-strategy內(nèi)容更新之后,正常git push即可,子項(xiàng)目對(duì)于主項(xiàng)目來說完全是透明的。
子模塊拉取最新代碼
git subtree pull --prefix=src/Overview MarketingOverview master --squash
刪除子模塊
刪除subtree,直接刪除子模塊所在的目錄即可,沒有殘留文件需要單獨(dú)清理;
git rm -rf src/Overview/
補(bǔ)充
上面介紹了2種子模塊的增加和刪除功能,但是沒有介紹修改后的操作,主要是我認(rèn)為這里的使用場景是多業(yè)務(wù)線完整復(fù)用的場景,如果差異過多,需要自己單獨(dú)的模塊,就失去了復(fù)用的意義了。當(dāng)然這并不代表修改功能不能使用,感興趣的小伙伴可以去了解一下,這里就不贅述了。
submodule vs subtree
subtree優(yōu)點(diǎn):
- subtree相比submodule操作更簡單;無論添加還是刪除,都少了很多步驟;
- 不增加任何像.gitmodule這樣的新的元數(shù)據(jù)文件;
- git subtree對(duì)于項(xiàng)目中的其他成員透明,意味著可以不知道git subtree的存在
submodule優(yōu)點(diǎn):
- git submodule在本地可以存在多個(gè)git代碼倉庫
- git subtree只有一個(gè)代碼庫,也就是說在項(xiàng)目內(nèi)部依賴外部獨(dú)立項(xiàng)目的時(shí)候,是完全無感知的操作。
子模塊存在的問題
有些組件,方法或者常量定義,可能另一個(gè)子模塊也在使用,
比如ajax請(qǐng)求,本著盡量少配置和少依賴的原則,子模塊一般會(huì)有自己封裝的ajax方法,因?yàn)榇藭r(shí)不能默認(rèn)主項(xiàng)目也一定有ajax請(qǐng)求,如果引用多個(gè)子模塊,
每個(gè)模塊都有自己的ajax方法,這就造成了一定程度的代碼冗余;
考慮方案:
- 提取公共組件
- 常量及公共方法,可以單獨(dú)發(fā)布一個(gè)工具包引入
- 常量及公共方法再作為一個(gè)子模塊引入
總結(jié)
大家可以根據(jù)實(shí)際情況進(jìn)行選擇使用,如果只是依賴一個(gè)模塊,subtree可能更簡單一些,如果主項(xiàng)目依賴多個(gè)子項(xiàng)目,submodule才是最好的選擇。
參考:https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97