From: Colin Hinton <colinlewishinton@gmail.com>
To: git@vger.kernel.org
Cc: m@lfurio.us, gitster@pobox.com,
Colin Hinton <colinlewishinton@gmail.com>
Subject: [PATCH v2] fetch.c: defer fetch.followRemoteHEAD validation
Date: Fri, 25 Sep 2026 12:26:58 -0700 [thread overview]
Message-ID: <20260925192658.1166-1-colinlewishinton@gmail.com> (raw)
In-Reply-To: <20260922040047.2567-1-colinlewishinton@gmail.com>
The value of the fetch.followRemoteHEAD configuration variable is
validated while the configuration file is being parsed, which
produces a warning even when this particular "git fetch" invocation
will never consult it
Store the raw config string instead, and resolve/validate it lazily
at the one place in do_fetch() that actually uses it, so a stale or
mistyped fetch.followRemoteHEAD value only produces a warning when
this fetch would have consulted it.
Signed-off-by: Colin Hinton <colinlewishinton@gmail.com>
---
builtin/fetch.c | 67 +++++++++++++++++++++++--------------------------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/builtin/fetch.c b/builtin/fetch.c
index ab7db2be06..6a5254a9bc 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -103,7 +103,7 @@ static struct string_list negotiation_include = STRING_LIST_INIT_NODUP;
struct fetch_config {
enum display_format display_format;
- enum follow_remote_head_settings follow_remote_head;
+ char *follow_remote_head_raw;
int all;
int prune;
int prune_tags;
@@ -176,24 +176,31 @@ static int git_fetch_config(const char *k, const char *v,
}
if (!strcmp(k, "fetch.followremotehead")) {
- if (!v)
- return config_error_nonbool(k);
- else if (!strcmp(v, "never"))
- fetch_config->follow_remote_head = FOLLOW_REMOTE_NEVER;
- else if (!strcmp(v, "create"))
- fetch_config->follow_remote_head = FOLLOW_REMOTE_CREATE;
- else if (!strcmp(v, "warn"))
- fetch_config->follow_remote_head = FOLLOW_REMOTE_WARN;
- else if (!strcmp(v, "always"))
- fetch_config->follow_remote_head = FOLLOW_REMOTE_ALWAYS;
- else
- warning(_("unrecognized fetch.followRemoteHEAD value '%s' ignored"), v);
+ free(fetch_config->follow_remote_head_raw);
+ fetch_config->follow_remote_head_raw = xstrdup(v);
+
return 0;
}
return git_default_config(k, v, ctx, cb);
}
+static enum follow_remote_head_settings get_follow_remote_head(const char *setting)
+{
+ if (!setting)
+ die(_("missing value for 'fetch.followRemoteHEAD'"));
+ else if (!strcmp(setting, "never"))
+ return FOLLOW_REMOTE_NEVER;
+ else if (!strcmp(setting, "create"))
+ return FOLLOW_REMOTE_CREATE;
+ else if (!strcmp(setting, "warn"))
+ return FOLLOW_REMOTE_WARN;
+ else if (!strcmp(setting, "always"))
+ return FOLLOW_REMOTE_ALWAYS;
+ warning(_("unrecognized fetch.followRemoteHEAD value '%s' ignored"), setting);
+ return FOLLOW_REMOTE_UNCONFIGURED;
+}
+
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
{
BUG_ON_OPT_NEG(unset);
@@ -1918,11 +1925,10 @@ static int do_fetch(struct transport *transport,
TRANSPORT_LS_REFS_OPTIONS_INIT;
struct fetch_head fetch_head = { 0 };
struct strbuf err = STRBUF_INIT;
- int do_set_head = 0;
struct ref_update_display_info_array display_array = { 0 };
struct strmap rejected_refs = STRMAP_INIT;
int summary_width = 0;
- int follow_remote_head;
+ int follow_remote_head = FOLLOW_REMOTE_NEVER;
if (tags == TAGS_DEFAULT) {
if (transport->remote->fetch_tags == 2)
@@ -1938,22 +1944,6 @@ static int do_fetch(struct transport *transport,
goto cleanup;
}
- /*
- * NEEDSWORK: By the time this function executes, we have already parsed
- * all such followRemoteHEAD values from the external configuration,
- * potentially emitting warning messages for bogus values. Ideally, if
- * this fetch ends up not needing to consult these values, then git would
- * not ever output a value warning. (eg: when pulling from a URL directly -
- * rather than a configured remote, or when a remote's followRemoteHEAD
- * overrides the fallback fetch setting)
- */
- if (transport->remote->follow_remote_head)
- follow_remote_head = transport->remote->follow_remote_head;
- else if (config->follow_remote_head)
- follow_remote_head = config->follow_remote_head;
- else
- follow_remote_head = BUILTIN_FOLLOW_REMOTE_HEAD_DFLT;
-
if (rs->nr) {
refspec_ref_prefixes(rs, &transport_ls_refs_options.ref_prefixes);
} else {
@@ -1962,8 +1952,13 @@ static int do_fetch(struct transport *transport,
if (transport->remote->fetch.nr) {
refspec_ref_prefixes(&transport->remote->fetch,
&transport_ls_refs_options.ref_prefixes);
- if (follow_remote_head != FOLLOW_REMOTE_NEVER)
- do_set_head = 1;
+
+ if (transport->remote->follow_remote_head)
+ follow_remote_head = transport->remote->follow_remote_head;
+ else if (config->follow_remote_head_raw)
+ follow_remote_head = get_follow_remote_head(config->follow_remote_head_raw);
+ else
+ follow_remote_head = BUILTIN_FOLLOW_REMOTE_HEAD_DFLT;
}
if (branch && branch_has_merge_config(branch) &&
!strcmp(branch->remote_name, transport->remote->name)) {
@@ -1987,7 +1982,7 @@ static int do_fetch(struct transport *transport,
strvec_push(&transport_ls_refs_options.ref_prefixes,
"refs/tags/");
- if (do_set_head)
+ if (follow_remote_head != FOLLOW_REMOTE_NEVER)
strvec_push(&transport_ls_refs_options.ref_prefixes,
"HEAD");
@@ -2164,7 +2159,7 @@ static int do_fetch(struct transport *transport,
"you need to specify exactly one branch with the --set-upstream option"));
}
}
- if (do_set_head) {
+ if (follow_remote_head != FOLLOW_REMOTE_NEVER) {
/*
* Way too many cases where this can go wrong so let's just
* ignore errors and fail silently for now.
@@ -2509,7 +2504,7 @@ int cmd_fetch(int argc,
{
struct fetch_config config = {
.display_format = DISPLAY_FORMAT_FULL,
- .follow_remote_head = FOLLOW_REMOTE_UNCONFIGURED,
+ .follow_remote_head_raw = NULL,
.prune = -1,
.prune_tags = -1,
.show_forced_updates = 1,
--
2.55.0.windows.3
next prev parent reply other threads:[~2026-09-25 19:27 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 4:00 [PATCH] fetch.c: defer fetch.followRemoteHEAD validation Colin Hinton
2026-09-22 5:32 ` Junio C Hamano
2026-09-23 5:03 ` Colin Hinton
2026-09-24 7:50 ` Matt Hunter
2026-09-25 18:48 ` Colin Hinton
2026-09-24 7:50 ` Matt Hunter
2026-09-25 19:26 ` Colin Hinton [this message]
2026-09-25 19:40 ` [PATCH v2] " Junio C Hamano
2026-09-25 20:30 ` Colin Hinton
2026-09-30 4:21 ` Matt Hunter
2026-09-30 18:46 ` Junio C Hamano
2026-10-03 4:50 ` Colin Hinton
2026-09-25 23:06 ` [PATCH v3] " Colin Hinton
2026-10-03 23:14 ` [PATCH v4] " Colin Hinton
2026-10-04 13:27 ` Junio C Hamano
2026-10-04 15:40 ` Colin Hinton
2026-10-04 17:42 ` Junio C Hamano
2026-10-04 20:14 ` [PATCH v5] " Colin Hinton
2026-10-05 9:05 ` Matt Hunter
2026-10-05 13:07 ` Junio C Hamano
2026-10-06 3:22 ` [PATCH v6] " Colin Hinton
2026-10-07 16:50 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260925192658.1166-1-colinlewishinton@gmail.com \
--to=colinlewishinton@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=m@lfurio.us \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox