Teach "git submodule add" the --name option

"git submodule add" initializes the name of a submodule to its path. This was ok as long as the .git directory lived inside the submodule's work tree, but since 1.7.8 it is stored in the .git/modules/<name> directory of the superproject, making the submodule name survive the removal of the submodule's work tree. This leads to problems when the user tries to add a different submodule at the same path - and thus the same name - later, as that will happily try to restore the submodule from the old repository instead of the one the user specified and will lead to a checkout of the wrong repository. Add the new "--name" option to let the user provide a name for the submodule. This enables the user to solve this conflict without having to remove .git/modules/<name> by hand (which is no viable solution as it makes it impossible to checkout a commit that records the old submodule and populate it, as that will still check out the new submodule for the same reason). To achieve that the submodule's name is added to the parameter list of the module_clone() helper function. This makes it possible to remove the call of module_name() there because both callers of module_clone() already know the name and can provide it as argument number two. Reported-by: Jonathan Johnson <me@jondavidjohn.com> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jens Lehmann committed Sep 30, 2012 at 01:05 UTC 73b0898d0d04d432525f9d56e29bf70fc7bf6ea9
4 files changed +76 -12
Documentation/git-submodule.txt
+6 -1
@@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules
9 SYNOPSIS
10 --------
11 [verse]
12 -'git submodule' [--quiet] add [-b branch] [-f|--force]
12 +'git submodule' [--quiet] add [-b branch] [-f|--force] [--name <name>]
13 [--reference <repository>] [--] <repository> [<path>]
14 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
15 'git submodule' [--quiet] init [--] [<path>...]
@@ -266,6 +266,11 @@ OPTIONS
266 Initialize all submodules for which "git submodule init" has not been
267 called so far before updating.
268
269 +--name::
270 + This option is only valid for the add command. It sets the submodule's
271 + name to the given string instead of defaulting to its path. The name
272 + must be valid as a directory name and may not end with a '/'.
273 +
274 --reference <repository>::
275 This option is only valid for add and update commands. These
276 commands sometimes need to clone a remote repository. In this case,
Documentation/gitmodules.txt
+3 -1
@@ -18,7 +18,9 @@ working tree, is a text file with a syntax matching the requirements
18 of linkgit:git-config[1].
19
20 The file contains one subsection per submodule, and the subsection value
21 -is the name of the submodule. Each submodule section also contains the
21 +is the name of the submodule. The name is set to the path where the
22 +submodule has been added unless it was customized with the '--name'
23 +option of 'git submodule add'. Each submodule section also contains the
24 following required keys:
25
26 submodule.<name>.path::
git-submodule.sh
+22 -10
@@ -5,7 +5,7 @@
5 # Copyright (c) 2007 Lars Hjemli
6
7 dashless=$(basename "$0" | sed -e 's/-/ /')
8 -USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
8 +USAGE="[--quiet] add [-b branch] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
9 or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
10 or: $dashless [--quiet] init [--] [<path>...]
11 or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
@@ -29,6 +29,7 @@ files=
29 nofetch=
30 update=
31 prefix=
32 +custom_name=
33
34 # The function takes at most 2 arguments. The first argument is the
35 # URL that navigates to the submodule origin repo. When relative, this URL
@@ -179,8 +180,9 @@ module_name()
180 module_clone()
181 {
182 sm_path=$1
182 - url=$2
183 - reference="$3"
183 + name=$2
184 + url=$3
185 + reference="$4"
186 quiet=
187 if test -n "$GIT_QUIET"
188 then
@@ -189,8 +191,6 @@ module_clone()
191
192 gitdir=
193 gitdir_base=
192 - name=$(module_name "$sm_path" 2>/dev/null)
193 - test -n "$name" || name="$sm_path"
194 base_name=$(dirname "$name")
195
196 gitdir=$(git rev-parse --git-dir)
@@ -272,6 +272,11 @@ cmd_add()
272 reference="$1"
273 shift
274 ;;
275 + --name)
276 + case "$2" in '') usage ;; esac
277 + custom_name=$2
278 + shift
279 + ;;
280 --)
281 shift
282 break
@@ -336,6 +341,13 @@ Use -f if you really want to add it." >&2
341 exit 1
342 fi
343
344 + if test -n "$custom_name"
345 + then
346 + sm_name="$custom_name"
347 + else
348 + sm_name="$sm_path"
349 + fi
350 +
351 # perhaps the path exists and is already a git repo, else clone it
352 if test -e "$sm_path"
353 then
@@ -348,7 +360,7 @@ Use -f if you really want to add it." >&2
360
361 else
362
351 - module_clone "$sm_path" "$realrepo" "$reference" || exit
363 + module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" || exit
364 (
365 clear_local_git_env
366 cd "$sm_path" &&
@@ -359,13 +371,13 @@ Use -f if you really want to add it." >&2
371 esac
372 ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
373 fi
362 - git config submodule."$sm_path".url "$realrepo"
374 + git config submodule."$sm_name".url "$realrepo"
375
376 git add $force "$sm_path" ||
377 die "$(eval_gettext "Failed to add submodule '\$sm_path'")"
378
367 - git config -f .gitmodules submodule."$sm_path".path "$sm_path" &&
368 - git config -f .gitmodules submodule."$sm_path".url "$repo" &&
379 + git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
380 + git config -f .gitmodules submodule."$sm_name".url "$repo" &&
381 git add --force .gitmodules ||
382 die "$(eval_gettext "Failed to register submodule '\$sm_path'")"
383 }
@@ -594,7 +606,7 @@ Maybe you want to use 'update --init'?")"
606
607 if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
608 then
597 - module_clone "$sm_path" "$url" "$reference"|| exit
609 + module_clone "$sm_path" "$name" "$url" "$reference" || exit
610 cloned_modules="$cloned_modules;$name"
611 subsha1=
612 else
t/t7400-submodule-basic.sh
+45
@@ -681,4 +681,49 @@ test_expect_success 'moving the superproject does not break submodules' '
681 )
682 '
683
684 +test_expect_success 'submodule add --name allows to replace a submodule with another at the same path' '
685 + (
686 + cd addtest2 &&
687 + (
688 + cd repo &&
689 + echo "$submodurl/repo" >expect &&
690 + git config remote.origin.url >actual &&
691 + test_cmp expect actual &&
692 + echo "gitdir: ../.git/modules/repo" >expect &&
693 + test_cmp expect .git
694 + ) &&
695 + rm -rf repo &&
696 + git rm repo &&
697 + git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual &&
698 + test ! -s actual &&
699 + echo "gitdir: ../.git/modules/submod" >expect &&
700 + test_cmp expect submod/.git &&
701 + (
702 + cd repo &&
703 + echo "$submodurl/bare.git" >expect &&
704 + git config remote.origin.url >actual &&
705 + test_cmp expect actual &&
706 + echo "gitdir: ../.git/modules/repo_new" >expect &&
707 + test_cmp expect .git
708 + ) &&
709 + echo "repo" >expect &&
710 + git config -f .gitmodules submodule.repo.path >actual &&
711 + test_cmp expect actual &&
712 + git config -f .gitmodules submodule.repo_new.path >actual &&
713 + test_cmp expect actual&&
714 + echo "$submodurl/repo" >expect &&
715 + git config -f .gitmodules submodule.repo.url >actual &&
716 + test_cmp expect actual &&
717 + echo "$submodurl/bare.git" >expect &&
718 + git config -f .gitmodules submodule.repo_new.url >actual &&
719 + test_cmp expect actual &&
720 + echo "$submodurl/repo" >expect &&
721 + git config submodule.repo.url >actual &&
722 + test_cmp expect actual &&
723 + echo "$submodurl/bare.git" >expect &&
724 + git config submodule.repo_new.url >actual &&
725 + test_cmp expect actual
726 + )
727 +'
728 +
729 test_done