Skip to content

Commit

Permalink
Merge branch 'jl/submodule-add-by-name'
Browse files Browse the repository at this point in the history
If you remove a submodule, in order to keep the repository so that
"git checkout" to an older commit in the superproject history can
resurrect the submodule, the real repository will stay in $GIT_DIR
of the superproject.  A later "git submodule add $path" to add a
different submodule at the same path will fail.  Diagnose this case
a bit better, and if the user really wants to add an unrelated
submodule at the same path, give the "--name" option to give it a
place in $GIT_DIR of the superproject that does not conflict with
the original submodule.

* jl/submodule-add-by-name:
  submodule add: Fail when .git/modules/<name> already exists unless forced
  Teach "git submodule add" the --name option
  • Loading branch information
Jeff King committed Oct 29, 2012
2 parents d21240f + 4b7c286 commit fdb4d27
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 14 deletions.
7 changes: 6 additions & 1 deletion Documentation/git-submodule.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules
SYNOPSIS
--------
[verse]
'git submodule' [--quiet] add [-b branch] [-f|--force]
'git submodule' [--quiet] add [-b branch] [-f|--force] [--name <name>]
[--reference <repository>] [--] <repository> [<path>]
'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
Expand Down Expand Up @@ -265,6 +265,11 @@ OPTIONS
Initialize all submodules for which "git submodule init" has not been
called so far before updating.

--name::
This option is only valid for the add command. It sets the submodule's
name to the given string instead of defaulting to its path. The name
must be valid as a directory name and may not end with a '/'.

--reference <repository>::
This option is only valid for add and update commands. These
commands sometimes need to clone a remote repository. In this case,
Expand Down
4 changes: 3 additions & 1 deletion Documentation/gitmodules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ working tree, is a text file with a syntax matching the requirements
of linkgit:git-config[1].

The file contains one subsection per submodule, and the subsection value
is the name of the submodule. Each submodule section also contains the
is the name of the submodule. The name is set to the path where the
submodule has been added unless it was customized with the '--name'
option of 'git submodule add'. Each submodule section also contains the
following required keys:

submodule.<name>.path::
Expand Down
47 changes: 36 additions & 11 deletions git-submodule.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Copyright (c) 2007 Lars Hjemli

dashless=$(basename "$0" | sed -e 's/-/ /')
USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
USAGE="[--quiet] add [-b branch] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
or: $dashless [--quiet] init [--] [<path>...]
or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
Expand All @@ -29,6 +29,7 @@ files=
nofetch=
update=
prefix=
custom_name=

# The function takes at most 2 arguments. The first argument is the
# URL that navigates to the submodule origin repo. When relative, this URL
Expand Down Expand Up @@ -179,8 +180,9 @@ module_name()
module_clone()
{
sm_path=$1
url=$2
reference="$3"
name=$2
url=$3
reference="$4"
quiet=
if test -n "$GIT_QUIET"
then
Expand All @@ -189,8 +191,6 @@ module_clone()

gitdir=
gitdir_base=
name=$(module_name "$sm_path" 2>/dev/null)
test -n "$name" || name="$sm_path"
base_name=$(dirname "$name")

gitdir=$(git rev-parse --git-dir)
Expand Down Expand Up @@ -272,6 +272,11 @@ cmd_add()
reference="$1"
shift
;;
--name)
case "$2" in '') usage ;; esac
custom_name=$2
shift
;;
--)
shift
break
Expand Down Expand Up @@ -336,6 +341,13 @@ Use -f if you really want to add it." >&2
exit 1
fi

if test -n "$custom_name"
then
sm_name="$custom_name"
else
sm_name="$sm_path"
fi

# perhaps the path exists and is already a git repo, else clone it
if test -e "$sm_path"
then
Expand All @@ -347,8 +359,21 @@ Use -f if you really want to add it." >&2
fi

else

module_clone "$sm_path" "$realrepo" "$reference" || exit
if test -d ".git/modules/$sm_name"
then
if test -z "$force"
then
echo >&2 "$(eval_gettext "A git directory for '\$sm_name' is found locally with remote(s):")"
GIT_DIR=".git/modules/$sm_name" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^," ", -e s,' (fetch)',, >&2
echo >&2 "$(eval_gettext "If you want to reuse this local git directory instead of cloning again from")"
echo >&2 " $realrepo"
echo >&2 "$(eval_gettext "use the '--force' option. If the local git directory is not the correct repo")"
die "$(eval_gettext "or you are unsure what this means choose another name with the '--name' option.")"
else
echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
fi
fi
module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" || exit
(
clear_local_git_env
cd "$sm_path" &&
Expand All @@ -359,13 +384,13 @@ Use -f if you really want to add it." >&2
esac
) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
fi
git config submodule."$sm_path".url "$realrepo"
git config submodule."$sm_name".url "$realrepo"

