Git - - subtree與submodule

1 - 倉庫共用(子倉庫、子項目)

兩種子倉庫使用方式

  • git submodule(子模塊)
  • git subtree(子樹合併)

從1.5.2版本開始,官方新增Git Subtree並推薦使用這個功能來替代Git Submodule管理倉庫共用(子倉庫、子項目)

2 - submodule 與 subtree 對比

2.1 git submodule

  • 可以將其他倉庫某個commit作爲倉庫的子目錄
  • 克隆倉庫需要額外的步驟 init 和 update
  • 產生.gitmodule文件記錄和submodule版本信息
  • 刪除submodule步驟繁瑣
  • 可以在子倉庫單獨查看子倉庫的修改記錄,相當與在一個單獨的倉庫內,對外層父倉庫不可見

2.2 git subtree

  • 官方推薦方式
  • 不增加.gitmodule等文件
  • 管理和更新流程簡潔,對於項目中的其他成員透明(意味着可以不知道subtree的存在)
  • 本質就是把子項目目錄作爲一個普通的文件目錄,對於父級的主項目來說是完全透明的,原來是怎麼操作現在依舊是那麼操作
  • 無法直接單獨查看子倉庫的修改記錄,因爲子倉庫的修改包含在父倉庫的記錄中了。

3 - subtree

3.1 在父倉庫中新增子倉庫

cd <父倉庫>
git subtree add --prefix=<子倉庫在父倉庫的相對路徑> <子倉庫地址> <branch> --squash

# 參數--squash: 表示不拉取歷史信息,只生成一條commit信息,也就是不拉取子項目完整的歷史記錄

如果不需要更新或推送子倉庫的改動,那麼對於其他項目人員來說,可以不需要知道子倉庫的存在。
也就是說,在這種情況下,子倉庫就相當於父倉庫的一個普通目錄。

注意:
如果在子倉庫發生改動(更新和修改)後,在父倉庫中運行git status查看到子倉庫文件顯示modified,需要在父倉庫中使用 add commit push 提交推送。
也就是說,子倉庫的更改是會反映在父倉庫的更改上的,因此只要是對子倉庫進行了修改,無論如何都需要對父倉庫進行一次提交。

示例:

cd temp-test-1
git subtree add --prefix=sub/temp-test-2 <temp-test-2 address> master --squash

此時通過git log可以查看到新增兩條commit

commit b76c7b190760f33e7ae9dfeba40136e39309b737 (HEAD -> master)
Merge: b0aec0a e6a10bc
Author:
Date:

    Merge commit 'e6a10bc748638240ff372ae19c747584b7d8d1af' as 'sub/temp-test-2'

commit e6a10bc748638240ff372ae19c747584b7d8d1af
Author: 
Date:

    Squashed 'sub/temp-test-2/' content from commit bfb58a3

    git-subtree-dir: sub/temp-test-2
    git-subtree-split: bfb58a379631813584d286ee00a19a79860f9562

3.2 父倉庫的改動

在父倉庫目錄下查看狀態和提交修改都和原來一樣,保持不變。

3.3 拉取子倉庫的更新

git subtree pull --prefix=sub/temp-test-2 <temp-test-2 address> master --squash

3.4 推送子倉庫的修改

git subtree push --prefix=sub/temp-test-2 <temp-test-2 address> master

3.5 子倉庫切出起點

可以將子項目當前版本切出爲一個分支,作爲 push 時遍歷的新起點,這樣以後每次遍歷都只從上次切出的分支的起點開始,不會再遍歷以前的了,節約時間。
這個分支只是作起點儲存用的,不用管它不用修改不用推送到遠程庫。
需要更新這個起點時,只需要再在當前版本上再切出一個作起點的分支覆蓋原來的,命令和第一次切出分支作起點時相同。

git subtree split [--rejoin] --prefix=<本地子項目目錄> --branch <主項目中作爲放置子項目的分支名>

注意:
如果 push 時使用了 --squash 參數合併提交,那麼 split 時不能使用 --rejoin 參數,反之必須使用。

4- submodule

git clone <repository> --recursive  # 遞歸的方式克隆整個倉庫,包含父倉庫和子倉庫的內容
git submodule add <repository address> <path> # 添加子倉庫
git submodule init  # 初始化子倉庫,向.git/config文件寫入子模塊的信息
git submodule update  # 更新子倉庫,拉取父倉庫中對應子倉庫的提交id內容到到父倉庫目錄
git submodule foreach git pull  # 拉取所有子倉庫

4.1 在父倉庫中新增子倉庫

cd <父倉庫>
git submodule add <子倉庫地址> <子倉庫在父倉庫的相對路徑>

命令執行成功後

  • 父倉庫根目錄下會產生.gitmodules文件,包含子倉庫的path和url信息, 並且.gitmodules在父倉庫的git版本控制中
  • 父倉庫的git配置文件中加入了submodule字段,包含子倉庫的url信息
  • 父倉庫.git目錄下生成modudles文件夾,包含子倉庫的所有相關信息

示例: 在父倉庫中新增子倉庫並提交子倉庫信息

cd <project>
git submodule add <module repo addr> <module path>
git add *
git commit -m "add submodule"
git push origin master

4.2 拉取整個倉庫

如果單純使用git clone命令,克隆一個包含子倉庫的倉庫,並不會clone子倉庫的內容。
需要執行本地.gitmodules初始化的命令,再同步遠端submodule源碼。

方式1: 獲取父倉庫和所有子倉庫的內容

git clone <父倉庫地址> --recursive  或者 git clone <父倉庫地址> --recurse-submodules

# 使用參數--recursive,Git會自動遞歸去拉取所有的父倉庫和子倉庫的相關內容

方式2:

git clone <父倉庫地址>
git submodule init && git submodule update  或者  git submodule update --init --recursive

# - git submodule init  # 初始化本地.gitmodules文件
# - git submodule update  # 同步遠端submodule源碼

4.3 修改子倉庫

如果子倉庫發生改動,需要先在子倉庫提交,然後再到父倉庫提交。
子倉庫提交結束後,在父倉庫的根目錄執行 git status 命令會顯示子倉庫有新的提交。

示例:

cd <project>/<module>
git branch
echo "This is a submodule." > sm.txt
git add *
git commit -m "add sm.txt"
git push

cd ..
git status
git diff
git add *
git commit -m "update submodule add sm.txt"
git push 

4.4 更新子倉庫

非子倉庫的開發人員只需在父倉庫下pull代碼時,如果發現submodule有更改,執行git submodule update進行更新,然後將改動提交到父倉庫。
默認的使用git status可以看到父倉庫中submodule commit id的改變。

方式1: 先pull父項目,然後執行git submodule update

cd <project>
git pull
git submodule update

方式2: 先進入子模塊,然後切換到需要的分支,然後對子模塊pull

cd <project>/<module>
git checkout master
cd ..
git submodule foreach git pull

4.5 刪除submodule

方式1:

git submodule deinit -f <submodule>  # 逆初始化模塊,子模塊目錄將被清空
git rm --cached <submodule>  # 刪除.gitmodules中記錄的模塊信息(--cached選項清除.git/modules中的緩存)
git submodule  # 沒有顯示子模塊信息
git commit -m "remove submodule"

方式2:

git rm -rf <子倉庫在父倉庫的相對路徑>
rm -rf .git/modules/<子倉庫名稱>
vim .git/config  # 刪除submodule相關的內容
git commit -m "remove submodule"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章