git subtree使用

背景

公司要做一個服務平臺,有12個領域,每個領域爲一個微服務,現在前端項目暫時拆分爲三個,分別爲SEO,content和forward,三個項目(以後會拆分更多的項目)的組件、插件、工具、狀態管理爲同一套。現狀複製三份一個項目放一份,這樣的弊端是一個公共組件修改要同時維護三份,另外不同項目新增不同的組件,隨着項目的增多組件的同步、維護成本會越來越大

需求分析

  • (組件、插件、工具)、狀態管理等公用代碼遷移出去分別建立front-common和front-store(nuxt對vuex進行了封裝,爲了儘量不改動原目錄結構)兩個git 倉庫,供其他項目共享代碼
  • 公用代碼原本是什麼樣,抽取後也是什麼樣
  • 公用代碼庫是可以在不同項目間雙向同步的而不是單向同步
  • 保留公用代碼庫的歷史提交記錄與雙向同步記錄
雙向同步例子:A項目中依賴了子項目B,在A項目裏改B子項目對應的目錄裏的代碼,然後測試通過後,
直接提交代碼,這個更改也提交到B子項目的 Git倉庫裏。
同時子項目B也可以單獨提交到 Git 倉庫,在A項目裏把子項目B的代碼直接更新。

現有方案


  • Git Submodule:這是Git官方以前的推薦方案
  • Git Subtree:從 Git 1.5.2 開始,Git 新增並推薦使用這個功能來管理子項目
  • npm:node package manager,實際上不僅僅是 node 的包管理工具
  • composer:暫且認爲他是php版npm

雖然 npm,composer,maven 等更側重於包的依賴管理,以上幾個方案都是能夠做到在不同項目中同步同一塊代碼的,但沒法雙向同步,更適用於子項目代碼比較穩定的情形。Git Submodule 和 Git Subtree 都是官方支持的功能,不具有依賴管理的功能,但能滿足我們的要求。Git Subtree相對來說會更好一些 。

submodule 與 subtree對比

  • git submodule
    • 允許其他的倉庫指定以一個commit嵌入倉庫的子目錄
    • 倉庫 clone下來需要 initupdate
    • 會產 .gitmodule 文件記錄 submodule 版本信息
    • git submodule 刪除起來比較費勁
  • git subtree
    • 避免以上問題
    • 管理和更新流程比較方便
    • git subtree合併子倉庫到項目中的子目錄。不用像submodule那樣每次子項目修改了後要initupdate 。萬一哪次沒update就直接add ..gitmodulecommit上去就悲劇了
    • git v1.5.2以後建議使用git subtree

拆分已有項目

需要從現有項目中抽取公共模塊單獨進行git管理首先進行技術預演(展示網址爲私有項目,自行替換自己的git倉庫地址)
假設原項目test-sub-tree下web目錄抽取項目store

  1. **進入項目目錄:**cd test-sub-tree

*ps:直接使用git subtree add 的命令會出現 prefix ‘’ already exists. 這樣的錯誤提示,這是因爲對應的目錄已經存在,
不能直接添加,需要把對應的目錄剝離開然後再加入subtree

2.剝離出store
git subtree split -P <store項目的相對路徑> -b <臨時branch>


Git 會遍歷所有的commit,分離出store相關的commit,並存入front-store分支中

3. 創建子repo

在git遠程創建front-store項目

退出項目目錄,在原項目front同級目錄創建文件夾,進入front-store目錄,把這個目錄變成Git可以管理的倉庫:
cd ../

mkdir front-store

cd front-store

git init

拉取test-sub-tree項目front-store分支

git pull <test-sub-tree項目的路徑> <臨時branch>

如果直接用git clone <git地址>來拉取子項目並生成文件夾(我的common項目使用這種方法),執行上述命令
可能會報fatal: refusing to merge unrelated histories錯誤。



解決辦法使用命令: git pull <test-sub-tree項目的路徑> <臨時branch> --allow-unrelated-histories

關聯front-store遠程倉庫,推送代碼到遠程
git remote add origin <front-store項目的git倉庫>
git push origin -u master

4. 清理數據
cd test-sub-tree項目的路徑
git rm -rf <test-sub-tree項目的store相對路徑>


git commit -m '移除store模塊' # 提交刪除申請


git branch -D <臨時branch> # 刪除臨時分支front-store

5. 添加subtree
git subtree add -P <store項目的相對路徑> <store項目git地址> <分支> --squash
git push

解釋:--squash意思是把subtree的改動合併成一次commit,這樣就不用拉取子項目完整的歷史記錄。
-P等於--prefix,之後的=等號可以用空格。

執行完第3步時,對應的目錄已經剝離出來形成獨立的項目了。
第3,4步主要是把當前項目的對應的文件給刪除,重新在test-sub-tree項目建立Subtree

項目間雙向同步

test-sub-tree項目和front-store正常我們可以進行正常的日常git提交和修改維護

git add .

git commit -m "xxx文件修改"

git pull

git push

兩個項目的代碼要進行雙向同步要執行下面的操作:


1. test-sub-tree項目修改store文件夾下的文件提交更改到front-store子項目
場景test-sub-tree項目刪除store文件夾下supply_item文件

現在通過命令:

git subtree push -P <front-store項目的相對路徑> <front-store項目git地址> <分支>

將“刪除supply_item文件”這個操作同步到front-store子項目的倉庫

進入front-store子項目文件夾,拉取遠程倉庫代碼,會看到front-store文件夾下supply_item文件被刪除

Git 會遍歷步驟2中所有的commit,從中找出針對S目錄的更改,然後把這些更改記錄提交到S項目的Git服務器上,
並保留步驟2中的相關S的提交記錄到S倉庫中

4. front-store子項目修改提交同步到test-sub-tree項目store文件夾下

場景front-store項目新增supply_item文件

現在通過命令:

git subtree pull --prefix=<front-store項目的相對路徑> <front-store項目git地址> <分支> --squash

front-store子項目的“新增supply_item文件”這個操作同步(拉取)到test-sub-tree項目

用git push將front-store子項目修改推送到test-sub-tree項目遠程倉庫

Tips:相對路徑區別大小寫
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章