[GSoC Patch v7 0/8] add more path keys to git repo info
- From
K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
- Date
- Sep 27, 2026, 11:44 UTC
- Message-ID
- <20260927114420.59724-1-jayatheerthkulkarni2005@gmail.com>
- In-Reply-To
- <20260716012138.6714-1-jayatheerthkulkarni2005@gmail.com>
Series adds keys to git repo info.
Keys output paths of repository components: * path.toplevel: repository tree. * path.superproject-root: superproject tree from submodules. * path.hooks: repository hooks. * path.index: repository index. * path.grafts: repository grafts. * path.git-prefix: prefix offset. * path.cdup: relative path to top level from subdirectory.
Keys support suffixes for format. Commits contain documentation and tests.
fix a superproject bug where it now takes repo parameter instead of just depending on cwd.
changes since v6: * The superproject bug fix is now a commit of its own. * The dead code in index is removed, we simply rely on the helper itself and not write any new conditions. * cdup now works even when the worktree is outside the current working directory.
K Jayatheerth (8): repo: add path.toplevel with absolute and relative suffix formatting submodule: use repository to find superproject repo: add path.superproject-root with absolute and relative suffixes repo: add path.hooks with absolute and relative suffixes repo: add path.index with absolute and relative suffixes repo: add path.grafts with absolute and relative suffixes repo: add path.git-prefix repo: add path.cdup
Documentation/git-repo.adoc | 62 ++++++++++++ builtin/repo.c | 153 ++++++++++++++++++++++++++++ builtin/rev-parse.c | 2 +- submodule.c | 43 ++++---- submodule.h | 2 +- t/t1900-repo-info.sh | 194 +++++++++++++++++++++++++++++++++++- t/t7400-submodule-basic.sh | 19 ++++ 7 files changed, 450 insertions(+), 25 deletions(-)
Range-diff against v6:
-: ---------- > 1: 27b9811163 repo: add path.toplevel with absolute and relative suffix formatting
1: d4f3253256 ! 2: 7c90603a1b repo: add path.superproject-root with absolute and relative suffixes
@@ Metadata
Author: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
## Commit message ##
- repo: add path.superproject-root with absolute and relative suffixes
+ submodule: use repository to find superproject
- 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`.
+ `get_superproject_working_tree()` currently uses `xgetcwd()` to
+ determine the repository whose superproject should be checked.
- Introduce `path.superproject-root.absolute` and
- `path.superproject-root.relative` keys to `git repo info`.
- This exposes the core submodule context via a scriptable config-like key
- using standard format rules.
+ This is incorrect when `--git-dir` points to a repository different
+ from the one associated with the current working directory. In that
+ case, the current working directory may cause the function to return
+ the wrong superproject or an empty result.
- If requested when not inside a submodule, the command returns an empty
- string.
+ Pass the `repository` to `get_superproject_working_tree()` so that the
+ superproject is determined from the repository being inspected rather
+ than the current working directory.
Mentored-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
- ## Documentation/git-repo.adoc ##
-@@ Documentation/git-repo.adoc: values that they return:
- `path.gitdir.relative`::
- The path to the Git repository directory relative to the current working directory.
-
-+`path.superproject-root.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-root.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
-
- ## builtin/repo.c ##
-@@
- #include "strbuf.h"
- #include "string-list.h"
- #include "shallow.h"
-+#include "submodule.h"
- #include "tree.h"
- #include "tree-walk.h"
- #include "utf8.h"
-@@ builtin/repo.c: static int get_path_gitdir_relative(struct repository *repo, struct strbuf *buf)
- return 0;
- }
-
-+static int get_path_superproject_absolute(struct repository *repo, struct strbuf *buf)
-+{
-+ struct strbuf superproject = STRBUF_INIT;
-+
-+ if (!get_superproject_working_tree(repo, &superproject)) {
-+ strbuf_release(&superproject);
-+ return 0;
-+ }
-+
-+ format_path(buf, superproject.buf, "", PATH_FORMAT_CANONICAL);
-+ strbuf_release(&superproject);
-+ return 0;
-+}
-+
-+static int get_path_superproject_relative(struct repository *repo, struct strbuf *buf)
-+{
-+ struct strbuf superproject = STRBUF_INIT;
-+
-+ if (!get_superproject_working_tree(repo, &superproject)) {
-+ strbuf_release(&superproject);
-+ return 0;
-+ }
-+
-+ format_path(buf, superproject.buf, repo->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);
-@@ builtin/repo.c: 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-root.absolute", get_path_superproject_absolute },
-+ { "path.superproject-root.relative", get_path_superproject_relative },
- { "path.toplevel.absolute", get_path_toplevel_absolute },
- { "path.toplevel.relative", get_path_toplevel_relative },
- { "references.format", get_references_format },
-
## builtin/rev-parse.c ##
@@ builtin/rev-parse.c: int cmd_rev_parse(int argc,
}
@@ submodule.h: void absorb_git_dir_into_superproject(const char *path,
#endif
- ## t/t1900-repo-info.sh ##
-@@ t/t1900-repo-info.sh: test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \
- '.git' \
- 'GIT_DIR="../.git" && export GIT_DIR'
-
-+test_expect_success 'path.superproject-root 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-root.absolute=$ROOT" >expect.abs &&
-+ git repo info path.superproject-root.absolute >actual.abs &&
-+ test_cmp expect.abs actual.abs &&
-+
-+ echo "path.superproject-root.relative=../" >expect.rel &&
-+ git repo info path.superproject-root.relative >actual.rel &&
-+ test_cmp expect.rel actual.rel
-+ )
-+'
-+
-+test_expect_success 'path.superproject-root returns empty when not in a submodule' '
-+ test_when_finished "rm -rf repo" &&
-+ git init repo &&
-+ (
-+ cd repo &&
-+
-+ echo "path.superproject-root.absolute=" >expect.abs &&
-+ git repo info path.superproject-root.absolute >actual.abs &&
-+ test_cmp expect.abs actual.abs &&
-+
-+ echo "path.superproject-root.relative=" >expect.rel &&
-+ git repo info path.superproject-root.relative >actual.rel &&
-+ test_cmp expect.rel actual.rel
-+ )
-+'
-+
- test_expect_success 'path.toplevel absolute and relative' '
- test_when_finished "rm -rf repo" &&
- git init repo &&
-@@ t/t1900-repo-info.sh: test_expect_success 'path.toplevel absolute and relative in a bare repository' '
+ ## t/t7400-submodule-basic.sh ##
+@@ t/t7400-submodule-basic.sh: test_expect_success 'submodule add fails when name is reused' '
)
'
@@ t/t1900-repo-info.sh: test_expect_success 'path.toplevel absolute and relative i
+ test_cmp expect actual
+ )
+'
++
test_done
3: 1860d19d01 ! 3: 1bfb0c8c1d repo: add path.index with absolute and relative suffixes
@@ Metadata
Author: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
## Commit message ##
- repo: add path.index with absolute and relative suffixes
+ repo: add path.superproject-root with absolute and relative suffixes
- The repository index is a fundamental component used by Git and related
- tooling to track the working tree state. Scripts that interact with the
- index currently retrieve its location by invoking
- `git rev-parse --git-path index`.
+ 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.index.absolute` and `path.index.relative` keys to
- `git repo info`. This exposes the index file location as a scriptable
- config-like key using standard format rules, allowing scripts to
- retrieve it through the same interface as other repository path
- information.
+ Introduce `path.superproject-root.absolute` and
+ `path.superproject-root.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 <jltobler@gmail.com>
Mentored-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
@@ Commit message
## Documentation/git-repo.adoc ##
@@ Documentation/git-repo.adoc: values that they return:
- The path to the repository's hooks directory relative to the current
- working directory. Respects the `core.hooksPath` configuration.
+ `path.gitdir.relative`::
+ The path to the Git repository directory relative to the current working directory.
-+`path.index.absolute`::
-+ The canonical absolute path to the repository's current index file.
-+ Respects the `GIT_INDEX_FILE` environment override. Returns the
-+ configured index path even if the repository is bare or the file does
-+ not exist.
++`path.superproject-root.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.index.relative`::
-+ The path to the repository's current index file relative to the current
-+ working directory. Respects the `GIT_INDEX_FILE` environment override.
-+ Returns the configured index path even if the repository is bare or the
-+ file does not exist.
++`path.superproject-root.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.superproject-root.absolute`::
- The canonical absolute path to the working tree root of the superproject
- if the current repository is an initialized submodule. Outputs an empty
+ `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
## builtin/repo.c ##
-@@ builtin/repo.c: static int get_path_hooks_relative(struct repository *repo, struct strbuf *buf)
+@@
+ #include "strbuf.h"
+ #include "string-list.h"
+ #include "shallow.h"
++#include "submodule.h"
+ #include "tree.h"
+ #include "tree-walk.h"
+ #include "utf8.h"
+@@ builtin/repo.c: static int get_path_gitdir_relative(struct repository *repo, struct strbuf *buf)
return 0;
}
-+static int get_path_index_absolute(struct repository *repo, struct strbuf *buf)
++static int get_path_superproject_absolute(struct repository *repo, struct strbuf *buf)
+{
-+ const char *index_file = repo_get_index_file(repo);
++ struct strbuf superproject = STRBUF_INIT;
+
-+ if (!index_file)
-+ return error(_("unable to get index file"));
++ if (!get_superproject_working_tree(repo, &superproject)) {
++ strbuf_release(&superproject);
++ return 0;
++ }
+
-+ format_path(buf, index_file, "", PATH_FORMAT_CANONICAL);
++ format_path(buf, superproject.buf, "", PATH_FORMAT_CANONICAL);
++ strbuf_release(&superproject);
+ return 0;
+}
+
-+static int get_path_index_relative(struct repository *repo, struct strbuf *buf)
++static int get_path_superproject_relative(struct repository *repo, struct strbuf *buf)
+{
-+ const char *index_file = repo_get_index_file(repo);
++ struct strbuf superproject = STRBUF_INIT;
+
-+ if (!index_file)
-+ return error(_("unable to get index file"));
++ if (!get_superproject_working_tree(repo, &superproject)) {
++ strbuf_release(&superproject);
++ return 0;
++ }
+
-+ format_path(buf, index_file, repo->prefix, PATH_FORMAT_RELATIVE);
++ format_path(buf, superproject.buf, repo->prefix, PATH_FORMAT_RELATIVE);
++ strbuf_release(&superproject);
+ return 0;
+}
+
- static int get_path_superproject_absolute(struct repository *repo, struct strbuf *buf)
+ static int get_path_toplevel_absolute(struct repository *repo, struct strbuf *buf)
{
- struct strbuf superproject = STRBUF_INIT;
+ const char *work_tree = repo_get_work_tree(repo);
@@ builtin/repo.c: 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.index.absolute", get_path_index_absolute },
-+ { "path.index.relative", get_path_index_relative },
- { "path.superproject-root.absolute", get_path_superproject_absolute },
- { "path.superproject-root.relative", get_path_superproject_relative },
++ { "path.superproject-root.absolute", get_path_superproject_absolute },
++ { "path.superproject-root.relative", get_path_superproject_relative },
{ "path.toplevel.absolute", get_path_toplevel_absolute },
+ { "path.toplevel.relative", get_path_toplevel_relative },
+ { "references.format", get_references_format },
## t/t1900-repo-info.sh ##
-@@ t/t1900-repo-info.sh: then
- 'git config core.hooksPath /dev/null'
- fi
+@@ t/t1900-repo-info.sh: test_repo_info_path 'gitdir with explicit GIT_DIR' 'gitdir' \
+ '.git' \
+ 'GIT_DIR="../.git" && export GIT_DIR'
-+test_repo_info_path 'index standard' 'index' '.git/index'
++test_expect_success 'path.superproject-root 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-root.absolute=$ROOT" >expect.abs &&
++ git repo info path.superproject-root.absolute >actual.abs &&
++ test_cmp expect.abs actual.abs &&
+
-+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'
++ echo "path.superproject-root.relative=../" >expect.rel &&
++ git repo info path.superproject-root.relative >actual.rel &&
++ test_cmp expect.rel actual.rel
++ )
++'
+
-+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 &&
++test_expect_success 'path.superproject-root returns empty when not in a submodule' '
++ test_when_finished "rm -rf repo" &&
++ git init repo &&
+ (
-+ cd bare.git &&
-+ ROOT="$(test-tool path-utils real_path .)" &&
++ cd repo &&
+
-+ echo "path.index.absolute=$ROOT/index" >expect.abs &&
-+ git repo info path.index.absolute >actual.abs &&
++ echo "path.superproject-root.absolute=" >expect.abs &&
++ git repo info path.superproject-root.absolute >actual.abs &&
+ test_cmp expect.abs actual.abs &&
+
-+ echo "path.index.relative=index" >expect.rel &&
-+ git repo info path.index.relative >actual.rel &&
++ echo "path.superproject-root.relative=" >expect.rel &&
++ git repo info path.superproject-root.relative >actual.rel &&
+ test_cmp expect.rel actual.rel
+ )
+'
+
- test_expect_success 'path.superproject-root absolute and relative' '
- test_when_finished "rm -rf sub super" &&
- git init sub &&
+ test_expect_success 'path.toplevel absolute and relative' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
2: dcbaf1cb96 = 4: 09d2937fcd repo: add path.hooks with absolute and relative suffixes
-: ---------- > 5: d0c186f150 repo: add path.index with absolute and relative suffixes
4: ced5b0cb8b = 6: 351b4b7de7 repo: add path.grafts with absolute and relative suffixes
5: ac766e49e3 = 7: ef69d4aa8c repo: add path.git-prefix
6: 0a0c3dd924 ! 8: 3e61728dba repo: add path.cdup
@@ Documentation/git-repo.adoc: values that they return:
The object format (hash algorithm) used in the repository.
+`path.cdup`::
-+ The path to the root of the working tree relative to the current
-+ working directory. Returns the empty string when the current
-+ working directory is the root of the working tree.
++ When the command is invoked from a subdirectory, show the
++ path of the top-level directory relative to the current
++ directory (typically a sequence of "../", or an empty string).
+
`path.commondir.absolute`::
The canonical absolute path to the Git repository's common
@@ builtin/repo.c: static int get_object_format(struct repository *repo, struct str
+{
+ const char *pfx = repo->prefix;
+
++ if (!is_inside_work_tree(repo)) {
++ const char *worktree = repo_get_work_tree(repo);
++
++ if (worktree) {
++ strbuf_addstr(buf, worktree);
++ }
++ }
++
+ while (pfx) {
+ pfx = strchr(pfx, '/');
+ if (pfx) {
@@ t/t1900-repo-info.sh: test_repo_info_path 'commondir with only GIT_DIR' 'commond
+ test_cmp expect actual
+ )
+'
++
++test_expect_success 'path.cdup cwd outside the working tree' '
++ test_when_finished "rm -rf repo" &&
++ mkdir -p repo/tmp/x &&
++ cd repo &&
++ git init test &&
++ (
++ echo path.cdup=$(pwd)/tmp/x >./test/expect &&
++ cd test &&
++ GIT_WORK_TREE=../tmp/x &&
++ export GIT_WORK_TREE &&
++ GIT_DIR=$(pwd)/.git &&
++ export GIT_DIR &&
++ git repo info path.cdup >actual &&
++ test_cmp expect actual
++ )
++'
+
test_expect_success 'path.git-prefix at repository root' '
test_when_finished "rm -rf repo" &&-- 2.56.0-rc2