Jex’s Note

Git - Submodule 基本語法 & 實例操作

基本語法

git submodule foreach git pull origin master : 將每個submodule重新pull git submodule update --init : update submodule

git subomdule init :

根據 .gitmodules 的名稱和 URL,將這些資訊註冊到 .git/config 內,可是把 .gitmodules 內不用的 submodule 移除,使用這個指令並沒辦法自動刪除 .git/config 的相關內容,必須手動刪除;

git submodule update :

根據已註冊(也就是 .git/config )的 submodule 進行更新,例如 clone 遺失的 submodule,也就是上一段講的方法,所以執行這個指令前最好加上 --init

git submodule sync :

如果 submodule 的 remote URL 有變動,可以在 .gitmodules 修正 URL,然後執行這個指令,便會將 submodule 的 remote URL 更正

加入submodule :

git submodule add https://github.com/msanders/snipmate.vim.git bundle/snipmate.vim

clone時順便把submodule抓下來 :

git clone --recursive https://github.com/jex-lin/jex-vim.git clone

remove Git submodule (example : remove bundle/snipmate.vim)

$ oldPath="bundle/snipmate.vim"
$ git config -f .git/config --remove-section "submodule.${oldPath}"
$ git config -f .gitmodules --remove-section "submodule.${oldPath}"
$ git rm --cached "${oldPath}"
rm 'bundle/snipmate.vim'
$ rm -rf "${oldPath}"
$ rm -rf ".git/modules/${oldPath}"
$ git add .gitmodules
$ git commit -m "Removed ${oldPath}"
[master f36aa2e] Removed bundle/snipmate.vim
 2 files changed, 4 deletions(-)
 delete mode 160000 bundle/snipmate.vim

ref: http://blog.chh.tw/posts/git-submodule/

實例操作

practice_submodule => 假設它是如 jQuery 之類的第三方程式,我們要把它掛進來 test1 => 我 test2 => 是你同事

  • 3個都是獨立的repo
  • practice_submodule 是 push 到 github 的 practice_submodule.git,假設裡面目前已有 commit 紀錄了
  • test1、test2 目前是空資料夾也還不是個repo,之後會將它 push 到 github 的 test.git

我要先把 practice_submodule 掛進來,並且 push 到github,你同事再去 pull 下來,但發現 practice_submodule 沒東西,所以要做兩個關鍵的動作,然候”第三方程式”更新了,你同事將它的 practice_submodule 更新到最新版後 push 到 github,我將它 pull 下來,並且發現你的 practice_submodule 裡還是舊的,你要做一個關鍵動作把它更新到最新版…

我(test1) - 將 submodule 掛進來並且 push

jex_lin@devm3 ~/public_html/test1$ git init                                                             #初始化
Initialized empty Git repository in /home/jex_lin/public_html/test1/.git/
jex_lin@devm3 ~/public_html/test1$ git remote add origin https://github.com/jex-lin/test.git            #加入遠端位置
jex_lin@devm3 ~/public_html/test1$ git submodule add https://github.com/jex-lin/practice_submodule.git  #將 submodule 掛進來
Cloning into 'practice_submodule'...
remote: Counting objects: 27, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 27 (delta 5), reused 24 (delta 2)
 Unpacking objects: 100% (27/27), done.
jex_lin@devm3 ~/public_html/test1$ git add .                              #add
jex_lin@devm3 ~/public_html/test1$ git submodule init                     #記得 submodule 掛進來後要將 submodule 做初始化,git 才會知道
jex_lin@devm3 ~/public_html/test1$ git commit -m "add submodule"          #commit
[master (root-commit) a47ffce] add submodule
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 practice_submodule
jex_lin@devm3 ~/public_html/test1(master)$ git push origin master -f      #push 到 github。因為我遠端目前已有 commit,所以我將它強制 push
Username for 'https://github.com': jex-lin
Password for 'https://jex-lin@github.com':
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 329 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/jex-lin/test.git
 + 67b6611...a47ffce master -> master (forced update)

你同事(test2) - pull 回來,並且做 submodule 的處理

jex_lin@devm3 ~/public_html/test2$ git init                                                   #初始化
Initialized empty Git repository in /home/jex_lin/public_html/test2/.git/
jex_lin@devm3 ~/public_html/test2$ git remote add origin https://github.com/jex-lin/test.git  #加入遠端位置
jex_lin@devm3 ~/public_html/test2$ git pull origin master                                     #pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/jex-lin/test
 * branch            master     -> FETCH_HEAD

jex_lin@devm3 ~/public_html/test2(master)$ git submodule            #查看 submodule 的commit id
-0fae9e91890d86e633a48ba3d6c43d6d1b783360 practice_submodule        #減號...有問題!  什麼問題?  不知道,之後知道再補充
                                                                    #這時候進去 practice_submodule/ 裡面是沒有東西的,還需要做兩個步驟

