Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions lib/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,38 @@
# 5. Environment variables
# 6. Fallback values

# Resolve the main repo root from the current git context.
# Works from the main repo root, a subdirectory, or a linked worktree.
# Returns: absolute path to main repo root or empty on failure
_resolve_main_repo_root() {
local git_common_dir repo_root
git_common_dir=$(git rev-parse --git-common-dir 2>/dev/null) || return 1

[ -n "$git_common_dir" ] || return 1

case "$git_common_dir" in
/*)
repo_root="${git_common_dir%/.git}"
;;
*)
repo_root=$(
unset CDPATH
cd -P -- "$git_common_dir/.." 2>/dev/null && pwd -P
) || return 1
;;
esac

[ -n "$repo_root" ] || return 1
printf "%s" "$repo_root"
}

# Get the path to .gtrconfig file in main repo root
# Usage: _gtrconfig_path
# Returns: path to .gtrconfig or empty if not in a repo
# Note: Uses --git-common-dir to find main repo even from worktrees
# Note: Uses _resolve_main_repo_root to find main repo even from worktrees/subdirectories
_gtrconfig_path() {
local git_common_dir repo_root
git_common_dir=$(git rev-parse --git-common-dir 2>/dev/null) || return 0

# git-common-dir returns:
# - ".git" when in main repo (relative)
# - "/absolute/path/to/repo/.git" when in worktree (absolute)
if [ "$git_common_dir" = ".git" ]; then
# In main repo - use show-toplevel
repo_root=$(git rev-parse --show-toplevel 2>/dev/null) || return 0
else
# In worktree - strip /.git suffix from absolute path
repo_root="${git_common_dir%/.git}"
fi
local repo_root
repo_root=$(_resolve_main_repo_root) || return 0

printf "%s/.gtrconfig" "$repo_root"
}
Expand Down
20 changes: 2 additions & 18 deletions lib/core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,8 @@ declare _ctx_is_main _ctx_worktree_path _ctx_branch
# Returns: absolute path to main repo root
# Exit code: 0 on success, 1 if not in a git repo
discover_repo_root() {
local root git_common_dir
git_common_dir=$(git rev-parse --git-common-dir 2>/dev/null)

if [ -z "$git_common_dir" ]; then
log_error "Not in a git repository"
return 1
fi

# --git-common-dir returns:
# ".git" (relative) when in the main repo
# "/absolute/path/to/repo/.git" when in a worktree
if [ "$git_common_dir" = ".git" ]; then
root=$(git rev-parse --show-toplevel 2>/dev/null)
else
root="${git_common_dir%/.git}"
fi

if [ -z "$root" ]; then
local root
if ! root=$(_resolve_main_repo_root); then
log_error "Not in a git repository"
return 1
fi
Expand Down
9 changes: 9 additions & 0 deletions tests/cmd_list.bats
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,12 @@ teardown() {
[[ "$output" == *"$TEST_REPO"* ]]
[[ "$output" == *"wt-porcelain"* ]]
}

@test "cmd_list from a repo subdirectory shows the main repo root" {
mkdir -p "$TEST_REPO/subdir/nested"
cd "$TEST_REPO/subdir/nested"
run cmd_list
[ "$status" -eq 0 ]
[[ "$output" == *"$TEST_REPO"* ]]
[[ "$output" != *"subdir/..-worktrees"* ]]
}
31 changes: 31 additions & 0 deletions tests/config.bats
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ setup() {
source "$PROJECT_ROOT/lib/config.sh"
}

teardown() {
if [ -n "${TEST_REPO:-}" ]; then
teardown_integration_repo
unset TEST_REPO TEST_WORKTREES_DIR
fi
}

# ── Key mapping ──────────────────────────────────────────────────────────────

@test "cfg_map_to_file_key maps gtr.copy.include to copy.include" {
Expand Down Expand Up @@ -125,3 +132,27 @@ setup() {
[[ "$result" == *"vscode"* ]]
[[ "$result" == *"[local]"* ]]
}

# ── Repo context integration ─────────────────────────────────────────────────

@test "_resolve_main_repo_root returns the repo root from a subdirectory" {
setup_integration_repo
mkdir -p "$TEST_REPO/subdir/nested"
cd "$TEST_REPO/subdir/nested"
local expected
expected=$(cd "$TEST_REPO" && pwd -P)

result=$(_resolve_main_repo_root)
[ "$result" = "$expected" ]
}

@test "_gtrconfig_path points at the repo root from a subdirectory" {
setup_integration_repo
mkdir -p "$TEST_REPO/subdir/nested"
cd "$TEST_REPO/subdir/nested"
local expected
expected="$(cd "$TEST_REPO" && pwd -P)/.gtrconfig"

result=$(_gtrconfig_path)
[ "$result" = "$expected" ]
}
20 changes: 20 additions & 0 deletions tests/core_resolve_target.bats
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,23 @@ teardown() {
expected=$(pwd -P)
[ "$root" = "$expected" ]
}

@test "discover_repo_root returns main repo root when called from a repo subdirectory" {
mkdir -p "$TEST_REPO/subdir/nested"
cd "$TEST_REPO/subdir/nested"
local root expected
root=$(discover_repo_root)
expected=$(cd "$TEST_REPO" && pwd -P)
[ "$root" = "$expected" ]
}

@test "discover_repo_root returns 1 outside a git repository" {
local outside_repo
outside_repo=$(mktemp -d)
cd "$outside_repo"

run discover_repo_root
[ "$status" -eq 1 ]

rm -rf "$outside_repo"
}
Loading