From 4f4f0e15d62a5f0a571d27e98c4a04abc28b9479 Mon Sep 17 00:00:00 2001 From: K Jayatheerth Date: Sun, 26 Jul 2026 16:13:37 +0530 Subject: [PATCH 1/7] repo: add path.toplevel with absolute and relative suffix formatting Scripts frequently need to find the root directory of a repository's working tree. Currently, this requires using `git rev-parse --show-toplevel` or inferring it from other path components. Introduce `path.toplevel.absolute` and `path.toplevel.relative` keys to `git repo info`. This allows scripts to retrieve the top-level working tree path in a predictable, strictly formatted manner without relying on `rev-parse`. If requested in a bare repository where no working tree exists, the command returns an empty string. Mentored-by: Justin Tobler Mentored-by: Lucas Seiki Oshiro Signed-off-by: K Jayatheerth Signed-off-by: Junio C Hamano --- Documentation/git-repo.adoc | 10 ++++++++++ builtin/repo.c | 28 ++++++++++++++++++++++++++++ t/t1900-repo-info.sh | 30 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index ed7d80c690..e34abe5fea 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -119,6 +119,16 @@ values that they return: `path.gitdir.relative`:: The path to the Git repository directory relative to the current working directory. +`path.toplevel.absolute`:: + The canonical absolute path to the top-level directory of the + repository's working tree. Outputs an empty string if the repository + is bare. + +`path.toplevel.relative`:: + The path to the top-level directory of the repository's working + tree relative to the current working directory. Outputs an empty + string if the repository is bare. + `references.format`:: The reference storage format. The valid values are: + diff --git a/builtin/repo.c b/builtin/repo.c index 042d6de558..194757eb18 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -121,6 +121,32 @@ static int get_path_gitdir_relative(struct repository *repo, struct strbuf *buf) return 0; } +static int get_path_toplevel_absolute(struct repository *repo, struct strbuf *buf) +{ + const char *work_tree = repo_get_work_tree(repo); + + if (!work_tree) { + strbuf_addstr(buf, ""); + return 0; + } + + format_path(buf, work_tree, startup_info->prefix, PATH_FORMAT_CANONICAL); + return 0; +} + +static int get_path_toplevel_relative(struct repository *repo, struct strbuf *buf) +{ + const char *work_tree = repo_get_work_tree(repo); + + if (!work_tree) { + strbuf_addstr(buf, ""); + return 0; + } + + format_path(buf, work_tree, startup_info->prefix, PATH_FORMAT_RELATIVE); + return 0; +} + static int get_references_format(struct repository *repo, struct strbuf *buf) { strbuf_addstr(buf, @@ -137,6 +163,8 @@ static const struct repo_info_field repo_info_field[] = { { "path.commondir.relative", get_path_commondir_relative }, { "path.gitdir.absolute", get_path_gitdir_absolute }, { "path.gitdir.relative", get_path_gitdir_relative }, + { "path.toplevel.absolute", get_path_toplevel_absolute }, + { "path.toplevel.relative", get_path_toplevel_relative }, { "references.format", get_references_format }, }; diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh index ae8c22c817..fbb9063ee5 100755 --- a/t/t1900-repo-info.sh +++ b/t/t1900-repo-info.sh @@ -213,4 +213,34 @@ test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \ '.git' \ 'GIT_DIR="../.git" && export GIT_DIR' +test_expect_success 'path.toplevel absolute and relative' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + mkdir -p repo/sub && + cd repo/sub && + + ROOT="$(test-tool path-utils real_path ..)" && + + echo "path.toplevel.absolute=$ROOT" >expect.abs && + git repo info path.toplevel.absolute >actual.abs && + test_cmp expect.abs actual.abs && + + echo "path.toplevel.relative=../" >expect.rel && + git repo info path.toplevel.relative >actual.rel && + test_cmp expect.rel actual.rel + ) +' + +test_expect_success 'path.toplevel returns empty in a bare repository' ' + test_when_finished "rm -rf bare.git" && + git init --bare bare.git && + ( + cd bare.git && + echo "path.toplevel.absolute=" >expect && + git repo info path.toplevel.absolute >actual && + test_cmp expect actual + ) +' + test_done From 0b038af81bb89712e93543b2bf672cfbb27d4c2c Mon Sep 17 00:00:00 2001 From: K Jayatheerth Date: Sun, 26 Jul 2026 16:13:38 +0530 Subject: [PATCH 2/7] repo: add path.superproject-working-tree with absolute and relative suffixes Scripts working in multi-repository setups often need to identify the top-level working tree of a superproject from within a submodule. Currently, this is only exposed via `git rev-parse --show-superproject-working-tree`. Introduce `path.superproject-working-tree.absolute` and `path.superproject-working-tree.relative` keys to `git repo info`. This exposes the core submodule context via a scriptable config-like key using standard format rules. If requested when not inside a submodule, the command returns an empty string. Mentored-by: Justin Tobler Mentored-by: Lucas Seiki Oshiro Signed-off-by: K Jayatheerth Signed-off-by: Junio C Hamano --- Documentation/git-repo.adoc | 10 ++++++++++ builtin/repo.c | 33 +++++++++++++++++++++++++++++++++ t/t1900-repo-info.sh | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index e34abe5fea..03aa57942f 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -119,6 +119,16 @@ values that they return: `path.gitdir.relative`:: The path to the Git repository directory relative to the current working directory. +`path.superproject-working-tree.absolute`:: + The canonical absolute path to the working tree root of the superproject + if the current repository is an initialized submodule. Outputs an empty + string if not in a submodule. + +`path.superproject-working-tree.relative`:: + The path to the working tree root of the superproject relative to the + current working directory if the current repository is an initialized + submodule. Outputs an empty string if not in a submodule. + `path.toplevel.absolute`:: The canonical absolute path to the top-level directory of the repository's working tree. Outputs an empty string if the repository diff --git a/builtin/repo.c b/builtin/repo.c index 194757eb18..82359473e9 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -18,6 +18,7 @@ #include "strbuf.h" #include "string-list.h" #include "shallow.h" +#include "submodule.h" #include "tree.h" #include "tree-walk.h" #include "utf8.h" @@ -121,6 +122,36 @@ static int get_path_gitdir_relative(struct repository *repo, struct strbuf *buf) return 0; } +static int get_path_superproject_absolute(struct repository *repo UNUSED, struct strbuf *buf) +{ + struct strbuf superproject = STRBUF_INIT; + + if (!get_superproject_working_tree(&superproject)) { + strbuf_release(&superproject); + strbuf_addstr(buf, ""); + return 0; + } + + format_path(buf, superproject.buf, startup_info->prefix, PATH_FORMAT_CANONICAL); + strbuf_release(&superproject); + return 0; +} + +static int get_path_superproject_relative(struct repository *repo UNUSED, struct strbuf *buf) +{ + struct strbuf superproject = STRBUF_INIT; + + if (!get_superproject_working_tree(&superproject)) { + strbuf_release(&superproject); + strbuf_addstr(buf, ""); + return 0; + } + + format_path(buf, superproject.buf, startup_info->prefix, PATH_FORMAT_RELATIVE); + strbuf_release(&superproject); + return 0; +} + static int get_path_toplevel_absolute(struct repository *repo, struct strbuf *buf) { const char *work_tree = repo_get_work_tree(repo); @@ -163,6 +194,8 @@ static const struct repo_info_field repo_info_field[] = { { "path.commondir.relative", get_path_commondir_relative }, { "path.gitdir.absolute", get_path_gitdir_absolute }, { "path.gitdir.relative", get_path_gitdir_relative }, + { "path.superproject-working-tree.absolute", get_path_superproject_absolute }, + { "path.superproject-working-tree.relative", get_path_superproject_relative }, { "path.toplevel.absolute", get_path_toplevel_absolute }, { "path.toplevel.relative", get_path_toplevel_relative }, { "references.format", get_references_format }, diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh index fbb9063ee5..220b3d4d3d 100755 --- a/t/t1900-repo-info.sh +++ b/t/t1900-repo-info.sh @@ -213,6 +213,40 @@ test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \ '.git' \ 'GIT_DIR="../.git" && export GIT_DIR' +test_expect_success 'path.superproject-working-tree absolute and relative' ' + test_when_finished "rm -rf sub super" && + git init sub && + test_commit -C sub initial && + git init super && + ( + cd super && + git -c protocol.file.allow=always submodule add "../sub" sub && + git commit -m "add submodule" && + + cd sub && + ROOT="$(test-tool path-utils real_path ..)" && + + echo "path.superproject-working-tree.absolute=$ROOT" >expect.abs && + git repo info path.superproject-working-tree.absolute >actual.abs && + test_cmp expect.abs actual.abs && + + echo "path.superproject-working-tree.relative=../" >expect.rel && + git repo info path.superproject-working-tree.relative >actual.rel && + test_cmp expect.rel actual.rel + ) +' + +test_expect_success 'path.superproject-working-tree returns empty when not in a submodule' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + echo "path.superproject-working-tree.absolute=" >expect && + git repo info path.superproject-working-tree.absolute >actual && + test_cmp expect actual + ) +' + test_expect_success 'path.toplevel absolute and relative' ' test_when_finished "rm -rf repo" && git init repo && From b167a461e5803c3250c2e36ae9021652f290766e Mon Sep 17 00:00:00 2001 From: K Jayatheerth Date: Sun, 26 Jul 2026 16:13:39 +0530 Subject: [PATCH 3/7] repo: add path.objects with absolute and relative suffix formatting Tools and deployment hooks frequently query the location of the object database directory. Currently, this relies on legacy parsing methods or manually inspecting `git rev-parse --git-path objects`. Introduce `path.objects.absolute` and `path.objects.relative` keys to `git repo info`. This allows tools to discover the object database location safely while natively adhering to active `GIT_OBJECT_DIRECTORY` environment variable overrides. Mentored-by: Justin Tobler Mentored-by: Lucas Seiki Oshiro Signed-off-by: K Jayatheerth Signed-off-by: Junio C Hamano --- Documentation/git-repo.adoc | 9 +++++++++ builtin/repo.c | 24 ++++++++++++++++++++++++ t/t1900-repo-info.sh | 7 +++++++ 3 files changed, 40 insertions(+) diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index 03aa57942f..8429a44b43 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -119,6 +119,15 @@ values that they return: `path.gitdir.relative`:: The path to the Git repository directory relative to the current working directory. +`path.objects.absolute`:: + The canonical absolute path to the repository's object database directory. + Respects the `GIT_OBJECT_DIRECTORY` environment override. + +`path.objects.relative`:: + The path to the repository's object database directory relative to the + current working directory. Respects the `GIT_OBJECT_DIRECTORY` + environment override. + `path.superproject-working-tree.absolute`:: The canonical absolute path to the working tree root of the superproject if the current repository is an initialized submodule. Outputs an empty diff --git a/builtin/repo.c b/builtin/repo.c index 82359473e9..d6bdd5bcfa 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -122,6 +122,28 @@ static int get_path_gitdir_relative(struct repository *repo, struct strbuf *buf) return 0; } +static int get_path_objects_absolute(struct repository *repo, struct strbuf *buf) +{ + const char *obj_dir = repo_get_object_directory(repo); + + if (!obj_dir) + return error(_("unable to get object directory")); + + format_path(buf, obj_dir, startup_info->prefix, PATH_FORMAT_CANONICAL); + return 0; +} + +static int get_path_objects_relative(struct repository *repo, struct strbuf *buf) +{ + const char *obj_dir = repo_get_object_directory(repo); + + if (!obj_dir) + return error(_("unable to get object directory")); + + format_path(buf, obj_dir, startup_info->prefix, PATH_FORMAT_RELATIVE); + return 0; +} + static int get_path_superproject_absolute(struct repository *repo UNUSED, struct strbuf *buf) { struct strbuf superproject = STRBUF_INIT; @@ -194,6 +216,8 @@ static const struct repo_info_field repo_info_field[] = { { "path.commondir.relative", get_path_commondir_relative }, { "path.gitdir.absolute", get_path_gitdir_absolute }, { "path.gitdir.relative", get_path_gitdir_relative }, + { "path.objects.absolute", get_path_objects_absolute }, + { "path.objects.relative", get_path_objects_relative }, { "path.superproject-working-tree.absolute", get_path_superproject_absolute }, { "path.superproject-working-tree.relative", get_path_superproject_relative }, { "path.toplevel.absolute", get_path_toplevel_absolute }, diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh index 220b3d4d3d..260f4fde43 100755 --- a/t/t1900-repo-info.sh +++ b/t/t1900-repo-info.sh @@ -213,6 +213,13 @@ test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \ '.git' \ 'GIT_DIR="../.git" && export GIT_DIR' +test_repo_info_path 'objects standard' 'objects' '.git/objects' + +test_repo_info_path 'objects with GIT_OBJECT_DIRECTORY override' 'objects' \ + 'custom-objects' \ + 'GIT_OBJECT_DIRECTORY="$ROOT/custom-objects" && export GIT_OBJECT_DIRECTORY && + mkdir -p "$ROOT/custom-objects"' + test_expect_success 'path.superproject-working-tree absolute and relative' ' test_when_finished "rm -rf sub super" && git init sub && From fac6532b35090729caf0996b24897e1a49b2da56 Mon Sep 17 00:00:00 2001 From: K Jayatheerth Date: Sun, 26 Jul 2026 16:13:40 +0530 Subject: [PATCH 4/7] repo: add path.hooks with absolute and relative suffix formatting External tool integrations and validation systems need a stable way to identify where the repository hooks are stored. Currently, this involves relying on `git rev-parse --git-path hooks` or querying `core.hooksPath` manually. Introduce `path.hooks.absolute` and `path.hooks.relative` keys to `git repo info`. This allows tools to discover the active hooks location natively, ensuring proper resolution regardless of whether Git is using the standard `.git/hooks` structure or a custom `core.hooksPath` setup. Mentored-by: Justin Tobler Mentored-by: Lucas Seiki Oshiro Signed-off-by: K Jayatheerth Signed-off-by: Junio C Hamano --- Documentation/git-repo.adoc | 8 ++++++++ builtin/repo.c | 22 ++++++++++++++++++++++ t/t1900-repo-info.sh | 6 ++++++ 3 files changed, 36 insertions(+) diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index 8429a44b43..7bc1c51310 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -119,6 +119,14 @@ values that they return: `path.gitdir.relative`:: The path to the Git repository directory relative to the current working directory. +`path.hooks.absolute`:: + The canonical absolute path to the repository's hooks directory. + Respects `core.hooksPath` configuration adjustments. + +`path.hooks.relative`:: + The path to the repository's hooks directory relative to the current + working directory. Respects `core.hooksPath` configuration adjustments. + `path.objects.absolute`:: The canonical absolute path to the repository's object database directory. Respects the `GIT_OBJECT_DIRECTORY` environment override. diff --git a/builtin/repo.c b/builtin/repo.c index d6bdd5bcfa..c921de222d 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -122,6 +122,26 @@ static int get_path_gitdir_relative(struct repository *repo, struct strbuf *buf) return 0; } +static int get_path_hooks_absolute(struct repository *repo, struct strbuf *buf) +{ + struct strbuf hooks_path = STRBUF_INIT; + + repo_git_path_replace(repo, &hooks_path, "hooks"); + format_path(buf, hooks_path.buf, startup_info->prefix, PATH_FORMAT_CANONICAL); + strbuf_release(&hooks_path); + return 0; +} + +static int get_path_hooks_relative(struct repository *repo, struct strbuf *buf) +{ + struct strbuf hooks_path = STRBUF_INIT; + + repo_git_path_replace(repo, &hooks_path, "hooks"); + format_path(buf, hooks_path.buf, startup_info->prefix, PATH_FORMAT_RELATIVE); + strbuf_release(&hooks_path); + return 0; +} + static int get_path_objects_absolute(struct repository *repo, struct strbuf *buf) { const char *obj_dir = repo_get_object_directory(repo); @@ -216,6 +236,8 @@ static const struct repo_info_field repo_info_field[] = { { "path.commondir.relative", get_path_commondir_relative }, { "path.gitdir.absolute", get_path_gitdir_absolute }, { "path.gitdir.relative", get_path_gitdir_relative }, + { "path.hooks.absolute", get_path_hooks_absolute }, + { "path.hooks.relative", get_path_hooks_relative }, { "path.objects.absolute", get_path_objects_absolute }, { "path.objects.relative", get_path_objects_relative }, { "path.superproject-working-tree.absolute", get_path_superproject_absolute }, diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh index 260f4fde43..cd3f856d04 100755 --- a/t/t1900-repo-info.sh +++ b/t/t1900-repo-info.sh @@ -213,6 +213,12 @@ test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \ '.git' \ 'GIT_DIR="../.git" && export GIT_DIR' +test_repo_info_path 'hooks standard fallback' 'hooks' '.git/hooks' + +test_repo_info_path 'hooks with core.hooksPath override' 'hooks' \ + 'custom-hooks' \ + 'git config core.hooksPath "$ROOT/custom-hooks" && mkdir -p "$ROOT/custom-hooks"' + test_repo_info_path 'objects standard' 'objects' '.git/objects' test_repo_info_path 'objects with GIT_OBJECT_DIRECTORY override' 'objects' \ From 629ac8ddbbe1a90a5fd38d51c86b4642300cd149 Mon Sep 17 00:00:00 2001 From: K Jayatheerth Date: Sun, 26 Jul 2026 16:13:41 +0530 Subject: [PATCH 5/7] repo: add path.index with absolute and relative suffix formatting External script workflows and formatting layers require straightforward access to the location of the index staging file. Currently, tracking this necessitates a legacy call to `git rev-parse --git-path index` or `--show-toplevel` logic abstractions. Introduce `path.index.absolute` and `path.index.relative` keys to `git repo info`. This allows tooling utilities to discover the active index context cleanly while scaling transparently with localized `GIT_INDEX_FILE` environment overrides. Mentored-by: Justin Tobler Mentored-by: Lucas Seiki Oshiro Signed-off-by: K Jayatheerth Signed-off-by: Junio C Hamano --- Documentation/git-repo.adoc | 12 ++++++++++++ builtin/repo.c | 24 ++++++++++++++++++++++++ t/t1900-repo-info.sh | 23 +++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index 7bc1c51310..34c4f7d61c 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -127,6 +127,18 @@ values that they return: The path to the repository's hooks directory relative to the current working directory. Respects `core.hooksPath` configuration adjustments. +`path.index.absolute`:: + The canonical absolute path to the repository's current index file. + Respects the `GIT_INDEX_FILE` environment override. The returned path + reflects the configured/default index location regardless of whether the + repository is bare or whether the file currently exists. + +`path.index.relative`:: + The path to the repository's current index file relative to the current + working directory. Respects the `GIT_INDEX_FILE` environment override. + The returned path reflects the configured/default index location regardless + of whether the repository is bare or whether the file currently exists. + `path.objects.absolute`:: The canonical absolute path to the repository's object database directory. Respects the `GIT_OBJECT_DIRECTORY` environment override. diff --git a/builtin/repo.c b/builtin/repo.c index c921de222d..66bf4c67cc 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -142,6 +142,28 @@ static int get_path_hooks_relative(struct repository *repo, struct strbuf *buf) return 0; } +static int get_path_index_absolute(struct repository *repo, struct strbuf *buf) +{ + const char *index_file = repo_get_index_file(repo); + + if (!index_file) + return error(_("unable to get index file")); + + format_path(buf, index_file, startup_info->prefix, PATH_FORMAT_CANONICAL); + return 0; +} + +static int get_path_index_relative(struct repository *repo, struct strbuf *buf) +{ + const char *index_file = repo_get_index_file(repo); + + if (!index_file) + return error(_("unable to get index file")); + + format_path(buf, index_file, startup_info->prefix, PATH_FORMAT_RELATIVE); + return 0; +} + static int get_path_objects_absolute(struct repository *repo, struct strbuf *buf) { const char *obj_dir = repo_get_object_directory(repo); @@ -238,6 +260,8 @@ static const struct repo_info_field repo_info_field[] = { { "path.gitdir.relative", get_path_gitdir_relative }, { "path.hooks.absolute", get_path_hooks_absolute }, { "path.hooks.relative", get_path_hooks_relative }, + { "path.index.absolute", get_path_index_absolute }, + { "path.index.relative", get_path_index_relative }, { "path.objects.absolute", get_path_objects_absolute }, { "path.objects.relative", get_path_objects_relative }, { "path.superproject-working-tree.absolute", get_path_superproject_absolute }, diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh index cd3f856d04..dee1db2a49 100755 --- a/t/t1900-repo-info.sh +++ b/t/t1900-repo-info.sh @@ -219,6 +219,29 @@ test_repo_info_path 'hooks with core.hooksPath override' 'hooks' \ 'custom-hooks' \ 'git config core.hooksPath "$ROOT/custom-hooks" && mkdir -p "$ROOT/custom-hooks"' +test_repo_info_path 'index standard' 'index' '.git/index' + +test_repo_info_path 'index with GIT_INDEX_FILE override' 'index' \ + 'custom-index-file' \ + 'GIT_INDEX_FILE="$ROOT/custom-index-file" && export GIT_INDEX_FILE' + +test_expect_success 'path.index in a bare repository returns default index location' ' + test_when_finished "rm -rf bare.git" && + git init --bare bare.git && + ( + cd bare.git && + ROOT="$(test-tool path-utils real_path .)" && + + echo "path.index.absolute=$ROOT/index" >expect.abs && + git repo info path.index.absolute >actual.abs && + test_cmp expect.abs actual.abs && + + echo "path.index.relative=index" >expect.rel && + git repo info path.index.relative >actual.rel && + test_cmp expect.rel actual.rel + ) +' + test_repo_info_path 'objects standard' 'objects' '.git/objects' test_repo_info_path 'objects with GIT_OBJECT_DIRECTORY override' 'objects' \ From b93d827053a216a02d7d907c1cdf09b38e8b54bb Mon Sep 17 00:00:00 2001 From: K Jayatheerth Date: Sun, 26 Jul 2026 16:13:42 +0530 Subject: [PATCH 6/7] repo: add path.grafts with absolute and relative suffix formatting External toolchains managing specialized history rewrites or legacy history splices require access to the location of the repository grafts file. Currently, this requires a legacy call to `git rev-parse --git-path info/grafts`. Introduce `path.grafts.absolute` and `path.grafts.relative` keys to `git repo info`. This allows scripting layers to query the active grafts context cleanly while scaling transparently with active `GIT_GRAFT_FILE` environment variable overrides. Mentored-by: Justin Tobler Mentored-by: Lucas Seiki Oshiro Signed-off-by: K Jayatheerth Signed-off-by: Junio C Hamano --- Documentation/git-repo.adoc | 10 ++++++++++ builtin/repo.c | 24 ++++++++++++++++++++++++ t/t1900-repo-info.sh | 6 ++++++ 3 files changed, 40 insertions(+) diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index 34c4f7d61c..def888da91 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -119,6 +119,16 @@ values that they return: `path.gitdir.relative`:: The path to the Git repository directory relative to the current working directory. +`path.grafts.absolute`:: + The canonical absolute path to the repository grafts file. + Respects the `GIT_GRAFT_FILE` environment override. The path is returned + regardless of whether the file currently exists on disk. + +`path.grafts.relative`:: + The path to the repository grafts file relative to the current working + directory. Respects the `GIT_GRAFT_FILE` environment override. The path + is returned regardless of whether the file currently exists on disk. + `path.hooks.absolute`:: The canonical absolute path to the repository's hooks directory. Respects `core.hooksPath` configuration adjustments. diff --git a/builtin/repo.c b/builtin/repo.c index 66bf4c67cc..a97ad71649 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -122,6 +122,28 @@ static int get_path_gitdir_relative(struct repository *repo, struct strbuf *buf) return 0; } +static int get_path_grafts_absolute(struct repository *repo, struct strbuf *buf) +{ + const char *graft_file = repo_get_graft_file(repo); + + if (!graft_file) + return error(_("unable to get graft file")); + + format_path(buf, graft_file, startup_info->prefix, PATH_FORMAT_CANONICAL); + return 0; +} + +static int get_path_grafts_relative(struct repository *repo, struct strbuf *buf) +{ + const char *graft_file = repo_get_graft_file(repo); + + if (!graft_file) + return error(_("unable to get graft file")); + + format_path(buf, graft_file, startup_info->prefix, PATH_FORMAT_RELATIVE); + return 0; +} + static int get_path_hooks_absolute(struct repository *repo, struct strbuf *buf) { struct strbuf hooks_path = STRBUF_INIT; @@ -258,6 +280,8 @@ static const struct repo_info_field repo_info_field[] = { { "path.commondir.relative", get_path_commondir_relative }, { "path.gitdir.absolute", get_path_gitdir_absolute }, { "path.gitdir.relative", get_path_gitdir_relative }, + { "path.grafts.absolute", get_path_grafts_absolute }, + { "path.grafts.relative", get_path_grafts_relative }, { "path.hooks.absolute", get_path_hooks_absolute }, { "path.hooks.relative", get_path_hooks_relative }, { "path.index.absolute", get_path_index_absolute }, diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh index dee1db2a49..15a4ec9b78 100755 --- a/t/t1900-repo-info.sh +++ b/t/t1900-repo-info.sh @@ -213,6 +213,12 @@ test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \ '.git' \ 'GIT_DIR="../.git" && export GIT_DIR' +test_repo_info_path 'grafts standard' 'grafts' '.git/info/grafts' + +test_repo_info_path 'grafts with GIT_GRAFT_FILE override' 'grafts' \ + 'custom-graft-file' \ + 'GIT_GRAFT_FILE="$ROOT/custom-graft-file" && export GIT_GRAFT_FILE' + test_repo_info_path 'hooks standard fallback' 'hooks' '.git/hooks' test_repo_info_path 'hooks with core.hooksPath override' 'hooks' \ From 2cd8dac1317fcfea82ca8c65c54fa31cf0fd4928 Mon Sep 17 00:00:00 2001 From: K Jayatheerth Date: Sun, 26 Jul 2026 16:13:43 +0530 Subject: [PATCH 7/7] repo: add path.git-prefix path key Scripts and command-line prompt integrations frequently need to know their relative depth inside a repository working tree layout. Currently, this is retrieved using `git rev-parse --show-prefix`. Introduce the `path.git-prefix` key to `git repo info`. This mirrors the prefix location tracking framework as a standalone key, returning the exact relative path offset complete with a trailing slash, or an empty string if run directly at the repository working tree root. Mentored-by: Justin Tobler Mentored-by: Lucas Seiki Oshiro Signed-off-by: K Jayatheerth Signed-off-by: Junio C Hamano --- Documentation/git-repo.adoc | 5 +++++ builtin/repo.c | 11 +++++++++++ t/t1900-repo-info.sh | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index def888da91..98282ea668 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -113,6 +113,11 @@ values that they return: The path to the Git repository's common directory relative to the current working directory. +`path.git-prefix`:: + The relative path from the top-level directory of the working tree to + the current working directory (including a trailing slash). Outputs an + empty string if executed at the root of the working tree. + `path.gitdir.absolute`:: The canonical absolute path to the Git repository directory (the `.git` directory). diff --git a/builtin/repo.c b/builtin/repo.c index a97ad71649..b93c140c74 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -100,6 +100,16 @@ static int get_path_commondir_relative(struct repository *repo, struct strbuf *b return 0; } +static int get_path_git_prefix(struct repository *repo UNUSED, struct strbuf *buf) +{ + /* + * startup_info->prefix is NULL if we are at the working tree root. + * We add an empty string to ensure the buffer is cleanly initialized. + */ + strbuf_addstr(buf, startup_info->prefix ? startup_info->prefix : ""); + return 0; +} + static int get_path_gitdir_absolute(struct repository *repo, struct strbuf *buf) { const char *git_dir = repo_get_git_dir(repo); @@ -278,6 +288,7 @@ static const struct repo_info_field repo_info_field[] = { { "object.format", get_object_format }, { "path.commondir.absolute", get_path_commondir_absolute }, { "path.commondir.relative", get_path_commondir_relative }, + { "path.git-prefix", get_path_git_prefix }, { "path.gitdir.absolute", get_path_gitdir_absolute }, { "path.gitdir.relative", get_path_gitdir_relative }, { "path.grafts.absolute", get_path_grafts_absolute }, diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh index 15a4ec9b78..2879e54668 100755 --- a/t/t1900-repo-info.sh +++ b/t/t1900-repo-info.sh @@ -207,6 +207,25 @@ test_repo_info_path 'commondir with only GIT_DIR' 'commondir' \ '.git' \ 'GIT_DIR="../.git" && export GIT_DIR' +test_expect_success 'path.git-prefix at root and in a subdirectory' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + echo "path.git-prefix=" >expect.root && + git repo info path.git-prefix >actual.root && + test_cmp expect.root actual.root && + + mkdir -p sub/dir && + cd sub/dir && + + echo "path.git-prefix=sub/dir/" >expect.sub && + git repo info path.git-prefix >actual.sub && + test_cmp expect.sub actual.sub + ) +' + test_repo_info_path 'gitdir standard' 'gitdir' '.git' test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \