diff options
-rw-r--r-- | Documentation/git-submodule.txt | 16 | ||||
-rwxr-xr-x | git-submodule.sh | 83 | ||||
-rwxr-xr-x | t/t7400-submodule-basic.sh | 38 |
3 files changed, 78 insertions, 59 deletions
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index cb0424f77b..f8fb80f18b 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -23,15 +23,15 @@ status:: repository. This command is the default command for git-submodule. init:: - Initialize the submodules, i.e. clone the git repositories specified - in the .gitmodules file and checkout the submodule commits specified - in the index of the containing repository. This will make the - submodules HEAD be detached. + Initialize the submodules, i.e. register in .git/config each submodule + path and url found in .gitmodules. The key used in git/config is + `submodule.$path.url`. This command does not alter existing information + in .git/config. update:: - Update the initialized submodules, i.e. checkout the submodule commits - specified in the index of the containing repository. This will make - the submodules HEAD be detached. + Update the registered submodules, i.e. clone missing submodules and + checkout the commit specified in the index of the containing repository. + This will make the submodules HEAD be detached. OPTIONS @@ -50,7 +50,7 @@ OPTIONS FILES ----- -When cloning submodules, a .gitmodules file in the top-level directory +When initializing submodules, a .gitmodules file in the top-level directory of the containing repository is used to find the url of each submodule. This file should be formatted in the same way as $GIR_DIR/config. The key to each submodule url is "module.$path.url". diff --git a/git-submodule.sh b/git-submodule.sh index 6ed5a6ced2..8bdd99a2f3 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -25,8 +25,35 @@ say() fi } + # -# Run clone + checkout on missing submodules +# Clone a submodule +# +module_clone() +{ + path=$1 + url=$2 + + # If there already is a directory at the submodule path, + # expect it to be empty (since that is the default checkout + # action) and try to remove it. + # Note: if $path is a symlink to a directory the test will + # succeed but the rmdir will fail. We might want to fix this. + if test -d "$path" + then + rmdir "$path" 2>/dev/null || + die "Directory '$path' exist, but is neither empty nor a git repository" + fi + + test -e "$path" && + die "A file already exist at path '$path'" + + git-clone -n "$url" "$path" || + die "Clone of submodule '$path' failed" +} + +# +# Register submodules in .git/config # # $@ = requested paths (default to all) # @@ -35,52 +62,23 @@ modules_init() git ls-files --stage -- "$@" | grep -e '^160000 ' | while read mode sha1 stage path do - # Skip submodule paths that already contain a .git directory. - # This will also trigger if $path is a symlink to a git - # repository - test -d "$path"/.git && continue - - # If there already is a directory at the submodule path, - # expect it to be empty (since that is the default checkout - # action) and try to remove it. - # Note: if $path is a symlink to a directory the test will - # succeed but the rmdir will fail. We might want to fix this. - if test -d "$path" - then - rmdir "$path" 2>/dev/null || - die "Directory '$path' exist, but is neither empty nor a git repository" - fi - - test -e "$path" && - die "A file already exist at path '$path'" + # Skip already registered paths + url=$(git-config submodule."$path".url) + test -z "$url" || continue url=$(GIT_CONFIG=.gitmodules git-config module."$path".url) test -z "$url" && die "No url found for submodule '$path' in .gitmodules" - # MAYBE FIXME: this would be the place to check GIT_CONFIG - # for a preferred url for this submodule, possibly like this: - # - # modname=$(GIT_CONFIG=.gitmodules git-config module."$path".name) - # alturl=$(git-config module."$modname".url) - # - # This would let the versioned .gitmodules file use the submodule - # path as key, while the unversioned GIT_CONFIG would use the - # logical modulename (if present) as key. But this would need - # another fallback mechanism if the module wasn't named. - - git-clone -n "$url" "$path" || - die "Clone of submodule '$path' failed" + git-config submodule."$path".url "$url" || + die "Failed to register url for submodule '$path'" - (unset GIT_DIR && cd "$path" && git-checkout -q "$sha1") || - die "Checkout of submodule '$path' failed" - - say "Submodule '$path' initialized" + say "Submodule '$path' registered with url '$url'" done } # -# Checkout correct revision of each initialized submodule +# Update each submodule path to correct revision, using clone and checkout as needed # # $@ = requested paths (default to all) # @@ -89,14 +87,21 @@ modules_update() git ls-files --stage -- "$@" | grep -e '^160000 ' | while read mode sha1 stage path do - if ! test -d "$path"/.git + url=$(git-config submodule."$path".url) + if test -z "$url" then # Only mention uninitialized submodules when its # path have been specified test "$#" != "0" && say "Submodule '$path' not initialized" - continue; + continue fi + + if ! test -d "$path"/.git + then + module_clone "$path" "$url" || exit + fi + subsha1=$(unset GIT_DIR && cd "$path" && git-rev-parse --verify HEAD) || die "Unable to find current revision of submodule '$path'" diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 6274729729..3940433b8f 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -40,7 +40,7 @@ test_expect_success 'Prepare submodule testing' ' git-add a lib z && git-commit -m "super commit 1" && mv lib .subrepo && - GIT_CONFIG=.gitmodules git-config module.lib.url ./.subrepo + GIT_CONFIG=.gitmodules git-config module.lib.url git://example.com/lib.git ' test_expect_success 'status should only print one line' ' @@ -52,41 +52,55 @@ test_expect_success 'status should initially be "missing"' ' git-submodule status | grep "^-$rev1" ' -test_expect_success 'init should fail when path is used by a file' ' +test_expect_success 'init should register submodule url in .git/config' ' + git-submodule init && + url=$(git-config submodule.lib.url) && + if test "$url" != "git://example.com/lib.git" + then + echo "[OOPS] init succeeded but submodule url is wrong" + false + elif ! git-config submodule.lib.url ./.subrepo + then + echo "[OOPS] init succeeded but update of url failed" + false + fi +' + +test_expect_success 'update should fail when path is used by a file' ' echo "hello" >lib && - if git-submodule init + if git-submodule update then - echo "[OOPS] init should have failed" + echo "[OOPS] update should have failed" false elif test -f lib && test "$(cat lib)" != "hello" then - echo "[OOPS] init failed but lib file was molested" + echo "[OOPS] update failed but lib file was molested" false else rm lib fi ' -test_expect_success 'init should fail when path is used by a nonempty directory' ' +test_expect_success 'update should fail when path is used by a nonempty directory' ' mkdir lib && echo "hello" >lib/a && - if git-submodule init + if git-submodule update then - echo "[OOPS] init should have failed" + echo "[OOPS] update should have failed" false elif test "$(cat lib/a)" != "hello" then - echo "[OOPS] init failed but lib/a was molested" + echo "[OOPS] update failed but lib/a was molested" false else rm lib/a fi ' -test_expect_success 'init should work when path is an empty dir' ' +test_expect_success 'update should work when path is an empty dir' ' rm -rf lib && mkdir lib && - git-submodule init && + git-submodule update && head=$(cd lib && git-rev-parse HEAD) && if test -z "$head" then @@ -99,7 +113,7 @@ test_expect_success 'init should work when path is an empty dir' ' fi ' -test_expect_success 'status should be "up-to-date" after init' ' +test_expect_success 'status should be "up-to-date" after update' ' git-submodule status | grep "^ $rev1" ' |