repo: add path.commondir with absolute and relative suffix formatting

Scripts working with worktree setups need a reliable way to discover
the common directory, which diverges from the git directory when
multiple worktrees are in use. There is no way to retrieve this path
from git repo info today.

Introduce path.commondir.absolute and path.commondir.relative keys.
Exposing explicit format variants rather than a single key with a
default avoids ambiguity for scripts that require predictable output.

Add a test helper test_repo_info_path that creates isolated
repositories per test case to prevent state leaks, captures the repo
root before changing directories to avoid eval, and accepts an optional
init_command to cover environment variable overrides such as
GIT_COMMON_DIR and GIT_DIR.

Mentored-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
K Jayatheerth
2026-06-12 23:58:46 +05:30
committed by Junio C Hamano
parent fe19dc3aac
commit b9cf3f646b
3 changed files with 96 additions and 0 deletions

View File

@@ -104,6 +104,15 @@ values that they return:
`object.format`::
The object format (hash algorithm) used in the repository.
`path.commondir.absolute`::
The canonical absolute path to the Git repository's common
directory (the shared `.git` directory containing objects,
refs, and global configuration).
`path.commondir.relative`::
The path to the Git repository's common directory relative to
the current working directory.
`references.format`::
The reference storage format. The valid values are:
+

View File

@@ -7,12 +7,14 @@
#include "hex.h"
#include "odb.h"
#include "parse-options.h"
#include "path.h"
#include "path-walk.h"
#include "progress.h"
#include "quote.h"
#include "ref-filter.h"
#include "refs.h"
#include "revision.h"
#include "setup.h"
#include "strbuf.h"
#include "string-list.h"
#include "shallow.h"
@@ -75,6 +77,28 @@ static int get_object_format(struct repository *repo, struct strbuf *buf)
return 0;
}
static int get_path_commondir_absolute(struct repository *repo, struct strbuf *buf)
{
const char *common_dir = repo_get_common_dir(repo);
if (!common_dir)
return error(_("unable to get common directory"));
append_formatted_path(buf, common_dir, startup_info->prefix, PATH_FORMAT_CANONICAL);
return 0;
}
static int get_path_commondir_relative(struct repository *repo, struct strbuf *buf)
{
const char *common_dir = repo_get_common_dir(repo);
if (!common_dir)
return error(_("unable to get common directory"));
append_formatted_path(buf, common_dir, startup_info->prefix, PATH_FORMAT_RELATIVE);
return 0;
}
static int get_references_format(struct repository *repo, struct strbuf *buf)
{
strbuf_addstr(buf,
@@ -87,6 +111,8 @@ static const struct repo_info_field repo_info_field[] = {
{ "layout.bare", get_layout_bare },
{ "layout.shallow", get_layout_shallow },
{ "object.format", get_object_format },
{ "path.commondir.absolute", get_path_commondir_absolute },
{ "path.commondir.relative", get_path_commondir_relative },
{ "references.format", get_references_format },
};

View File

@@ -155,4 +155,65 @@ test_expect_success 'git repo info -h shows only repo info usage' '
test_grep ! "git repo structure" actual
'
# Helper function to test path keys in both absolute and relative formats.
# $1: label for the test
# $2: field_name (e.g., commondir)
# $3: unique repo name for isolation
# $4: expect_absolute (suffix appended to repo root)
# $5: expect_relative (the relative path string expected)
# $6: init_command (extra setup like exporting env vars)
test_repo_info_path () {
label=$1
field_name=$2
repo_name=$3
expect_absolute_suffix=$4
expect_relative=$5
init_command=$6
absolute_root="$repo_name-absolute"
relative_root="$repo_name-relative"
test_expect_success "setup: $label" '
git init "$absolute_root" &&
git init "$relative_root" &&
mkdir -p "$absolute_root/sub" "$relative_root/sub"
'
test_expect_success "absolute: $label" '
(
cd "$absolute_root/sub" &&
ROOT="$(test-tool path-utils real_path "..")" && export ROOT &&
eval "$init_command" &&
expect_path="$ROOT${expect_absolute_suffix:+/$expect_absolute_suffix}" &&
echo "path.$field_name.absolute=$expect_path" >expect &&
git repo info "path.$field_name.absolute" >actual &&
test_cmp expect actual
)
'
test_expect_success "relative: $label" '
(
cd "$relative_root/sub" &&
ROOT="$(test-tool path-utils real_path "..")" && export ROOT &&
eval "$init_command" &&
echo "path.$field_name.relative=$expect_relative" >expect &&
git repo info "path.$field_name.relative" >actual &&
test_cmp expect actual
)
'
}
test_repo_info_path 'commondir standard' 'commondir' 'commondir-std' \
'.git' '../.git'
test_repo_info_path 'commondir with GIT_COMMON_DIR and GIT_DIR' 'commondir' \
'commondir-envs' 'custom-common' '../custom-common' \
'GIT_COMMON_DIR="$ROOT/custom-common" && export GIT_COMMON_DIR &&
GIT_DIR="../.git" && export GIT_DIR &&
git init --bare "$ROOT/custom-common"'
test_repo_info_path 'commondir with only GIT_DIR' 'commondir' \
'commondir-only-gitdir' '.git' '../.git' \
'GIT_DIR="../.git" && export GIT_DIR'
test_done