git 子模块如何恢复到它的提交版本?
How can a git submodule be restored to it's committed version?
如果我更新一个父项目分支中的子模块,然后切换到同一工作树中的另一个分支,则子模块引用显示为好像已被修改。
例如(哈希值可能会有所不同,您可能需要向下滚动代码 window 才能看到所有行):
# create soon to be submodule
mkdir /tmp/example-submodule
cd /tmp/example-submodule
git init
echo a > a
git add a
git commit -m 'm'
cp -r .git /tmp/example-submodule.git
cd /tmp/example-submodule.git
git config --bool core.bare true
cd /tmp
/bin/rm -rf /tmp/example-submodule
git clone file:///tmp/example-submodule.git
#create other project and add sub-module
mkdir /tmp/example-supermodule
cd /tmp/example-supermodule
git init
echo x > x
git add x
git commit -m 'm'
cp -r .git /tmp/example-supermodule.git
cd /tmp/example-supermodule.git
git config --bool core.bare true
cd /tmp
/bin/rm -rf /tmp/example-supermodule
git clone file:///tmp/example-supermodule.git
#update the submodule
cd /tmp/example-supermodule
git submodule add file:///tmp/example-submodule.git example-sub
git commit -a -m'm'
git submodule status
# prints: 189ea25d45618862d0bfcbf5bd995e05ce1c2e4e example-sub (heads/master)
git push
#update the submodule
cd /tmp/example-submodule
echo b > b
git add b
git commit -m 'm'
git push
#create new branch in super module and update submodule to new HEAD
cd /tmp/example-supermodule
git branch otherbranch
git checkout otherbranch
git submodule update --remote
git commit -a -m'm'
git submodule status
# prints: 26f94e59002603475a1ba731104f92e10e88cf6b example-sub (remotes/origin/HEAD)
git push origin otherbranch
#checkout another branch
git checkout master
git status
cat .git/modules/example-sub/HEAD
# prints: 26f94e59002603475a1ba731104f92e10e88cf6b
检出master后,子模块的hash不同,好像其他分支的更新也影响了master。
如果我克隆超级项目而不是切换同一工作树中的分支:
cd /tmp
git clone --recursive file:///tmp/example-supermodule.git/ other
cd /tmp/other
git submodule status
它显示了在 master 分支中添加的子模块提交。
某人如何在他们的工作树中的分支之间切换并使子模块的提交与提交的内容相匹配?或者如何在更改分支后恢复显示子模块在该分支中未修改时已修改?
我刚刚用 git 2.9.0
重现了这个问题
你最后要做的就是找回干净的主人:
git submodule update
这会将子模块重置为其 master
值,并且 .git/modules/example-sub/HEAD
将具有正确的值
您再次结帐时会遇到同样的问题otherbranch
。
右边gitlink (special entry in the index)会被签出
但是 .git/modules/example-sub/HEAD
不会立即更改。
这两种情况,那是因为checkout只修改了gitlink,没有子模块的内容。
只有 git submodule update
会实际检查子模块的内容到其记录的 gitlink SHA1.
这样一来,如果您在子模块中有正在进行的工作,它们不会被父仓库中的检出清除。
这是我自己的实验:
C:\Users\vonc\prog\git\tests>mkdir subm
C:\Users\vonc\prog\git\tests>cd subm
让我们创建两个存储库,每个存储库有一个提交:
C:\Users\vonc\prog\git\tests\subm>git init s
Initialized empty Git repository in C:/Users/vonc/prog/git/tests/subm/s/.git/
C:\Users\vonc\prog\git\tests\subm>git init p
Initialized empty Git repository in C:/Users/vonc/prog/git/tests/subm/p/.git/
C:\Users\vonc\prog\git\tests\subm>cd s
C:\Users\vonc\prog\git\tests\subm\s>git commit --allow-empty -m "first s commit"
[master (root-commit) d11bd81] first s commit
C:\Users\vonc\prog\git\tests\subm\s>cd ..\p
C:\Users\vonc\prog\git\tests\subm\p>git commit --allow-empty -m "first p commit"
[master (root-commit) 10a7044] first p commit
让我们添加 s
作为 p
(父仓库)的子模块
C:\Users\vonc\prog\git\tests\subm\p>git submodule add -- ../s
Cloning into 'C:/Users/vonc/prog/git/tests/subm/p/s'...
done.
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: s
C:\Users\vonc\prog\git\tests\subm\p>git commit -m "add p"
[master aa33ba9] add p
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 s
现在让我们修改 s
存储库,向其 master
分支添加一个新提交
C:\Users\vonc\prog\git\tests\subm\p>cd ..\s
C:\Users\vonc\prog\git\tests\subm\s>git commit --allow-empty -m "second s commit"
[master 81e4800] second s commit
C:\Users\vonc\prog\git\tests\subm\s>gl
* 81e4800 - (HEAD -> master) second s commit (1 second ago) <VonC>
* d11bd81 - first s commit (3 minutes ago) <VonC>
让我们在父仓库中创建一个新分支
C:\Users\vonc\prog\git\tests\subm\s>cd ..\p
C:\Users\vonc\prog\git\tests\subm\p>git commit --allow-empty -m "second s commit"
C:\Users\vonc\prog\git\tests\subm\p>git checkout -b branch
Switched to a new branch 'branch'
让我们更新子模块,并将其添加到新分支branch
:
C:\Users\vonc\prog\git\tests\subm\p>git submodule update --remote
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (1/1), done.
From C:/Users/vonc/prog/git/tests/subm/s
d11bd81..81e4800 master -> origin/master
Submodule path 's': checked out '81e48007afc90aceca16d884d0fdc34074121732'
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: s (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
C:\Users\vonc\prog\git\tests\subm\p>git add .
C:\Users\vonc\prog\git\tests\subm\p>git commit -m "update s to latest master"
[branch 271a4fb] update s to latest master
1 file changed, 1 insertion(+), 1 deletion(-)
C:\Users\vonc\prog\git\tests\subm\p>cat .git\modules\s\HEAD
81e48007afc90aceca16d884d0fdc34074121732
C:\Users\vonc\prog\git\tests\subm\p>gl
* 271a4fb - (HEAD -> branch) update s to latest master (26 seconds ago) <VonC>
* f86aab2 - (master) second s commit (2 minutes ago) <VonC>
* aa33ba9 - add p (3 minutes ago) <VonC>
* 10a7044 - first p commit (4 minutes ago) <VonC>
我签出master
,右边的子模块SHA1被签出,但是子模块的内容还没有改变
C:\Users\vonc\prog\git\tests\subm\p>git checkout master
M s
Switched to branch 'master'
C:\Users\vonc\prog\git\tests\subm\p>cat .git\modules\s\HEAD
81e48007afc90aceca16d884d0fdc34074121732
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: s (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
如果我切换回分支 branch
,状态将是干净的(那是因为子模块 s
的内容与其记录的 gitlink SHA1)
C:\Users\vonc\prog\git\tests\subm\p>git checkout branch
Switched to branch 'branch'
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch branch
nothing to commit, working directory clean
但是在 master
上,我需要一个 submodule update
来将子模块 s
的内容重置为它的 SHA1:
C:\Users\vonc\prog\git\tests\subm\p>git checkout master
M s
Switched to branch 'master'
C:\Users\vonc\prog\git\tests\subm\p>git submodule update
Submodule path 's': checked out 'd11bd8132971a18e3e7cd19984cc6ce106478087'
C:\Users\vonc\prog\git\tests\subm\p>cat .git\modules\s\HEAD
d11bd8132971a18e3e7cd19984cc6ce106478087
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch master
nothing to commit, working directory clean
结帐时也会出现同样的问题branch
:
C:\Users\vonc\prog\git\tests\subm\p>
C:\Users\vonc\prog\git\tests\subm\p>git checkout branch
M s
Switched to branch 'branch'
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: s (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
C:\Users\vonc\prog\git\tests\subm\p>git show s
commit 271a4fb6bf79e2524f98dfbd505b2876b0c173a8
Author: VonC <vonc@laposte.net>
Date: Sat Jul 9 06:52:57 2016 +0200
update s to latest master
diff --git a/s b/s
index d11bd81..81e4800 160000
--- a/s
+++ b/s
@@ -1 +1 @@
-Subproject commit d11bd8132971a18e3e7cd19984cc6ce106478087
+Subproject commit 81e48007afc90aceca16d884d0fdc34074121732
同样,git submodule update
会将子模块 s
的内容重置为记录在父仓库的分支 branch
中的 SHA1。
如果我更新一个父项目分支中的子模块,然后切换到同一工作树中的另一个分支,则子模块引用显示为好像已被修改。
例如(哈希值可能会有所不同,您可能需要向下滚动代码 window 才能看到所有行):
# create soon to be submodule
mkdir /tmp/example-submodule
cd /tmp/example-submodule
git init
echo a > a
git add a
git commit -m 'm'
cp -r .git /tmp/example-submodule.git
cd /tmp/example-submodule.git
git config --bool core.bare true
cd /tmp
/bin/rm -rf /tmp/example-submodule
git clone file:///tmp/example-submodule.git
#create other project and add sub-module
mkdir /tmp/example-supermodule
cd /tmp/example-supermodule
git init
echo x > x
git add x
git commit -m 'm'
cp -r .git /tmp/example-supermodule.git
cd /tmp/example-supermodule.git
git config --bool core.bare true
cd /tmp
/bin/rm -rf /tmp/example-supermodule
git clone file:///tmp/example-supermodule.git
#update the submodule
cd /tmp/example-supermodule
git submodule add file:///tmp/example-submodule.git example-sub
git commit -a -m'm'
git submodule status
# prints: 189ea25d45618862d0bfcbf5bd995e05ce1c2e4e example-sub (heads/master)
git push
#update the submodule
cd /tmp/example-submodule
echo b > b
git add b
git commit -m 'm'
git push
#create new branch in super module and update submodule to new HEAD
cd /tmp/example-supermodule
git branch otherbranch
git checkout otherbranch
git submodule update --remote
git commit -a -m'm'
git submodule status
# prints: 26f94e59002603475a1ba731104f92e10e88cf6b example-sub (remotes/origin/HEAD)
git push origin otherbranch
#checkout another branch
git checkout master
git status
cat .git/modules/example-sub/HEAD
# prints: 26f94e59002603475a1ba731104f92e10e88cf6b
检出master后,子模块的hash不同,好像其他分支的更新也影响了master。
如果我克隆超级项目而不是切换同一工作树中的分支:
cd /tmp
git clone --recursive file:///tmp/example-supermodule.git/ other
cd /tmp/other
git submodule status
它显示了在 master 分支中添加的子模块提交。
某人如何在他们的工作树中的分支之间切换并使子模块的提交与提交的内容相匹配?或者如何在更改分支后恢复显示子模块在该分支中未修改时已修改?
我刚刚用 git 2.9.0
重现了这个问题你最后要做的就是找回干净的主人:
git submodule update
这会将子模块重置为其 master
值,并且 .git/modules/example-sub/HEAD
将具有正确的值
您再次结帐时会遇到同样的问题otherbranch
。
右边gitlink (special entry in the index)会被签出
但是 .git/modules/example-sub/HEAD
不会立即更改。
这两种情况,那是因为checkout只修改了gitlink,没有子模块的内容。
只有 git submodule update
会实际检查子模块的内容到其记录的 gitlink SHA1.
这样一来,如果您在子模块中有正在进行的工作,它们不会被父仓库中的检出清除。
这是我自己的实验:
C:\Users\vonc\prog\git\tests>mkdir subm
C:\Users\vonc\prog\git\tests>cd subm
让我们创建两个存储库,每个存储库有一个提交:
C:\Users\vonc\prog\git\tests\subm>git init s
Initialized empty Git repository in C:/Users/vonc/prog/git/tests/subm/s/.git/
C:\Users\vonc\prog\git\tests\subm>git init p
Initialized empty Git repository in C:/Users/vonc/prog/git/tests/subm/p/.git/
C:\Users\vonc\prog\git\tests\subm>cd s
C:\Users\vonc\prog\git\tests\subm\s>git commit --allow-empty -m "first s commit"
[master (root-commit) d11bd81] first s commit
C:\Users\vonc\prog\git\tests\subm\s>cd ..\p
C:\Users\vonc\prog\git\tests\subm\p>git commit --allow-empty -m "first p commit"
[master (root-commit) 10a7044] first p commit
让我们添加 s
作为 p
(父仓库)的子模块
C:\Users\vonc\prog\git\tests\subm\p>git submodule add -- ../s
Cloning into 'C:/Users/vonc/prog/git/tests/subm/p/s'...
done.
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: s
C:\Users\vonc\prog\git\tests\subm\p>git commit -m "add p"
[master aa33ba9] add p
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 s
现在让我们修改 s
存储库,向其 master
分支添加一个新提交
C:\Users\vonc\prog\git\tests\subm\p>cd ..\s
C:\Users\vonc\prog\git\tests\subm\s>git commit --allow-empty -m "second s commit"
[master 81e4800] second s commit
C:\Users\vonc\prog\git\tests\subm\s>gl
* 81e4800 - (HEAD -> master) second s commit (1 second ago) <VonC>
* d11bd81 - first s commit (3 minutes ago) <VonC>
让我们在父仓库中创建一个新分支
C:\Users\vonc\prog\git\tests\subm\s>cd ..\p
C:\Users\vonc\prog\git\tests\subm\p>git commit --allow-empty -m "second s commit"
C:\Users\vonc\prog\git\tests\subm\p>git checkout -b branch
Switched to a new branch 'branch'
让我们更新子模块,并将其添加到新分支branch
:
C:\Users\vonc\prog\git\tests\subm\p>git submodule update --remote
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (1/1), done.
From C:/Users/vonc/prog/git/tests/subm/s
d11bd81..81e4800 master -> origin/master
Submodule path 's': checked out '81e48007afc90aceca16d884d0fdc34074121732'
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: s (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
C:\Users\vonc\prog\git\tests\subm\p>git add .
C:\Users\vonc\prog\git\tests\subm\p>git commit -m "update s to latest master"
[branch 271a4fb] update s to latest master
1 file changed, 1 insertion(+), 1 deletion(-)
C:\Users\vonc\prog\git\tests\subm\p>cat .git\modules\s\HEAD
81e48007afc90aceca16d884d0fdc34074121732
C:\Users\vonc\prog\git\tests\subm\p>gl
* 271a4fb - (HEAD -> branch) update s to latest master (26 seconds ago) <VonC>
* f86aab2 - (master) second s commit (2 minutes ago) <VonC>
* aa33ba9 - add p (3 minutes ago) <VonC>
* 10a7044 - first p commit (4 minutes ago) <VonC>
我签出master
,右边的子模块SHA1被签出,但是子模块的内容还没有改变
C:\Users\vonc\prog\git\tests\subm\p>git checkout master
M s
Switched to branch 'master'
C:\Users\vonc\prog\git\tests\subm\p>cat .git\modules\s\HEAD
81e48007afc90aceca16d884d0fdc34074121732
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: s (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
如果我切换回分支 branch
,状态将是干净的(那是因为子模块 s
的内容与其记录的 gitlink SHA1)
C:\Users\vonc\prog\git\tests\subm\p>git checkout branch
Switched to branch 'branch'
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch branch
nothing to commit, working directory clean
但是在 master
上,我需要一个 submodule update
来将子模块 s
的内容重置为它的 SHA1:
C:\Users\vonc\prog\git\tests\subm\p>git checkout master
M s
Switched to branch 'master'
C:\Users\vonc\prog\git\tests\subm\p>git submodule update
Submodule path 's': checked out 'd11bd8132971a18e3e7cd19984cc6ce106478087'
C:\Users\vonc\prog\git\tests\subm\p>cat .git\modules\s\HEAD
d11bd8132971a18e3e7cd19984cc6ce106478087
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch master
nothing to commit, working directory clean
结帐时也会出现同样的问题branch
:
C:\Users\vonc\prog\git\tests\subm\p>
C:\Users\vonc\prog\git\tests\subm\p>git checkout branch
M s
Switched to branch 'branch'
C:\Users\vonc\prog\git\tests\subm\p>git st
On branch branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: s (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
C:\Users\vonc\prog\git\tests\subm\p>git show s
commit 271a4fb6bf79e2524f98dfbd505b2876b0c173a8
Author: VonC <vonc@laposte.net>
Date: Sat Jul 9 06:52:57 2016 +0200
update s to latest master
diff --git a/s b/s
index d11bd81..81e4800 160000
--- a/s
+++ b/s
@@ -1 +1 @@
-Subproject commit d11bd8132971a18e3e7cd19984cc6ce106478087
+Subproject commit 81e48007afc90aceca16d884d0fdc34074121732
同样,git submodule update
会将子模块 s
的内容重置为记录在父仓库的分支 branch
中的 SHA1。