git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCHv2 10/10] branch: Fix display of remote branches in refs/peers/*

From
Johan Herland <johan@herland.net>
Date
May 11, 2013, 16:21 UTC
Message-ID
<1368289280-30337-11-git-send-email-johan@herland.net>
In-Reply-To
<1368289280-30337-1-git-send-email-johan@herland.net>

The current branch display code assumes all remote-tracking branches live inside refs/remotes/*, and that their appropriate shorthand names can be retrieved by simply stripping off the "refs/remotes/" prefix.

When we add remote-tracking branches in refs/peers/$remote/heads/*, the code must not only be taught how to list refs from the new location, but also how to appropriately derive shorthand names for the remote-tracking branches there (instead of stripping off a hardcoded prefix, we must use the refname_shorten() function introduced in an earlier patch.)

There is already a good set of tests for the expected output from git branch, and this patch does not break any of them. However, we do fix the two tests with remote-tracking branches in refs/peers/* introduced in a previous patch.

Signed-off-by: Johan Herland <johan@herland.net>
---
 builtin/branch.c                               | 66 ++++++++++++++------------
 refs.c                                         |  4 +-
 refs.h                                         |  3 ++
 t/t7900-working-with-namespaced-remote-refs.sh |  4 +-
 4 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index 4480be2..9a6bce8 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -290,18 +290,16 @@ struct ref_list {
 	int kinds;
 };
 
-static char *resolve_symref(const char *src, const char *prefix)
+static void resolve_symref(struct strbuf *shortname, const char *pattern, const char *src)
 {
 	unsigned char sha1[20];
 	int flag;
-	const char *dst, *cp;
+	const char *dst;
 
 	dst = resolve_ref_unsafe(src, sha1, 0, &flag);
-	if (!(dst && (flag & REF_ISSYMREF)))
-		return NULL;
-	if (prefix && (cp = skip_prefix(dst, prefix)))
-		dst = cp;
-	return xstrdup(dst);
+	if (dst && (flag & REF_ISSYMREF) &&
+	    refname_shorten(shortname, pattern, dst, strlen(dst)))
+		strbuf_addstr(shortname, dst);
 }
 
 struct append_ref_cb {
@@ -328,74 +326,80 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
 	struct ref_list *ref_list = cb->ref_list;
 	struct ref_item *newitem;
 	struct commit *commit;
+	struct strbuf ref = STRBUF_INIT;
 	int kind, i;
-	const char *prefix, *orig_refname = refname;
+	const char *pattern;
+	size_t refname_len = strlen(refname);
 
 	static struct {
 		int kind;
-		const char *prefix;
-		int pfxlen;
+		const char *pattern;
 	} ref_kind[] = {
-		{ REF_LOCAL_BRANCH, "refs/heads/", 11 },
-		{ REF_REMOTE_BRANCH, "refs/remotes/", 13 },
+		{ REF_LOCAL_BRANCH, "refs/heads/%*" },
+		{ REF_REMOTE_BRANCH, "refs/remotes/%*" },
+		{ REF_REMOTE_BRANCH, "refs/peers/%1/heads/%*" },
 	};
 
 	/* Detect kind */
 	for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
-		prefix = ref_kind[i].prefix;
-		if (strncmp(refname, prefix, ref_kind[i].pfxlen))
+		if (refname_shorten(&ref, ref_kind[i].pattern, refname, refname_len))
 			continue;
 		kind = ref_kind[i].kind;
-		refname += ref_kind[i].pfxlen;
+		pattern = ref_kind[i].pattern;
 		break;
 	}
 	if (ARRAY_SIZE(ref_kind) <= i)
-		return 0;
+		goto out;
 
 	/* Don't add types the caller doesn't want */
 	if ((kind & ref_list->kinds) == 0)
-		return 0;
+		goto out;
 
-	if (!match_patterns(cb->pattern, refname))
-		return 0;
+	if (!match_patterns(cb->pattern, ref.buf))
+		goto out;
 
 	commit = NULL;
 	if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
 		commit = lookup_commit_reference_gently(sha1, 1);
 		if (!commit) {
-			cb->ret = error(_("branch '%s' does not point at a commit"), refname);
-			return 0;
+			cb->ret = error(_("branch '%s' does not point at a commit"), ref.buf);
+			goto out;
 		}
 
 		/* Filter with with_commit if specified */
 		if (!is_descendant_of(commit, ref_list->with_commit))
-			return 0;
+			goto out;
 
 		if (merge_filter != NO_FILTER)
 			add_pending_object(&ref_list->revs,
-					   (struct object *)commit, refname);
+					   (struct object *)commit, ref.buf);
 	}
 
+	/*
+	 * When displaying more then just remote-tracking branches, make the
+	 * remote-tracking branches more explicit, e.g. instead of printing
+	 * "origin/master", we should print "remote/origin/master" (or
+	 * "peers/origin/heads/master").
+	 */
+	if (kind == REF_REMOTE_BRANCH && ref_list->kinds != REF_REMOTE_BRANCH)
+		refname_shorten(&ref, "refs/%*", refname, refname_len);
+
 	ALLOC_GROW(ref_list->list, ref_list->index + 1, ref_list->alloc);
 
 	/* Record the new item */
 	newitem = &(ref_list->list[ref_list->index++]);
 	strbuf_init(&newitem->name, 0);
-	strbuf_addstr(&newitem->name, refname);
+	strbuf_addbuf(&newitem->name, &ref);
 	newitem->kind = kind;
 	newitem->commit = commit;
 	strbuf_init(&newitem->dest, 0);
