Subject: [PATCH 2/4] path: add new function strbuf_add_path

From: Lucas Seiki Oshiro <[email-masked]>
Date: Sat, 28 Feb 2026 19:05:56 -0300

The function `print_path`, introduced in fac60b8925 (rev-parse: add
option for absolute or relative path formatting, 2020-12-13), is used
by git-rev-parse for printing paths, deciding between using relative
or absolute paths. This decision, however, could benefit other
commands, notably git-repo-info.

Encapsulate this logic into a new function called `strbuf_add_path`,
located in `path.c`. Move to path.c the two enums used for deciding
the path format, i.e. `path_default_type` and `path_format_type`.

Signed-off-by: Lucas Seiki Oshiro <[email-masked]>
---
 builtin/rev-parse.c | 72 ++++-----------------------------------------
 path.c              | 51 ++++++++++++++++++++++++++++++++
 path.h              | 23 +++++++++++++++
 3 files changed, 80 insertions(+), 66 deletions(-)

diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index a2162ff39e..024a9e7d5f 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -623,73 +623,13 @@ static void handle_ref_opt(const char *pattern, const char *prefix)
 	clear_ref_exclusions(&ref_excludes);
 }
 
-enum path_format_type {
-	/* We would like a relative path. */
-	PATH_FORMAT_RELATIVE,
-	/* We would like a canonical absolute path. */
-	PATH_FORMAT_CANONICAL,
-	/* We would like the default behavior. */
-	PATH_FORMAT_DEFAULT,
-};
-
-enum path_default_type {
-	/* Our default is a relative path. */
-	PATH_DEFAULT_RELATIVE,
-	/* Our default is a relative path if there's a shared root. */
-	PATH_DEFAULT_RELATIVE_IF_SHARED,
-	/* Our default is a canonical absolute path. */
-	PATH_DEFAULT_CANONICAL,
-	/* Our default is not to modify the item. */
-	PATH_DEFAULT_UNMODIFIED,
-};
-
-static void print_path(const char *path, const char *prefix, enum path_format_type format, enum path_default_type def)
+static void print_path(const char *path, const char *prefix,
+		       enum path_format_type format, enum path_default_type def)
 {
-	char *cwd = NULL;
-	/*
-	 * We don't ever produce a relative path if prefix is NULL, so set the
-	 * prefix to the current directory so that we can produce a relative
-	 * path whenever possible.  If we're using RELATIVE_IF_SHARED mode, then
-	 * we want an absolute path unless the two share a common prefix, so don't
-	 * set it in that case, since doing so causes a relative path to always
-	 * be produced if possible.
-	 */
-	if (!prefix && (format != PATH_FORMAT_DEFAULT || def != PATH_DEFAULT_RELATIVE_IF_SHARED))
-		prefix = cwd = xgetcwd();
-	if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_UNMODIFIED) {
-		puts(path);
-	} else if (format == PATH_FORMAT_RELATIVE ||
-		  (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE)) {
-		/*
-		 * In order for relative_path to work as expected, we need to
-		 * make sure that both paths are absolute paths.  If we don't,
-		 * we can end up with an unexpected absolute path that the user
-		 * didn't want.
-		 */
-		struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
-		if (!is_absolute_path(path)) {
-			strbuf_realpath_forgiving(&realbuf, path,  1);
-			path = realbuf.buf;
-		}
-		if (!is_absolute_path(prefix)) {
-			strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
-			prefix = prefixbuf.buf;
-		}
-		puts(relative_path(path, prefix, &buf));
-		strbuf_release(&buf);
-		strbuf_release(&realbuf);
-		strbuf_release(&prefixbuf);
-	} else if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE_IF_SHARED) {
-		struct strbuf buf = STRBUF_INIT;
-		puts(relative_path(path, prefix, &buf));
-		strbuf_release(&buf);
-	} else {
-		struct strbuf buf = STRBUF_INIT;
-		strbuf_realpath_forgiving(&buf, path, 1);
-		puts(buf.buf);
-		strbuf_release(&buf);
-	}
-	free(cwd);
+	struct strbuf sb = STRBUF_INIT;
+	strbuf_add_path(&sb, path, prefix, format, def);
+	puts(sb.buf);
+	strbuf_release(&sb);
 }
 
 int cmd_rev_parse(int argc,
diff --git a/path.c b/path.c
index d726537622..ab9669abff 100644
--- a/path.c
+++ b/path.c
@@ -1574,6 +1574,57 @@ char *xdg_cache_home(const char *filename)
 	return NULL;
 }
 
