Update Q2 2018 and Git 2.18:
Moving a submodule that itself has submodule in it with "git mv
" forgot to make necessary adjustment to the nested sub-submodules;
now the codepath learned to recurse into the submodules.
See commit 6856077 (28 Mar 2018) by Jonathan Tan (jhowtan
).
See commit da62f78, commit 0c89fdd, commit 3b8fb39, commit f793b89, commit 61aad92 (28 Mar 2018) by Stefan Beller (stefanbeller
).
(Merged by Junio C Hamano -- gitster
-- in commit 0c7ecb7, 08 May 2018)
submodule: fixup nested submodules after moving the submodule
As submodules can have nested submodules themselves, we'd also want to fix the nested submodules when asked to. Add an option to recurse into the nested submodules and connect them as well.
As submodules are identified by their name (which determines their git
directory in relation to their superproject's git directory) internally
and by their path in the working tree of the superproject, we need to
make sure that the mapping of name <-> path
is kept intact. We can do
that in the git-mv
command by writing out the .gitmodules
file first
and then forcing a reload of the submodule config machinery.
Update Q4 2017:
The latest Git 2.14.x/2.15 (Q4 2017) documents the bug
See commit c514167 (15 Sep 2017) by Heiko Voigt (hvoigt
).
(Merged by Junio C Hamano -- gitster
-- in commit 450b908, 25 Sep 2017)
When using git-mv
with a submodule it will detect that and update the
paths for its configurations (.gitmodules
, worktree and gitfile).
This does not work for recursive submodules where a user renames the root
submodule.
Original answer 2015
I just tested it with git 2.6.0 (on Windows), and moving submodules with nested submodules of their own seems to be problematic:
C:\Users\vonc\prog\git\tests\submove>git clone --recursive a a1
Cloning into 'a1'...
done.
Submodule '2015/b' (C:/Users/vonc/prog/git/tests/submove/b) registered for path '2015/b'
Submodule 'c' (C:/Users/vonc/prog/git/tests/submove/c) registered for path 'c'
Cloning into '2015/b'...
done.
Submodule path '2015/b': checked out 'dc18955ec7b9ad0c04245968e2474646e4d593b2'
Cloning into 'c'...
done.
Submodule path 'c': checked out 'fb4722eaca17ac171b7a2c8c5a1ac1e697f0ee85'
Submodule 'd' (C:/Users/vonc/prog/git/tests/submove/d) registered for path 'd'
Cloning into 'd'...
done.
Submodule path 'c/d': checked out '73cd7b8ff82519720b2fcca18df5ed00dd618b71'
I have:
a1
c
d
2015
b
If I try and move submodule c
in the 2015 subfolder:
C:\Users\vonc\prog\git\tests\submove\a1>git mv c 2015/c
C:\Users\vonc\prog\git\tests\submove\a1>git status
fatal: Not a git repository: d/../../.git/modules/c/modules/d
fatal: 'git status --porcelain' failed in submodule 2015/c
I found that I need to modify 2 things in the nested module d
:
1/ modify manually .git/modules/c/modules/d/config
to inject the right path:
git config -f .git/modules/c/modules/d/config core.worktree ../../../../../2015/c/d
^^^^
2/ modify d
worktree:
git config -f .git/modules/c/modules/d/config core.worktree ../../../../../2015/c/d
From there, a git status
works, but I like (to be sure) to add a git submodule sync --recursive
:
C:\Users\vonc\prog\git\tests\submove\a1>git submodule sync --recursive
Synchronizing submodule url for '2015/b'
Synchronizing submodule url for '2015/c'
Synchronizing submodule url for '2015/c/d'
The git status
does show the expected result:
C:\Users\vonc\prog\git\tests\submove\a1>git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: .gitmodules
renamed: c -> 2015/c
I add and commit that change:
C:\Users\vonc\prog\git\tests\submove\a1>git add .
C:\Users\vonc\prog\git\tests\submove\a1>git commit -m "move sub c in 2015/c"
[master 8289632] move sub c in 2015/c
2 files changed, 1 insertion(+), 1 deletion(-)
rename c => 2015/c (100%)
C:\Users\vonc\prog\git\tests\submove\a1>gl
* 8289632 - (HEAD -> master) move sub c in 2015/c (3 seconds ago) <VonC>
* 7ebb8e0 - (origin/master, origin/HEAD) a with sub c (38 minutes ago) <VonC>
I now clone that repo to check the move was indeed properly registered:
C:\Users\vonc\prog\git\tests\submove>git clone --recursive a1 a2
Cloning into 'a2'...
done.
Submodule '2015/b' (C:/Users/vonc/prog/git/tests/submove/b) registered for path '2015/b'
Submodule 'c' (C:/Users/vonc/prog/git/tests/submove/c) registered for path '2015/c'
Cloning into '2015/b'...
done.
Submodule path '2015/b': checked out 'dc18955ec7b9ad0c04245968e2474646e4d593b2'
Cloning into '2015/c'...
done.
Submodule path '2015/c': checked out 'fb4722eaca17ac171b7a2c8c5a1ac1e697f0ee85'
Submodule 'd' (C:/Users/vonc/prog/git/tests/submove/d) registered for path 'd'
Cloning into 'd'...
done.
Submodule path '2015/c/d': checked out '73cd7b8ff82519720b2fcca18df5ed00dd618b71'
As you can see, c
and c/d
are in the expected 2015/
subfolder:
C:\Users\vonc\prog\git\tests\submove>cd a2
C:\Users\vonc\prog\git\tests\submove\a2>dir 2015\c
Directory of C:\Users\vonc\prog\git\tests\submove\a2\2015\c
03/10/2015 18:10 <DIR> .
03/10/2015 18:10 <DIR> ..
03/10/2015 18:10 29 .git
03/10/2015 18:10 40 .gitmodules
03/10/2015 18:10 <DIR> d
2 File(s) 69 bytes
3 Dir(s) 23 656 910 848 bytes free
C:\Users\vonc\prog\git\tests\submove\a2>dir 2015\c\d
Directory of C:\Users\vonc\prog\git\tests\submove\a2\2015\c\d
03/10/2015 18:10 <DIR> .
03/10/2015 18:10 <DIR> ..
03/10/2015 18:10 42 .git
03/10/2015 18:10 3 d.txt
2 File(s) 45 bytes
2 Dir(s) 23 656 910 848 bytes free