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

[PATCH 1/4] ref-filter: factor out refname component counting

From
Jeff King <peff@peff.net>
Date
Feb 15, 2026, 09:00 UTC
Message-ID
<20260215090052.GA695631@coredump.intra.peff.net>
In-Reply-To
<20260215085755.GA86262@coredump.intra.peff.net>

The "lstrip" and "rstrip" options to the %(refname) placeholder both accept a negative length, which asks us to keep that many path components (rather than stripping that many).

The code to count components and convert the negative value to a positive was copied from lstrip to rstrip in 1a34728e6b (ref-filter: add an 'rstrip=<N>' option to atoms which deal with refnames, 2017-01-10).

Let's factor it out into a separate function. This reduces duplication and also makes the lstrip/rstrip functions much easier to follow, since the bulk of their code is now the actual stripping.

Note that the computed "remaining" value is currently stored as a "long", so in theory that's what our function should return. But this is purely historical. When the variable was added in 0571979bd6 (tag: do not show ambiguous tag names as "tags/foo", 2016-01-25), we parsed the value from strtol(), and thus used a long. But these days we take "len" as an int, and also use an int to count up components. So let's just consistently use int here. This value could only overflow in a pathological case (e.g., 4GB worth of "a/a/...") and even then will not result in out-of-bounds memory access (we keep stripping until we run out of string to parse).

The minimal Myers diff here is a little hard to read; with --patience the code movement is shown much more clearly.

Signed-off-by: Jeff King <peff@peff.net>
---
I did generate this with --patience. Using --color-words also helps show
that it's a pure code movement.
 ref-filter.c | 56 +++++++++++++++++++++-------------------------------
 1 file changed, 22 insertions(+), 34 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 3917c4ccd9..9153331f42 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2173,28 +2173,32 @@ static inline char *copy_advance(char *dst, const char *src)
 	return dst;
 }
 
+static int normalize_component_count(const char *refname, int len)
+{
+	if (len < 0) {
+		int i;
+		const char *p = refname;
+
+		/* Find total no of '/' separated path-components */
+		for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
+			;
+		/*
+		 * The number of components we need to strip is now
+		 * the total minus the components to be left (Plus one
+		 * because we count the number of '/', but the number
+		 * of components is one more than the no of '/').
+		 */
+		len = i + len + 1;
+	}
+	return len;
+}
+
 static const char *lstrip_ref_components(const char *refname, int len)
 {
-	long remaining = len;
+	int remaining = normalize_component_count(refname, len);
 	const char *start = xstrdup(refname);
 	const char *to_free = start;
 
-	if (len < 0) {
-		int i;
-		const char *p = refname;
-
-		/* Find total no of '/' separated path-components */
-		for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
-			;
-		/*
-		 * The number of components we need to strip is now
-		 * the total minus the components to be left (Plus one
-		 * because we count the number of '/', but the number
-		 * of components is one more than the no of '/').
-		 */
-		remaining = i + len + 1;
-	}
-
 	while (remaining > 0) {
 		switch (*start++) {
 		case '\0':
@@ -2213,26 +2217,10 @@ static const char *lstrip_ref_components(const char *refname, int len)
 
 static const char *rstrip_ref_components(const char *refname, int len)
 {
-	long remaining = len;
+	int remaining = normalize_component_count(refname, len);
 	const char *start = xstrdup(refname);
 	const char *to_free = start;
 
-	if (len < 0) {
-		int i;
-		const char *p = refname;
-
-		/* Find total no of '/' separated path-components */
-		for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
-			;
-		/*
-		 * The number of components we need to strip is now
-		 * the total minus the components to be left (Plus one
-		 * because we count the number of '/', but the number
-		 * of components is one more than the no of '/').
-		 */
-		remaining = i + len + 1;
-	}
-
 	while (remaining-- > 0) {
 		char *p = strrchr(start, '/');
 		if (!p) {
-- 
2.53.0.438.gad17e1cd28
Previous: Jeff KingNext: Junio C Hamano
Message 3 of 14 in “ref-filter: don't declare a strdup'd variable const before writing to it”
  1. ref-filter: don't declare a strdup'd variable const before writing to itCollin Funk, Feb 14, 2026
  2. 0/4 cleaning up ref-filter lstrip/rstrip codeJeff King, Feb 15, 2026
  3. 1/4 ref-filter: factor out refname component countingJeff King, Feb 15, 2026
  4. Junio C HamanoFeb 17, 2026
  5. Jeff KingFeb 19, 2026
  6. Junio C HamanoFeb 19, 2026
  7. ref-filter: clarify lstrip/rstrip component countingJeff King, Feb 20, 2026
  8. Karthik NayakFeb 22, 2026
  9. 2/4 ref-filter: simplify lstrip_ref_components() memory handlingJeff King, Feb 15, 2026
  10. 3/4 ref-filter: simplify rstrip_ref_components() memory handlingJeff King, Feb 15, 2026
  11. 4/4 ref-filter: avoid strrchr() in rstrip_ref_components()Jeff King, Feb 15, 2026
  12. Patrick SteinhardtFeb 16, 2026
  13. Jeff KingFeb 15, 2026
  14. Collin FunkFeb 15, 2026

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.