git add $force "$sm_path" ||
die "$(eval_gettext "Failed to add submodule '\$sm_path'")"

git config -f .gitmodules submodule."$sm_path".path "$sm_path" &&
git config -f .gitmodules submodule."$sm_path".url "$repo" &&
git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
git config -f .gitmodules submodule."$sm_name".url "$repo" &&
git add --force .gitmodules ||
die "$(eval_gettext "Failed to register submodule '\$sm_path'")"
}
Expand Down Expand Up @@ -594,7 +619,7 @@ Maybe you want to use 'update --init'?")"

if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
then
module_clone "$sm_path" "$url" "$reference"|| exit
module_clone "$sm_path" "$name" "$url" "$reference" || exit
cloned_modules="$cloned_modules;$name"
subsha1=
else
Expand Down
75 changes: 75 additions & 0 deletions t/t7400-submodule-basic.sh
Original file line number Diff line number Diff line change
Expand Up @@ -681,4 +681,79 @@ test_expect_success 'moving the superproject does not break submodules' '
)
'

test_expect_success 'submodule add --name allows to replace a submodule with another at the same path' '
(
cd addtest2 &&
(
cd repo &&
echo "$submodurl/repo" >expect &&
git config remote.origin.url >actual &&
test_cmp expect actual &&
echo "gitdir: ../.git/modules/repo" >expect &&
test_cmp expect .git
) &&
rm -rf repo &&
git rm repo &&
git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual &&
test ! -s actual &&
echo "gitdir: ../.git/modules/submod" >expect &&
test_cmp expect submod/.git &&
(
cd repo &&
echo "$submodurl/bare.git" >expect &&
git config remote.origin.url >actual &&
test_cmp expect actual &&
echo "gitdir: ../.git/modules/repo_new" >expect &&
test_cmp expect .git
) &&
echo "repo" >expect &&
git config -f .gitmodules submodule.repo.path >actual &&
test_cmp expect actual &&
git config -f .gitmodules submodule.repo_new.path >actual &&
test_cmp expect actual&&
echo "$submodurl/repo" >expect &&
git config -f .gitmodules submodule.repo.url >actual &&
test_cmp expect actual &&
echo "$submodurl/bare.git" >expect &&
git config -f .gitmodules submodule.repo_new.url >actual &&
test_cmp expect actual &&
echo "$submodurl/repo" >expect &&
git config submodule.repo.url >actual &&
test_cmp expect actual &&
echo "$submodurl/bare.git" >expect &&
git config submodule.repo_new.url >actual &&
test_cmp expect actual
)
'

test_expect_success 'submodule add with an existing name fails unless forced' '
(
cd addtest2 &&
rm -rf repo &&
git rm repo &&
test_must_fail git submodule add -q --name repo_new "$submodurl/repo.git" repo &&
test ! -d repo &&
echo "repo" >expect &&
git config -f .gitmodules submodule.repo_new.path >actual &&
test_cmp expect actual&&
echo "$submodurl/bare.git" >expect &&
git config -f .gitmodules submodule.repo_new.url >actual &&
test_cmp expect actual &&
echo "$submodurl/bare.git" >expect &&
git config submodule.repo_new.url >actual &&
test_cmp expect actual &&
git submodule add -f -q --name repo_new "$submodurl/repo.git" repo &&
test -d repo &&
echo "repo" >expect &&
git config -f .gitmodules submodule.repo_new.path >actual &&
test_cmp expect actual&&
echo "$submodurl/repo.git" >expect &&
git config -f .gitmodules submodule.repo_new.url >actual &&
test_cmp expect actual &&
echo "$submodurl/repo.git" >expect &&
git config submodule.repo_new.url >actual &&
test_cmp expect actual
)
'

test_done
2 changes: 1 addition & 1 deletion t/t7406-submodule-update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ test_expect_success 'submodule add properly re-creates deeper level submodules'
(cd super &&
git reset --hard master &&
rm -rf deeper/ &&
git submodule add ../submodule deeper/submodule
git submodule add --force ../submodule deeper/submodule
)
'

Expand Down

0 comments on commit fdb4d27

Please sign in to comment.