From b7fd5527dc3ee7a9b1dbabebde58603a67b04bf1 Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Fri, 2 Oct 2026 02:17:03 +0530 Subject: [PATCH] fix(git): keep trailing spaces in the top-level path; refuse relative origins under a caller GIT_DIR r2 gate: Path(stdout.strip()) dropped a trailing space in the checkout path, so include targets resolved to a missing file and were skipped. With a caller-set GIT_DIR or GIT_WORK_TREE git prints origins relative to another base; refuse instead of guessing. --- hermes_cli/_subprocess_compat.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hermes_cli/_subprocess_compat.py b/hermes_cli/_subprocess_compat.py index f18b2d7168..ba4ea1edae 100644 --- a/hermes_cli/_subprocess_compat.py +++ b/hermes_cli/_subprocess_compat.py @@ -476,6 +476,7 @@ _FILTER_COMMAND_KEY = re.compile(r"^filter\..+\.(?:clean|smudge|process)$", re.I # is therefore read directly, whatever its condition, and its filter names are neutralized too. # Global/system config is already /dev/null, so only repo-local includes reach this. _INCLUDE_IF_KEY = re.compile(r"^includeif\..*\.path$", re.IGNORECASE) +# Any include (conditional or not) inside an include target: discovery does not walk it twice. _INCLUDE_KEY = re.compile(r"^include(?:if\..*)?\.path$", re.IGNORECASE) # `git config --get-regexp` pattern for the keys discovery reads (filter commands and includes). _DISCOVERY_KEYS_REGEXP = r"^(filter\..*\.(clean|smudge|process)|include\.path|includeif\..*\.path)$" @@ -526,13 +527,16 @@ def noninteractive_repo_git_env( return None origin_path = Path(origin[len("file:"):]) if not origin_path.is_absolute(): - # git prints repo-local origins relative to the worktree top level, not to *cwd*. + # git prints repo-local origins relative to the worktree top level, not to *cwd*; with a + # caller-set GIT_DIR/GIT_WORK_TREE they are relative to something else, so refuse. + if env.get("GIT_DIR") or env.get("GIT_WORK_TREE"): + return None if toplevel is None: top = bounded_probe_run(["git", "-C", str(cwd), "rev-parse", "--show-toplevel"], timeout=2, env=env) if top is None or top.returncode != 0: return None - toplevel = Path(top.stdout.strip()) + toplevel = Path(top.stdout.rstrip("\r\n")) # a checkout path may end in a space origin_path = toplevel / origin_path # A relative include path resolves against the directory of the config file naming it. target = (origin_path.parent / os.path.expanduser(value)).resolve()