jex_lin@devm3 ~/public_html/test2(master)$ git submodule init       #將 submodule 初始化
Submodule 'practice_submodule' (https://github.com/jex-lin/practice_submodule.git) registered for path 'practice_submodule'
jex_lin@devm3 ~/public_html/test2(master)$ git submodule update     #更新 submodule
Cloning into 'practice_submodule'...
remote: Counting objects: 27, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 27 (delta 5), reused 24 (delta 2)
Unpacking objects: 100% (27/27), done.
Submodule path 'practice_submodule': checked out '0fae9e91890d86e633a48ba3d6c43d6d1b783360'

jex_lin@devm3 ~/public_html/test2(master)$ git submodule                      #這時候再查看 submodule 的 commit id
 0fae9e91890d86e633a48ba3d6c43d6d1b783360 practice_submodule (heads/master)   #最前面沒符號了,舒服多了,再進去 practice_submodule/ 裡面就有東西了

第三方程式(practice_submodule) - 發行新版本了! (這部份指令省略,隨便改個檔案,並且 add, commit, push )

你同事(test2) - 接下來”你同事”發現新版本釋出了,趕緊來用用 :b

jex_lin@devm3 ~/public_html/test2(master)$ cd practice_submodule/                         #進入 submodule 的資料夾
jex_lin@devm3 ~/public_html/test2/practice_submodule((no branch))$ git checkout master    #發現是(no branch),這時 pull 是沒用的,要先切到 master
Switched to branch 'master'
jex_lin@devm3 ~/public_html/test2/practice_submodule(master)$ git pull                    #然候將 practice_submodule 最新版下載下來
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1)
Unpacking objects: 100% (3/3), done.
From https://github.com/jex-lin/practice_submodule
   0fae9e9..7ca8d97  master     -> origin/master
Updating 0fae9e9..7ca8d97
Fast-forward
 test | 1 +
 1 file changed, 1 insertion(+)

jex_lin@devm3 ~/public_html/test2/practice_submodule(master)$ cd ..             #回上一層
jex_lin@devm3 ~/public_html/test2(master)$ git submodule                        #查看 submodule 的 commit id
+7ca8d979e730727ccfbaed3c0dbfe5c8ff3b209e practice_submodule (heads/master)     #是加號

                  #(略)... 做 add、commit

jex_lin@devm3 ~/public_html/test2(master)$ git submodule                        #再查看 submodule 的 commit id
 7ca8d979e730727ccfbaed3c0dbfe5c8ff3b209e practice_submodule (heads/master)     #正常了
jex_lin@devm3 ~/public_html/test2(master)$ git push origin master               #push 到 github
Username for 'https://github.com': jex-lin
Password for 'https://jex-lin@github.com':
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 275 bytes, done.
Total 2 (delta 0), reused 0 (delta 0)
To https://github.com/jex-lin/test.git
   a47ffce..d920edf  master -> master

你(test1) - 現在”你”要 pull 更新”你同事”的變更

jex_lin@devm3 ~/public_html/test1(master)$ git pull origin master               #pull 下來
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 0), reused 2 (delta 0)
Unpacking objects: 100% (2/2), done.
From https://github.com/jex-lin/test
 * branch            master     -> FETCH_HEAD
Updating a47ffce..d920edf
Fast-forward
 practice_submodule | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
jex_lin@devm3 ~/public_html/test1(master)$ git submodule                        #查看 submodule 的 commit id
+0fae9e91890d86e633a48ba3d6c43d6d1b783360 practice_submodule (heads/master)     #是加號,代表 submodule 是舊的,現在要將 submodule 更新
jex_lin@devm3 ~/public_html/test1(master)$ git submodule update                 #更新 submodule ,在做這個動作之前你可以進去 practice_submodule 的資料夾裡面看看,資料還是上一版的資料,但應該要是最新版的才對阿!所以才需要更新 submodule
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1)
Unpacking objects: 100% (3/3), done.
From https://github.com/jex-lin/practice_submodule
   0fae9e9..7ca8d97  master     -> origin/master
Submodule path 'practice_submodule': checked out '7ca8d979e730727ccfbaed3c0dbfe5c8ff3b209e'

jex_lin@devm3 ~/public_html/test1(master)$ git submodule                            #查看 submodule 的 commit id
 7ca8d979e730727ccfbaed3c0dbfe5c8ff3b209e practice_submodule (remotes/origin/HEAD)  #沒問題了,再去 submodule 裡面看,檔案都是最新版的

將 submodule 掛進來的套件停用在某個 commit id

有時候我們在專案裡使用某些套件並不會想一直隨著套件更新而也跟著更新, 因為可能會導致原本功能是正常的, 更新完就不正常了, 所以希望將掛進來的套件就一直停在固定的版本就好了

  1. 將套件 fork 到自己的 github 裡
  2. 到該 submodule 下 checkout 到要的 tag 或 commit id (會變成 no branch, 但不用理會)
  3. 回到專案根目錄下 add 全部及 commit, git submodule 就會記住該套件的 commit id, 之後拉下來都會是那個 commit id 的 code 了

Comments