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.
This commit is contained in:
kshitijk4poor
2026-10-02 02:17:03 +05:30
committed by kshitij
parent c646bc29a9
commit b7fd5527dc

View File

@@ -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()