-	orig_refname = resolve_symref(orig_refname, prefix);
-	if (orig_refname)
-		strbuf_addstr(&newitem->dest, orig_refname);
-	/* adjust for "remotes/" */
-	if (newitem->kind == REF_REMOTE_BRANCH &&
-	    ref_list->kinds != REF_REMOTE_BRANCH)
-		strbuf_insert(&newitem->name, 0, "remotes/", 8);
+	resolve_symref(&newitem->dest, pattern, refname);
 	newitem->width = utf8_strwidth(newitem->name.buf);
 	if (newitem->width > ref_list->maxwidth)
 		ref_list->maxwidth = newitem->width;
 
+out:
+	strbuf_release(&ref);
 	return 0;
 }
 
diff --git a/refs.c b/refs.c
index 188a9eb..a78199a 100644
--- a/refs.c
+++ b/refs.c
@@ -1873,8 +1873,8 @@ static int handle_fragment(struct strbuf *dst, struct strbuf *fragment,
 	return (ref - refname) + trail_len;
 }
 
-static int refname_shorten(struct strbuf *dst, const char *pattern,
-			   const char *refname, size_t refname_len)
+int refname_shorten(struct strbuf *dst, const char *pattern,
+		    const char *refname, size_t refname_len)
 {
 	/*
 	 * Match refname against pattern, using "%*" as wildcard, and
diff --git a/refs.h b/refs.h
index e05c1f1..245d53d 100644
--- a/refs.h
+++ b/refs.h
@@ -165,6 +165,9 @@ extern int check_refname_format(const char *refname, int flags);
 
 extern const char *prettify_refname(const char *refname);
 
+extern int refname_shorten(struct strbuf *dst, const char *pattern,
+			   const char *refname, size_t refname_len);
+
 extern int refname_match(const char *abbrev_name, const char *full_name);
 
 extern char *shorten_unambiguous_ref(const char *refname, int strict);
diff --git a/t/t7900-working-with-namespaced-remote-refs.sh b/t/t7900-working-with-namespaced-remote-refs.sh
index 279664c..450b193 100755
--- a/t/t7900-working-with-namespaced-remote-refs.sh
+++ b/t/t7900-working-with-namespaced-remote-refs.sh
@@ -112,7 +112,7 @@ cat >expect.branch-r << EOF
   origin/other
 EOF
 
-test_expect_failure 'git branch -r should show remote-tracking branches' '
+test_expect_success 'git branch -r should show remote-tracking branches' '
 	git branch -r >actual.branch-r &&
 	test_cmp expect.branch-r actual.branch-r
 '
@@ -123,7 +123,7 @@ cat >expect.branch-a << EOF
   peers/origin/heads/other
 EOF
 
-test_expect_failure 'git branch -a should also show remote-tracking branches' '
+test_expect_success 'git branch -a should also show remote-tracking branches' '
 	git branch -a >actual.branch-a &&
 	test_cmp expect.branch-a actual.branch-a
 '
-- 
1.8.1.3.704.g33f7d4f
Previous: Johan HerlandNext: Eric Sunshine
Message 29 of 31 in “[PATCHv2 00/10] Prepare for alternative remote-tracking branch location”
  1. Johan HerlandMay 11, 2013
  2. 01/10 t7900: Start testing usability of namespaced remote refsJohan Herland, May 11, 2013
  3. 02/10 t7900: Demonstrate failure to expand "$peer/$branch" according to refspecsJohan Herland, May 11, 2013
  4. 03/10 refs.c: Refactor code for mapping between shorthand names and full refnamesJohan Herland, May 11, 2013
  5. Junio C HamanoMay 13, 2013
  6. Johan HerlandMay 13, 2013
  7. Junio C HamanoMay 13, 2013
  8. Junio C HamanoMay 13, 2013
  9. Johan HerlandMay 14, 2013
  10. Junio C HamanoMay 14, 2013
  11. Michael HaggertyMay 15, 2013
  12. Johan HerlandMay 15, 2013
  13. Johan HerlandMay 15, 2013
  14. Junio C HamanoMay 15, 2013
  15. Eric WongMay 15, 2013
  16. 04/10 remote: Reject remote names containing '/'Johan Herland, May 11, 2013
  17. Eric SunshineMay 13, 2013
  18. Johan HerlandMay 13, 2013
  19. Junio C HamanoMay 13, 2013
  20. Johan HerlandMay 13, 2013
  21. Ramkumar RamachandraMay 16, 2013
  22. Johan HerlandMay 16, 2013
  23. Ramkumar RamachandraMay 16, 2013
  24. 05/10 refs.c: Add support for expanding/shortening refs in refs/peers/*Johan Herland, May 11, 2013
  25. 06/10 t7900: Test git branch -r/-a output w/remote-tracking branches in refs/peers/*Johan Herland, May 11, 2013
  26. 07/10 t3203: Add testcase for fix in 1603ade81352a526ccb206f41ff81ecbc855df2dJohan Herland, May 11, 2013
  27. 08/10 builtin/branch.c: Refactor ref_item.name and .dest into strbufsJohan Herland, May 11, 2013
  28. 09/10 builtin/branch.c: Refactor "remotes/" prepending to remote-tracking branchesJohan Herland, May 11, 2013
  29. 10/10 branch: Fix display of remote branches in refs/peers/*Johan Herland, May 11, 2013
  30. Eric SunshineMay 13, 2013
  31. Johan HerlandMay 13, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.