+void strbuf_add_path(struct strbuf *sb, const char *path, const char *prefix,
+		     enum path_format_type format, enum path_default_type def)
+{
+	char *cwd = NULL;
+	/*
+	 * We don't ever produce a relative path if prefix is NULL, so set the
+	 * prefix to the current directory so that we can produce a relative
+	 * path whenever possible.  If we're using RELATIVE_IF_SHARED mode, then
+	 * we want an absolute path unless the two share a common prefix, so don't
+	 * set it in that case, since doing so causes a relative path to always
+	 * be produced if possible.
+	 */
+	if (!prefix && (format != PATH_FORMAT_DEFAULT || def != PATH_DEFAULT_RELATIVE_IF_SHARED))
+		prefix = cwd = xgetcwd();
+	if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_UNMODIFIED) {
+		strbuf_addstr(sb, path);
+	} else if (format == PATH_FORMAT_RELATIVE ||
+		   (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE)) {
+		/*
+		 * In order for relative_path to work as expected, we need to
+		 * make sure that both paths are absolute paths.  If we don't,
+		 * we can end up with an unexpected absolute path that the user
+		 * didn't want.
+		 */
+		struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
+		if (!is_absolute_path(path)) {
+			strbuf_realpath_forgiving(&realbuf, path,  1);
+			path = realbuf.buf;
+		}
+		if (!is_absolute_path(prefix)) {
+			strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
+			prefix = prefixbuf.buf;
+		}
+		strbuf_addstr(sb, relative_path(path, prefix, &buf));
+		strbuf_release(&buf);
+		strbuf_release(&realbuf);
+		strbuf_release(&prefixbuf);
+	} else if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE_IF_SHARED) {
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_addstr(sb, relative_path(path, prefix, &buf));
+		strbuf_release(&buf);
+	} else {
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_realpath_forgiving(&buf, path, 1);
+		strbuf_addbuf(sb, &buf);
+		strbuf_release(&buf);
+	}
+	free(cwd);
+}
+
+
 REPO_GIT_PATH_FUNC(squash_msg, "SQUASH_MSG")
 REPO_GIT_PATH_FUNC(merge_msg, "MERGE_MSG")
 REPO_GIT_PATH_FUNC(merge_rr, "MERGE_RR")
diff --git a/path.h b/path.h
index 0ec95a0b07..c152d20c71 100644
--- a/path.h
+++ b/path.h
@@ -258,6 +258,29 @@ enum scld_error safe_create_leading_directories_no_share(char *path);
 int safe_create_file_with_leading_directories(struct repository *repo,
 					      const char *path);
 
+enum path_format_type {
+	/* We would like a relative path. */
+	PATH_FORMAT_RELATIVE,
+	/* We would like a canonical absolute path. */
+	PATH_FORMAT_CANONICAL,
+	/* We would like the default behavior. */
+	PATH_FORMAT_DEFAULT,
+};
+
+enum path_default_type {
+	/* Our default is a relative path. */
+	PATH_DEFAULT_RELATIVE,
+	/* Our default is a relative path if there's a shared root. */
+	PATH_DEFAULT_RELATIVE_IF_SHARED,
+	/* Our default is a canonical absolute path. */
+	PATH_DEFAULT_CANONICAL,
+	/* Our default is not to modify the item. */
+	PATH_DEFAULT_UNMODIFIED,
+};
+
+void strbuf_add_path(struct strbuf *buf, const char *path, const char *prefix,
+		     enum path_format_type format, enum path_default_type def);
+
 # ifdef USE_THE_REPOSITORY_VARIABLE
 #  include "strbuf.h"
 #  include "repository.h"
-- 
2.50.1 (Apple Git-155)