Merge branch 'sb/submodule-update-dot-branch'
authorJunio C Hamano <gitster@pobox.com>
Wed, 10 Aug 2016 19:33:20 +0000 (12:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 10 Aug 2016 19:33:20 +0000 (12:33 -0700)
A few updates to "git submodule update".

Use of "| wc -l" break with BSD variant of 'wc'.

* sb/submodule-update-dot-branch:
t7406: fix breakage on OSX
submodule update: allow '.' for branch value
submodule--helper: add remote-branch helper
submodule-config: keep configured branch around
submodule--helper: fix usage string for relative-path
submodule update: narrow scope of local variable
submodule update: respect depth in subsequent fetches
t7406: future proof tests with hard coded depth

builtin/submodule--helper.c
git-submodule.sh
submodule-config.c
submodule-config.h
t/t7406-submodule-update.sh
index 6f6d67a4694a83f18f86f5de2d9d64fd4e449a5e..b09632e468e6b64e0329a685e0f3ba7517884c5c 100644 (file)
@@ -892,13 +892,64 @@ static int resolve_relative_path(int argc, const char **argv, const char *prefix
 {
        struct strbuf sb = STRBUF_INIT;
        if (argc != 3)
-               die("submodule--helper relative_path takes exactly 2 arguments, got %d", argc);
+               die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
 
        printf("%s", relative_path(argv[1], argv[2], &sb));
        strbuf_release(&sb);
        return 0;
 }
 
+static const char *remote_submodule_branch(const char *path)
+{
+       const struct submodule *sub;
+       gitmodules_config();
+       git_config(submodule_config, NULL);
+
+       sub = submodule_from_path(null_sha1, path);
+       if (!sub)
+               return NULL;
+
+       if (!sub->branch)
+               return "master";
+
+       if (!strcmp(sub->branch, ".")) {
+               unsigned char sha1[20];
+               const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+
+               if (!refname)
+                       die(_("No such ref: %s"), "HEAD");
+
+               /* detached HEAD */
+               if (!strcmp(refname, "HEAD"))
+                       die(_("Submodule (%s) branch configured to inherit "
+                             "branch from superproject, but the superproject "
+                             "is not on any branch"), sub->name);
+
+               if (!skip_prefix(refname, "refs/heads/", &refname))
+                       die(_("Expecting a full ref name, got %s"), refname);
+               return refname;
+       }
+
+       return sub->branch;
+}
+
+static int resolve_remote_submodule_branch(int argc, const char **argv,
+               const char *prefix)
+{
+       const char *ret;
+       struct strbuf sb = STRBUF_INIT;
+       if (argc != 2)
+               die("submodule--helper remote-branch takes exactly one arguments, got %d", argc);
+
+       ret = remote_submodule_branch(argv[1]);
+       if (!ret)
+               die("submodule %s doesn't exist", argv[1]);
+
+       printf("%s", ret);
+       strbuf_release(&sb);
+       return 0;
+}
+
 struct cmd_struct {
        const char *cmd;
        int (*fn)(int, const char **, const char *);
@@ -912,7 +963,8 @@ static struct cmd_struct commands[] = {
        {"relative-path", resolve_relative_path},
        {"resolve-relative-url", resolve_relative_url},
        {"resolve-relative-url-test", resolve_relative_url_test},
-       {"init", module_init}
+       {"init", module_init},
+       {"remote-branch", resolve_remote_submodule_branch}
 };
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
index c90dc335d145fa0a16efbe41873a525b596b806d..b57f87de658b627c48ec672faaab3dc6aac3b505 100755 (executable)
@@ -479,7 +479,8 @@ fetch_in_submodule () (
        '')
                git fetch ;;
        *)
-               git fetch $(get_default_remote) "$2" ;;
+               shift
+               git fetch $(get_default_remote) "$@" ;;
        esac
 )
 
@@ -588,7 +589,6 @@ cmd_update()
 
                name=$(git submodule--helper name "$sm_path") || exit
                url=$(git config submodule."$name".url)
-               branch=$(get_submodule_config "$name" branch master)
                if ! test -z "$update"
                then
                        update_module=$update
@@ -614,10 +614,11 @@ cmd_update()
 
                if test -n "$remote"
                then
+                       branch=$(git submodule--helper remote-branch "$sm_path")
                        if test -z "$nofetch"
                        then
                                # Fetch remote before determining tracking $sha1
-                               fetch_in_submodule "$sm_path" ||
+                               fetch_in_submodule "$sm_path" $depth ||
                                die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
                        fi
                        remote_name=$(sanitize_submodule_env; cd "$sm_path" && get_default_remote)
@@ -640,13 +641,13 @@ cmd_update()
                                # Run fetch only if $sha1 isn't present or it
                                # is not reachable from a ref.
                                is_tip_reachable "$sm_path" "$sha1" ||
-                               fetch_in_submodule "$sm_path" ||
+                               fetch_in_submodule "$sm_path" $depth ||
                                die "$(eval_gettext "Unable to fetch in submodule path '\$displaypath'")"
 
                                # Now we tried the usual fetch, but $sha1 may
                                # not be reachable from any of the refs
                                is_tip_reachable "$sm_path" "$sha1" ||
-                               fetch_in_submodule "$sm_path" "$sha1" ||
+                               fetch_in_submodule "$sm_path" $depth "$sha1" ||
                                die "$(eval_gettext "Fetched in submodule path '\$displaypath', but it did not contain \$sha1. Direct fetching of that commit failed.")"
                        fi
 
index d22a851d2705fc44c608cdde1c31bea40b454ebb..098085be69b97687b0febfe9e29c6dc0c64569a1 100644 (file)
@@ -59,6 +59,7 @@ static void free_one_config(struct submodule_entry *entry)
 {
        free((void *) entry->config->path);
        free((void *) entry->config->name);
+       free((void *) entry->config->branch);
        free((void *) entry->config->update_strategy.command);
        free(entry->config);
 }
@@ -199,6 +200,7 @@ static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
        submodule->update_strategy.command = NULL;
        submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
        submodule->ignore = NULL;
+       submodule->branch = NULL;
        submodule->recommend_shallow = -1;
 
        hashcpy(submodule->gitmodules_sha1, gitmodules_sha1);
@@ -358,9 +360,16 @@ static int parse_config(const char *var, const char *value, void *data)
                if (!me->overwrite && submodule->recommend_shallow != -1)
                        warn_multiple_config(me->commit_sha1, submodule->name,
                                             "shallow");
-               else {
+               else
                        submodule->recommend_shallow =
                                git_config_bool(var, value);
+       } else if (!strcmp(item.buf, "branch")) {
+               if (!me->overwrite && submodule->branch)
+                       warn_multiple_config(me->commit_sha1, submodule->name,
+                                            "branch");
+               else {
+                       free((void *)submodule->branch);
+                       submodule->branch = xstrdup(value);
                }
        }
 
index b1fdcc0c33326f556d23ce65ad21b01514fcb927..d05c542d2cdace181ea72055c0f71db6b1afda42 100644 (file)
@@ -15,6 +15,7 @@ struct submodule {
        const char *url;
        int fetch_recurse;
        const char *ignore;
+       const char *branch;
        struct submodule_update_strategy update_strategy;
        /* the sha1 blob id of the responsible .gitmodules file */
        unsigned char gitmodules_sha1[20];
index 88e9750abb2f2c0346385439e305dd07ec795a41..64f322c4cc87493ebc060ae5837495563fe61958 100755 (executable)
@@ -209,9 +209,42 @@ test_expect_success 'submodule update --remote should fetch upstream changes' '
        )
 '
 
+test_expect_success 'submodule update --remote should fetch upstream changes with .' '
+       (
+               cd super &&
+               git config -f .gitmodules submodule."submodule".branch "." &&
+               git add .gitmodules &&
+               git commit -m "submodules: update from the respective superproject branch"
+       ) &&
+       (
+               cd submodule &&
+               echo line4a >> file &&
+               git add file &&
+               test_tick &&
+               git commit -m "upstream line4a" &&
+               git checkout -b test-branch &&
+               test_commit on-test-branch
+       ) &&
+       (
+               cd super &&
+               git submodule update --remote --force submodule &&
+               git -C submodule log -1 --oneline >actual
+               git -C ../submodule log -1 --oneline master >expect
+               test_cmp expect actual &&
+               git checkout -b test-branch &&
+               git submodule update --remote --force submodule &&
+               git -C submodule log -1 --oneline >actual
+               git -C ../submodule log -1 --oneline test-branch >expect
+               test_cmp expect actual &&
+               git checkout master &&
+               git branch -d test-branch &&
+               git reset --hard HEAD^
+       )
+'
+
 test_expect_success 'local config should override .gitmodules branch' '
        (cd submodule &&
-        git checkout -b test-branch &&
+        git checkout test-branch &&
         echo line5 >> file &&
         git add file &&
         test_tick &&
@@ -841,16 +874,35 @@ test_expect_success SYMLINKS 'submodule update can handle symbolic links in pwd'
 '
 
 test_expect_success 'submodule update clone shallow submodule' '
+       test_when_finished "rm -rf super3" &&
+       first=$(git -C cloned submodule status submodule |cut -c2-41) &&
+       second=$(git -C submodule rev-parse HEAD) &&
+       commit_count=$(git -C submodule rev-list --count $first^..$second) &&
        git clone cloned super3 &&
        pwd=$(pwd) &&
-       (cd super3 &&
-        sed -e "s#url = ../#url = file://$pwd/#" <.gitmodules >.gitmodules.tmp &&
-        mv -f .gitmodules.tmp .gitmodules &&
-        git submodule update --init --depth=3
-        (cd submodule &&
-         test 1 = $(git log --oneline | wc -l)
-        )
-)
+       (
+               cd super3 &&
+               sed -e "s#url = ../#url = file://$pwd/#" <.gitmodules >.gitmodules.tmp &&
+               mv -f .gitmodules.tmp .gitmodules &&
+               git submodule update --init --depth=$commit_count &&
+               test 1 = $(git -C submodule log --oneline | wc -l)
+       )
+'
+
+test_expect_success 'submodule update clone shallow submodule outside of depth' '
+       test_when_finished "rm -rf super3" &&
+       git clone cloned super3 &&
+       pwd=$(pwd) &&
+       (
+               cd super3 &&
+               sed -e "s#url = ../#url = file://$pwd/#" <.gitmodules >.gitmodules.tmp &&
+               mv -f .gitmodules.tmp .gitmodules &&
+               test_must_fail git submodule update --init --depth=1 2>actual &&
+               test_i18ngrep "Direct fetching of that commit failed." actual &&
+               git -C ../submodule config uploadpack.allowReachableSHA1InWant true &&
+               git submodule update --init --depth=1 >actual &&
+               test 1 = $(git -C submodule log --oneline | wc -l)
+       )
 '
 
 test_expect_success 'submodule update --recursive drops module name before recursing' '