FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix(repo): unquote `git check-ignore` paths in `Repo.ignored` · gitpython-developers/GitPython@221defb · GitHub

Repository navigation

Commit 221defb

Browse files
committed
fix(repo): unquote git check-ignore paths in Repo.ignored
`Repo.ignored` runs `git check-ignore -- <paths>` and recovered the matched paths from stdout with `.replace("\\\\", "\\").replace('"', "").split("\n")`. git C-quotes a path that contains a non-ASCII byte (with the default `core.quotePath`), a double quote, a backslash or a control character, and that replacement does not reverse the quoting. With `*.env` in `.gitignore`: - `données.env` came back as `donn\303\251es.env` - `q"uote.env` came back as `q\uote.env` - `tab<TAB>.env` came back as `tab\t.env` - a name containing a line feed came back with a literal `\n` A caller that compares the result with the paths it passed in, for example to leave ignored files out of a commit, an upload or an archive, therefore treats those ignored files as not ignored. Read stdout as bytes and unquote each quoted line with `git.diff._unquote_path`, which already reverses git's C-quoting for patch headers. Splitting at line feeds stays safe because git always quotes a path that contains one. `git check-ignore -z` would avoid the quoting, but git accepts `-z` only together with `--stdin`. Paths git does not quote are returned unchanged. Adds `test_ignored_items_reported_verbatim` to `test/test_repo.py`; it fails before this change and passes after. `ruff check`, `ruff format --check` and `mypy` pass. The full pytest suite run locally fails the same 83 tests with and without this change; those failures come from fixture commits missing in the local clone, not from this change.
1 parent 9d3aff0 commit 221defb

2 files changed

Lines changed: 19 additions & 2 deletions

File tree

‎git/repo/base.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from git.compat import defenc, safe_decode
2727
from git.config import GitConfigParser
2828
from git.db import GitCmdObjectDB
29+
from git.diff import _unquote_path
2930
from git.exc import (
3031
GitCommandError,
3132
InvalidGitRepositoryError,
@@ -1158,7 +1159,7 @@ def ignored(self, *paths: PathLike) -> List[str]:
11581159
Subset of those paths which are ignored
11591160
"""
11601161
try:
1161-
proc: str = self.git.check_ignore("--", *paths)
1162+
proc: bytes = self.git.check_ignore("--", *paths, stdout_as_string=False)
11621163
except GitCommandError as err:
11631164
if err.status == 1:
11641165
# If return code is 1, this means none of the items in *paths are
@@ -1168,7 +1169,12 @@ def ignored(self, *paths: PathLike) -> List[str]:
11681169
# Raise the exception on all other return codes.
11691170
raise
11701171

1171-
return proc.replace("\\\\", "\\").replace('"', "").split("\n")
1172+
# Git C-quotes a path containing special characters, including a line feed,
1173+
# so each path is on its own line.
1174+
return [
1175+
safe_decode(_unquote_path(path[1:-1]) if path[:1] == path[-1:] == b'"' else path)
1176+
for path in proc.split(b"\n")
1177+
]
11721178

11731179
@property
11741180
def active_branch(self) -> Head:

‎test/test_repo.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,17 @@ def test_ignored_items_reported(self):
16571657
["included_file.txt", "ignored_file.txt", "included_dir/file.txt", "ignored_dir/file.txt"]
16581658
) == ["ignored_file.txt", "ignored_dir/file.txt"]
16591659

1660+
def test_ignored_items_reported_verbatim(self):
1661+
with tempfile.TemporaryDirectory() as tdir:
1662+
temp_repo = Repo.init(pathlib.Path(tdir) / "repo")
1663+
1664+
with open(pathlib.Path(temp_repo.working_tree_dir) / ".gitignore", "w") as file:
1665+
file.write("*.env\n")
1666+
1667+
# Git C-quotes each of these in its default output format.
1668+
paths = ["donn\u00e9es.env", 'q"uote.env', "tab\t.env", "nl\nx.env"]
1669+
assert temp_repo.ignored(["keep.txt", *paths]) == paths
1670+
16601671
@requires_symlinks
16611672
def test_ignored_raises_error_w_symlink(self):
16621673
with tempfile.TemporaryDirectory() as tdir:

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL