Thread (7 messages) 7 messages, 3 authors, 2026-02-08

Re: [PATCH v27 2/2] status: add status.compareBranches config for multiple branch comparisons

From: Jeff King <hidden>
Date: 2026-01-22 23:06:59
Subsystem: the rest · Maintainer: Linus Torvalds

Possibly related (same subject, not in this thread)

On Thu, Jan 22, 2026 at 05:44:27PM -0500, Jeff King wrote:
The second issue concerns the case when an upstream is configured, but
the tracking ref for it is missing. So imagine "foo" is configured with
"refs/remotes/origin/foo" as its upstream, but that branch is gone.

Using branch_get_upstream() will return the name, even if it doesn't
exist. And then the tracking-info code recognizes this and reports it.
But repo_dwim_ref() won't return a missing ref at all, even with
nonfatal_dangling_mark. So I think we'd need to teach it a new option to
do so.
So I think that nonfatal_dangling_mark could arguably return the name
(but no oid) for this case, like so:
diff --git a/refs.c b/refs.c
index 627b7f8698..2316d0b8a9 100644
--- a/refs.c
+++ b/refs.c
@@ -813,7 +813,13 @@ int repo_dwim_ref(struct repository *r, const char *str, int len,
 	char *last_branch = substitute_branch_name(r, &str, &len,
 						   nonfatal_dangling_mark);
 	int   refs_found  = expand_ref(r, str, len, oid, ref);
-	free(last_branch);
+	if (nonfatal_dangling_mark && !refs_found && last_branch) {
+		oidclr(oid, r->hash_algo);
+		*ref = last_branch;
+		refs_found = 1;
+	} else {
+		free(last_branch);
+	}
 	return refs_found;
 }
 
But this brings up yet another corner case: substitute_branch_name()
will call shorten_unambiguous_ref() on the result when expanding
@-marks. So last_branch here might be "origin/foo" instead of
"refs/remotes/origin/foo". It's usually not a big deal because
expand_ref() will then reverse that shortening.  Which is maybe
wasteful, but not so bad (though if somebody racily creates an ambiguous
ref, it could affect the results).

But if we return last_branch explicitly, then information is lost: we
don't know what the fully-qualified version of "origin/foo" was supposed
to be. And so the tracking-info code gets confused, because it doesn't
realize that "origin/foo" was supposed to be our @{upstream}.

I think probably the interpret_branch_name() code should have an option
to avoid that shortening. So if we do this on top:
diff --git a/object-name.c b/object-name.c
index 8b862c124e..0663946f81 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1747,7 +1747,12 @@ static int interpret_branch_mark(struct repository *r,
 	if (!branch_interpret_allowed(value, options->allowed))
 		return -1;
 
-	set_shortened_ref(r, buf, value);
+	if (options->do_not_shorten) {
+		strbuf_reset(buf);
+		strbuf_addstr(buf, value);
+	} else {
+		set_shortened_ref(r, buf, value);
+	}
 	return len + at;
 }
 
diff --git a/object-name.h b/object-name.h
index cda4934cd5..20393cb213 100644
--- a/object-name.h
+++ b/object-name.h
@@ -119,6 +119,8 @@ struct interpret_branch_name_options {
 	 * of die()-ing.
 	 */
 	unsigned nonfatal_dangling_mark : 1;
+
+	unsigned do_not_shorten : 1;
 };
 int repo_interpret_branch_name(struct repository *r,
 			       const char *str, int len,
diff --git a/refs.c b/refs.c
index 2316d0b8a9..58f945e213 100644
--- a/refs.c
+++ b/refs.c
@@ -746,6 +746,7 @@ static char *substitute_branch_name(struct repository *r,
 {
 	struct strbuf buf = STRBUF_INIT;
 	struct interpret_branch_name_options options = {
+		.do_not_shorten = 1,
 		.nonfatal_dangling_mark = nonfatal_dangling_mark
 	};
 	int ret = repo_interpret_branch_name(r, *string, *len, &buf, &options);
then all of t6040 passes (curiously without me swapping in "%s@{push}"
as appropriate; I guess we are often on the branch of interest anyway,
so it accidentally works with just @{push}).


So I don't love how deep the rabbit-hole has gone here. But at the same
time, it feels like all of these "if we just do this on top" fixes are
actually smoothing some rough edges in the rest of Git. So maybe it's
worth it.

-Peff
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help