Skip to content

Commit e2981d2

Browse files
authored
git: is_tracked: use ls_files instead of walking the index (#3677)
Current implementation doesn't work with directories, which results in hard-to-debug bugs like #3561. The bug that made us walk through index manually is now fixed in gitpython, so we can simply use `ls_files` from now on. Added some tests to prevent this from happening in the future. Fixes #3561
1 parent ae9bc91 commit e2981d2

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

dvc/scm/git/__init__.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,11 +271,7 @@ def untracked_files(self):
271271
return [os.path.join(self.repo.working_dir, fname) for fname in files]
272272

273273
def is_tracked(self, path):
274-
# it is equivalent to `bool(self.repo.git.ls_files(path))` by
275-
# functionality, but ls_files fails on unicode filenames
276-
path = relpath(path, self.root_dir)
277-
# There are 4 stages, see BaseIndexEntry.stage
278-
return any((path, i) in self.repo.index.entries for i in (0, 1, 2, 3))
274+
return bool(self.repo.git.ls_files(path))
279275

280276
def is_dirty(self):
281277
return self.repo.is_dirty()

tests/unit/scm/test_git.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,37 @@ def test_walk_with_submodules(tmp_dir, scm, git_dir):
3737
# currently we don't walk through submodules
3838
assert not dirs
3939
assert set(files) == {".gitmodules", "submodule"}
40+
41+
42+
def test_is_tracked(tmp_dir, scm):
43+
tmp_dir.scm_gen(
44+
{
45+
"tracked": "tracked",
46+
"dir": {"data": "data", "subdir": {"subdata": "subdata"}},
47+
},
48+
commit="add dirs and files",
49+
)
50+
tmp_dir.gen({"untracked": "untracked", "dir": {"untracked": "untracked"}})
51+
52+
# sanity check
53+
assert (tmp_dir / "untracked").exists()
54+
assert (tmp_dir / "tracked").exists()
55+
assert (tmp_dir / "dir" / "untracked").exists()
56+
assert (tmp_dir / "dir" / "data").exists()
57+
assert (tmp_dir / "dir" / "subdir" / "subdata").exists()
58+
59+
assert not scm.is_tracked("untracked")
60+
assert not scm.is_tracked(os.path.join("dir", "untracked"))
61+
62+
assert scm.is_tracked("tracked")
63+
assert scm.is_tracked("dir")
64+
assert scm.is_tracked(os.path.join("dir", "data"))
65+
assert scm.is_tracked(os.path.join("dir", "subdir"))
66+
assert scm.is_tracked(os.path.join("dir", "subdir", "subdata"))
67+
68+
69+
def test_is_tracked_unicode(tmp_dir, scm):
70+
tmp_dir.scm_gen("ṭṝḁḉḵḗḋ", "tracked", commit="add unicode")
71+
tmp_dir.gen("ṳṋṭṝḁḉḵḗḋ", "untracked")
72+
assert scm.is_tracked("ṭṝḁḉḵḗḋ")
73+
assert not scm.is_tracked("ṳṋṭṝḁḉḵḗḋ")

0 commit comments

Comments
 (0)