問(wèn)題背景
隨著公司業(yè)務(wù)線的增加,不同的業(yè)務(wù)線不可避免的有些相似,甚至相同的邏輯,比如營(yíng)銷(xiāo)方略下有營(yíng)銷(xiāo)概覽,數(shù)據(jù)中心下也有一個(gè)同樣的營(yíng)銷(xiāo)概覽模塊,以后可能直投下也會(huì)添加一個(gè)類(lèi)似的模塊。它們的數(shù)據(jù)來(lái)源是相同的,交互也是大同小異。每個(gè)業(yè)務(wù)線都copy一遍代碼,造成了大量的代碼冗余,且后續(xù)修改也要挨個(gè)進(jìn)行一遍,所以這顯然不是一個(gè)好辦法。
本文要介紹的git子模塊,就是解決這個(gè)問(wèn)題的一個(gè)方案,希望能夠拋磚引玉。
git子模塊定義
子模塊允許你將一個(gè)Git倉(cāng)庫(kù)作為另一個(gè)Git倉(cāng)庫(kù)的子目錄。
它能讓你將另一個(gè)倉(cāng)庫(kù)克隆到自己的項(xiàng)目中,同時(shí)還保持提交的獨(dú)立。
子模塊適用于主項(xiàng)目對(duì)子模塊有依賴關(guān)系,卻又并不關(guān)心子模塊的內(nèi)部開(kāi)發(fā)的流程和細(xì)節(jié);適用于整體復(fù)用的情況;
比如我上面描述的問(wèn)題背景,就是典型的案例,營(yíng)銷(xiāo)方略主模塊不關(guān)心營(yíng)銷(xiāo)概覽子模塊的實(shí)現(xiàn),流程只要和數(shù)據(jù)中心保持一致即可;
下面以這個(gè)需求為例,分別簡(jiǎn)單介紹一下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)目所在目錄,添加子模塊到指定目錄下:
//語(yǔ)法: 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í)行完添加后,頁(yè)面會(huì)多出2個(gè)子目錄,如圖所示:
除了這2處外,.git目錄下也有變化,用于記錄子模塊的變更記錄:
協(xié)同開(kāi)發(fā)的問(wèn)題
當(dāng)有協(xié)同人員開(kāi)發(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外部的版本庫(kù)會(huì)作為一個(gè)目錄被整個(gè)復(fù)制到本版本庫(kù)中,并且復(fù)制到本版本庫(kù)中的子目錄下的數(shù)據(jù)可以和原版本庫(kù)數(shù)據(jù)建立跟蹤關(guān)聯(lián)。
添加子模塊
使用下面的代碼把子倉(cāng)庫(kù)的地址作為一個(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í)行:
//語(yǔ)法: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)目來(lái)說(shuō)完全是透明的。
子模塊拉取最新代碼
git subtree pull --prefix=src/Overview MarketingOverview master --squash
刪除子模塊
刪除subtree,直接刪除子模塊所在的目錄即可,沒(méi)有殘留文件需要單獨(dú)清理;
git rm -rf src/Overview/
補(bǔ)充
上面介紹了2種子模塊的增加和刪除功能,但是沒(méi)有介紹修改后的操作,主要是我認(rèn)為這里的使用場(chǎng)景是多業(yè)務(wù)線完整復(fù)用的場(chǎng)景,如果差異過(guò)多,需要自己?jiǎn)为?dú)的模塊,就失去了復(fù)用的意義了。當(dāng)然這并不代表修改功能不能使用,感興趣的小伙伴可以去了解一下,這里就不贅述了。
submodule vs subtree
subtree優(yōu)點(diǎn):
- subtree相比submodule操作更簡(jiǎn)單;無(wú)論添加還是刪除,都少了很多步驟;
- 不增加任何像.gitmodule這樣的新的元數(shù)據(jù)文件;
- git subtree對(duì)于項(xiàng)目中的其他成員透明,意味著可以不知道git subtree的存在
submodule優(yōu)點(diǎn):
- git submodule在本地可以存在多個(gè)git代碼倉(cāng)庫(kù)
- git subtree只有一個(gè)代碼庫(kù),也就是說(shuō)在項(xiàng)目?jī)?nèi)部依賴外部獨(dú)立項(xiàng)目的時(shí)候,是完全無(wú)感知的操作。
子模塊存在的問(wèn)題
有些組件,方法或者常量定義,可能另一個(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可能更簡(jiǎn)單一些,如果主項(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