How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`.
The default value is "create", which will create `remotes/<name>/HEAD`
if it exists on the remote, but not locally, but will not touch an
- already existing local reference. Setting to "warn" will print
+ already existing local reference. Setting to "warn" will print
a message if the remote has a different value, than the local one and
- in case there is no local reference, it behaves like "create". Setting
- to "always" will silently update it to the value on the remote.
+ in case there is no local reference, it behaves like "create".
+ A variant on "warn" is "warn-if-not-$branch", which behaves like
+ "warn", but if `HEAD` on the remote is `$branch` it will be silent.
+ Setting to "always" will silently update it to the value on the remote.
Finally, setting it to "never" will never change or create the local
reference.
+
const char message_advice_set_head[] =
N_("Run 'git remote set-head %s %s' to follow the change, or set\n"
"'remote.%s.followRemoteHEAD' configuration option to a different value\n"
- "if you do not want to see this message.");
+ "if you do not want to see this message. Specifically running\n"
+ "'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
+ "until the remote changes HEAD to something else.");
advise_if_enabled(ADVICE_FETCH_SET_HEAD_WARN, _(message_advice_set_head),
- remote, head_name, remote);
+ remote, head_name, remote, remote, head_name);
}
static void report_set_head(const char *remote, const char *head_name,
strbuf_release(&buf_prefix);
}
-static int set_head(const struct ref *remote_refs, int follow_remote_head)
+static int set_head(const struct ref *remote_refs, int follow_remote_head,
+ const char *no_warn_branch)
{
int result = 0, create_only, is_bare, was_detached;
struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
result = 1;
goto cleanup;
}
- if (follow_remote_head == FOLLOW_REMOTE_WARN && verbosity >= 0)
+ if (verbosity >= 0 &&
+ follow_remote_head == FOLLOW_REMOTE_WARN &&
+ (!no_warn_branch || strcmp(no_warn_branch, head_name)))
report_set_head(remote, head_name, &b_local_head, was_detached);
cleanup:
"you need to specify exactly one branch with the --set-upstream option"));
}
}
- if (set_head(remote_refs, transport->remote->follow_remote_head))
+ if (set_head(remote_refs, transport->remote->follow_remote_head,
+ transport->remote->no_warn_branch))
;
/*
* Way too many cases where this can go wrong
return parse_transport_option(key, value,
&remote->server_options);
} else if (!strcmp(subkey, "followremotehead")) {
+ const char *no_warn_branch;
if (!strcmp(value, "never"))
remote->follow_remote_head = FOLLOW_REMOTE_NEVER;
else if (!strcmp(value, "create"))
remote->follow_remote_head = FOLLOW_REMOTE_CREATE;
- else if (!strcmp(value, "warn"))
+ else if (!strcmp(value, "warn")) {
remote->follow_remote_head = FOLLOW_REMOTE_WARN;
- else if (!strcmp(value, "always"))
+ remote->no_warn_branch = NULL;
+ } else if (skip_prefix(value, "warn-if-not-", &no_warn_branch)) {
+ remote->follow_remote_head = FOLLOW_REMOTE_WARN;
+ remote->no_warn_branch = no_warn_branch;
+ } else if (!strcmp(value, "always")) {
remote->follow_remote_head = FOLLOW_REMOTE_ALWAYS;
+ } else {
+ warning(_("unrecognized followRemoteHEAD value '%s' ignored"),
+ value);
+ }
}
return 0;
}
struct string_list server_options;
enum follow_remote_head_settings follow_remote_head;
+ const char *no_warn_branch;
};
/**
)
'
+test_expect_success "fetch test followRemoteHEAD warn-if-not-branch branch is same" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git config set remote.origin.followRemoteHEAD "warn-if-not-main" &&
+ actual=$(git fetch) &&
+ test "z" = "z$actual" &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/other) &&
+ test "z$head" = "z$branch"
+ )
+'
+
+test_expect_success "fetch test followRemoteHEAD warn-if-not-branch branch is different" '
+ test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
+ (
+ cd "$D" &&
+ cd two &&
+ git rev-parse --verify refs/remotes/origin/other &&
+ git remote set-head origin other &&
+ git rev-parse --verify refs/remotes/origin/HEAD &&
+ git rev-parse --verify refs/remotes/origin/main &&
+ git config set remote.origin.followRemoteHEAD "warn-if-not-some/different-branch" &&
+ git fetch >actual &&
+ echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \
+ "but we have ${SQ}other${SQ} locally." >expect &&
+ test_cmp expect actual &&
+ head=$(git rev-parse refs/remotes/origin/HEAD) &&
+ branch=$(git rev-parse refs/remotes/origin/other) &&
+ test "z$head" = "z$branch"
+ )
+'
+
test_expect_success "fetch test followRemoteHEAD always" '
test_when_finished "git config unset remote.origin.followRemoteHEAD" &&
(