From: Harald Nordgren <redacted>
When a fetch has no refspec to work from, we decide what to fetch from
two sources: the remote's configured fetch refspec, and the current
branch's upstream, if it lives on that remote. For example, after
git clone --single-branch <url>
git switch -c work
git push -u origin work
the remote's refspec only covers "main", but a refspec-less "git fetch
origin" still fetches "work" into FETCH_HEAD, so that a plain "git
pull" finds the branch to merge. See 49ca2fba39 (fetch: add
branch.*.merge to default ref-prefix extension, 2022-09-08).
That "does this branch build on this remote" check was inlined for
just the current branch. Move it into its own function,
collect_upstream_from_remote(), so the same logic can be reused for
branches other than just the current one.
Signed-off-by: Harald Nordgren <redacted>
---
builtin/fetch.c | 18 ++++++++----------
remote.c | 15 +++++++++++++++
remote.h | 9 +++++++++
3 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 305934f5f4..31ec963db7 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1985,8 +1985,6 @@ static int do_fetch(struct transport *transport,
if (rs->nr) {
refspec_ref_prefixes(rs, &transport_ls_refs_options.ref_prefixes);
} else {
- struct branch *branch = branch_get(NULL);
-
if (transport->remote->fetch.nr) {
refspec_ref_prefixes(&transport->remote->fetch,
&transport_ls_refs_options.ref_prefixes);@@ -2001,14 +1999,14 @@ static int do_fetch(struct transport *transport,
else
follow_remote_head = BUILTIN_FOLLOW_REMOTE_HEAD_DFLT;
}
- if (branch && branch_has_merge_config(branch) &&
- !strcmp(branch->remote_name, transport->remote->name)) {
- int i;
- for (i = 0; i < branch->merge_nr; i++) {
- strvec_push(&transport_ls_refs_options.ref_prefixes,
- branch->merge[i]->src);
- }
- }
+
+ /*
+ * The configured refspec may not cover the current
+ * branch's upstream (e.g. a narrowed -t refspec), so
+ * make sure we can still fetch it regardless.
+ */
+ collect_upstream_from_remote(the_repository, transport->remote,
+ NULL, &transport_ls_refs_options.ref_prefixes);
/*
* If there are no refs specified to fetch, then we justdiff --git a/remote.c b/remote.c
index 9acab2e01a..d4259fe7f3 100644
--- a/remote.c
+++ b/remote.c
@@ -1899,6 +1899,21 @@ int branch_merge_matches(struct branch *branch,
return refname_match(branch->merge[i]->src, refname);
}
+void collect_upstream_from_remote(struct repository *repo,
+ const struct remote *remote,
+ const char *refname,
+ struct strvec *tracked)
+{
+ struct branch *branch = repo_branch_get(repo, refname);
+
+ if (!branch_has_merge_config(branch) ||
+ strcmp(branch->remote_name, remote->name))
+ return;
+
+ for (int i = 0; i < branch->merge_nr; i++)
+ strvec_push(tracked, branch->merge[i]->src);
+}
+
__attribute__((format (printf,2,3)))
static char *error_buf(struct strbuf *err, const char *fmt, ...)
{diff --git a/remote.h b/remote.h
index ac485a584d..003c8fd180 100644
--- a/remote.h
+++ b/remote.h
@@ -359,6 +359,15 @@ int branch_has_merge_config(struct branch *branch);
int branch_merge_matches(struct branch *, int n, const char *);
+/*
+ * If refname's branch builds on remote, add its upstream on remote to
+ * tracked. A NULL refname means the current branch.
+ */
+void collect_upstream_from_remote(struct repository *repo,
+ const struct remote *remote,
+ const char *refname,
+ struct strvec *tracked);
+
/* list of the remote in a group as configured */
struct remote_group_data {
const char *name;--
gitgitgadget