Ответ 1
обновит все подмодули в связанной ветки (по умолчанию, мастер), т.е. будет работать для подмоду1 и подмод2, но для остальных делать не так.
Собственно, да, это сделает "неправильный материал для остальных".
Я проиллюстрирую эту ошибку с приведенным ниже примером (репо с именем parent
с подмодулем 'sub
', сам с подмодулем 'subsub
'), используя git версию 2.9.0.windows. 1.
И я предложу простой способ обхода, позволяющий sub
следовать master
, убедившись, что subsub
не проверен на свой собственный master
.
Настройка
Сделайте repo subsub
с двумя коммитами:
[email protected] D:\git\tests\subm
> git init subsub1
Initialized empty Git repository in D:/git/tests/subm/subsub1/.git/
> cd subsub1
> git commit --allow-empty -m "subsub c1"
[master (root-commit) f3087a9] subsub c1
> git commit --allow-empty -m "subsub c2"
[master 03d08cc] subsub c2
Давайте сделаем этот репо subsub
подмодулем другого репо 'sub
':
[email protected] D:\git\tests\subm
> git init sub
Initialized empty Git repository in D:/git/tests/subm/sub/.git/
> cd sub
> git submodule add -- ../subsub
Cloning into 'D:/git/tests/subm/sub/subsub'...
done.
По умолчанию этот субмодуль "subsub
" выводится на свой собственный master
HEAD ( gl
является псевдонимом для git log
с симпатичным форматом):
[email protected] D:\git\tests\subm\sub\subsub
> gl
* 03d08cc - (HEAD -> master, origin/master, origin/HEAD) subsub c2 (4 minutes ago) VonC
* f3087a9 - subsub c1 (4 minutes ago) VonC
Удостоверьтесь, что sub
имеет subsub
в c1
(который не является master HEAD C2
):
[email protected] D:\git\tests\subm\sub\subsub
> git checkout @~
Note: checking out '@~'.
You are in 'detached HEAD' state.
HEAD is now at f3087a9... subsub c1
> git br -avv
* (HEAD detached at f3087a9) f3087a9 subsub c1
master 03d08cc [origin/master] subsub c2
remotes/origin/HEAD -> origin/master
remotes/origin/master 03d08cc subsub c2
Пусть добавляет и фиксирует этот подмодуль "subsub
" (выдается в master~1
c1
) в своем родительском репо 'sub
':
[email protected] D:\git\tests\subm\sub\subsub
> cd ..
[email protected] D:\git\tests\subm\sub
> git add .
> git commit -m "subsub at HEAD-1"
[master (root-commit) 1b8144b] subsub at HEAD-1
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 subsub
Добавьте несколько коммитов в этот репо 'sub
':
[email protected] D:\git\tests\subm\sub
> git commit --allow-empty -m "sub c1"
[master b7d1c40] sub c1
> git commit --allow-empty -m "sub c2"
[master c77f4b2] sub c2
[email protected] D:\git\tests\subm\sub
> gl
* c77f4b2 - (HEAD -> master) sub c2 (2 seconds ago) VonC
* b7d1c40 - sub c1 (3 seconds ago) VonC
* 1b8144b - subsub at HEAD-1 (77 seconds ago) VonC
Последняя фиксация sub
связывает свой подмодуль "subsub
" с правой фиксацией (подпункт c1
один, а не c2
)
[email protected] D:\git\tests\subm\sub
> git ls-tree @
100644 blob 25a0feba7e1c1795be3b8e7869aaa5dba29d33e8 .gitmodules
160000 commit f3087a9bc9b743625e0799f57c017c82c50e35d6 subsub
^^^
That is subsub master~1 commit c1
Наконец, позвольте сделать основной родительский репо 'parent
' и добавить 'sub
' в качестве подмодуля:
[email protected] D:\git\tests\subm
> git init parent
Initialized empty Git repository in D:/git/tests/subm/parent/.git/
> cd parent
[email protected] D:\git\tests\subm\parent
> git submodule add -- ../sub
Cloning into 'D:/git/tests/subm/parent/sub'...
done.
Убедитесь, что sub
не проверен на master
HEAD (как и раньше для subsub
)
[email protected] D:\git\tests\subm\parent
> cd sub
[email protected] D:\git\tests\subm\parent\sub
> gl
* c77f4b2 - (HEAD -> master, origin/master, origin/HEAD) sub c2 (2 minutes ago) VonC
* b7d1c40 - sub c1 (2 minutes ago) VonC
* 1b8144b - subsub at HEAD-1 (3 minutes ago) VonC
[email protected] D:\git\tests\subm\parent\sub
> git checkout @~1
Note: checking out '@~1'.
You are in 'detached HEAD' state.
HEAD is now at b7d1c40... sub c1
Теперь добавим sub
(проверили на своем c1
commit, а не на его c2 master
HEAD), на parent
repo:
[email protected] D:\git\tests\subm\parent
> git add .
> git st
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitmodules
new file: sub
[email protected] D:\git\tests\subm\parent
> git commit -m "sub at c1"
[master (root-commit) 27374ec] sub at c1
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 sub
Пусть make sub
следует master
как подмодуль в repo parent
:
[email protected] D:\git\tests\subm\parent
> git config -f .gitmodules submodule.sub.branch master
> git diff
diff --git a/.gitmodules b/.gitmodules
index 8688a8c..97974c1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "sub"]
path = sub
url = ../sub
+ branch = master
[email protected] D:\git\tests\subm\parent
> git add .
> git commit -m "sub follows master"
[master 2310a02] sub follows master
1 file changed, 1 insertion(+)
[email protected] D:\git\tests\subm\parent
> gl
* 2310a02 - (HEAD -> master) sub follows master (1 second ago) VonC
* 27374ec - sub at c1 (2 minutes ago) VonC
Ошибка:
Если я клонирую repo parent
, а затем попрошу какой-либо из его подмодуля проверить его после удаленной ветки, sub
и subsub
проверит их ветку master
(пока только sub
должен проверить master
, subsub
должен оставаться на c1
)
Сначала клон:
[email protected] D:\git\tests\subm
> git clone --recursive parent p1
Cloning into 'p1'...
done.
Submodule 'sub' (D:/git/tests/subm/sub) registered for path 'sub'
Cloning into 'D:/git/tests/subm/p1/sub'...
done.
Submodule path 'sub': checked out 'b7d1c403edaddf6a4c00bbbaa8e2dfa6ffbd112f'
Submodule 'subsub' (D:/git/tests/subm/subsub) registered for path 'sub/subsub'
Cloning into 'D:/git/tests/subm/p1/sub/subsub'...
done.
Submodule path 'sub/subsub': checked out 'f3087a9bc9b743625e0799f57c017c82c50e35d6'
До сих пор так хорошо: sub
и subsub
выставляются в c1
, а не c2
(то есть: не их master HEAD C2
)
Но:
[email protected] D:\git\tests\subm\p1
> git submodule update --recursive --remote
Submodule path 'sub': checked out 'c77f4b2590794e030ec68a8cea23ae566701d2de'
Submodule path 'sub/subsub': checked out '03d08cc81e3b9c0734b8f53fad03ea7b1f0373df'
Теперь, из клона p1
, оба подмодуля и подсуммодуля находятся в их master HEAD C2
.
И даже несмотря на то, что sub
(вычисленный на master
как ожидалось) все еще имеет subsub
в c2
:
[email protected] D:\git\tests\subm\p1\sub
> git ls-tree @
100644 blob 25a0feba7e1c1795be3b8e7869aaa5dba29d33e8 .gitmodules
160000 commit f3087a9bc9b743625e0799f57c017c82c50e35d6 subsub
Обход проблемы:
Не изменяя ничего внутри sub
и subsub
, вот как убедиться, что subsub
остается в ожидаемом c1
commit вместо следующего master
(например, sub
)
Вызвать git submodule update --recursive
из подмодуля, который сам вложил подмодули (поэтому здесь нет --remote
)
[email protected] D:\git\tests\subm\p1\sub
> git submodule update --recursive
Submodule path 'subsub': checked out 'f3087a9bc9b743625e0799f57c017c82c50e35d6'
Теперь имеем:
-
sub
, оставшееся приmaster
(из-за директивы parent.gitmodules
branch
и ее начальнойgit submodule update --recursive --remote
) -
subsub
возвращается к записанному sha1 (c1
, notmaster c2
)
Заключение
- Это выглядит как плохой дизайн:
--recursive
применяет--remote
ко всем вложенным подмодулям, по умолчанию используется мастер, когда не найденоsubmodule.<path>.<branch>
. -
Вы можете script выйти из этого, чтобы:
-
update --remote
что вы хотите - сброс любого подмодуля, который не имеет ветки, указанной в файле верхнего родительского репо
.gitmodules
, на их правильный SHA1.
-
Просто создайте где-нибудь в %PATH%
git-subupd
script (a bash script, который будет работать даже в обычном сеансе Windows CMD
, потому что он будет интерпретироваться git bash)
git-subupd
:
#!/bin/bash
git submodule update --recursive --remote
export top=$(pwd)
git submodule foreach --recursive 'b=$(git config -f ${top}/.gitmodules submodule.${path}.branch); case "${b}" in "") git checkout ${sha1};; esac'
"комбинации команд git" сводятся к одному вызову git:
cd /path/to/parent/repo
git subupd
Вот и все.
(Любой script, называемый git-xxx
, может быть вызван git с git xxx
)
[email protected] D:\git\tests\subm\p1
> git subupd
Submodule path 'sub/subsub': checked out '03d08cc81e3b9c0734b8f53fad03ea7b1f0373df'
Entering 'sub'
Entering 'sub/subsub'
Previous HEAD position was 03d08cc... subsub c2
HEAD is now at f3087a9... subsub c1
sub
остается установленным в master
(commit c2
, без изменений), а subsub
- от reset до c1
(вместо master c2
).
OP BartBog объявляет в комментариях с небольшим изменением этого script с:
export top=$(pwd)
git submodule foreach --recursive \
'b=$(git config -f ${top}/.gitmodules submodule.${path}.branch); \
case "${b}" in \
"") git checkout ${sha1};; \
*) git checkout ${b}; git pull origin ${b};; \
esac'
чтобы избежать вызова
submodule update --remote
И чтобы убедиться, что мои подмодули не находятся в состоянии отсоединенной головки (