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
{
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 *);
{"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)
'')
git fetch ;;
*)
- git fetch $(get_default_remote) "$2" ;;
+ shift
+ git fetch $(get_default_remote) "$@" ;;
esac
)
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
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)
# 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
{
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);
}
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);
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);
}
}
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];
)
'
+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 &&
'
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' '