Skip to content

Commit 0bb3f40

Browse files
authored
remove: delete .gitignore file if empty (#5148)
* remove: delete .gitignore file if empty modified behavior to unlink empty .gitignore files. added corresponding unit & func test cases. updated failing test cases. Fixes #4962 * fix failing lint checks * integrating feedback from the code review
1 parent afe9697 commit 0bb3f40

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

dvc/scm/git/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ def ignore_remove(self, path):
165165

166166
filtered = list(filter(lambda x: x.strip() != entry.strip(), lines))
167167

168+
if not filtered:
169+
os.unlink(gitignore)
170+
return
171+
168172
with open(gitignore, "w") as fobj:
169173
fobj.writelines(filtered)
170174

tests/func/test_remove.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_remove(tmp_dir, scm, dvc, run_copy, remove_outs):
2929
else:
3030
assert all(out_exists)
3131

32-
assert not any(out in get_gitignore_content() for out in stage.outs)
32+
assert not (tmp_dir / ".gitignore").exists()
3333

3434

3535
def test_remove_non_existent_file(tmp_dir, dvc):
@@ -69,3 +69,29 @@ def test_cmd_remove(tmp_dir, dvc):
6969
assert main(["remove", stage.addressing, "--outs"]) == 0
7070
assert not (tmp_dir / stage.relpath).exists()
7171
assert not (tmp_dir / "foo").exists()
72+
73+
74+
def test_cmd_remove_gitignore_single_stage(tmp_dir, scm, dvc, run_copy):
75+
stage = dvc.run(
76+
name="my", cmd='echo "hello" > out', deps=[], outs=["out"],
77+
)
78+
79+
assert (tmp_dir / ".gitignore").exists()
80+
81+
assert main(["remove", stage.addressing]) == 0
82+
assert not (tmp_dir / stage.relpath).exists()
83+
assert not (stage.dvcfile._lockfile).exists()
84+
assert not (tmp_dir / ".gitignore").exists()
85+
86+
87+
def test_cmd_remove_gitignore_multistage(tmp_dir, scm, dvc, run_copy):
88+
(stage,) = tmp_dir.dvc_gen("foo", "foo")
89+
stage1 = run_copy("foo", "foo1", single_stage=True)
90+
stage2 = run_copy("foo1", "foo2", name="copy-foo1-foo2")
91+
92+
assert (tmp_dir / ".gitignore").exists()
93+
94+
assert main(["remove", stage2.addressing]) == 0
95+
assert main(["remove", stage1.addressing]) == 0
96+
assert main(["remove", stage.addressing]) == 0
97+
assert not (tmp_dir / ".gitignore").exists()

tests/func/test_scm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def test_ignore(tmp_dir, scm):
8585
assert _count_gitignore_entries(target) == 1
8686

8787
scm.ignore_remove(foo)
88-
assert _count_gitignore_entries(target) == 0
88+
assert not (tmp_dir / ".gitignore").exists()
8989

9090

9191
def test_ignored(tmp_dir, scm):

tests/unit/scm/test_git.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,25 @@ def test_list_all_commits(tmp_dir, scm):
279279
scm.set_ref("refs/foo/bar", rev_c)
280280

281281
assert {rev_a, rev_b} == set(scm.list_all_commits())
282+
283+
284+
def test_ignore_remove_empty(tmp_dir, scm, git):
285+
286+
test_entries = [
287+
{"entry": "/foo1", "path": f"{tmp_dir}/foo1"},
288+
{"entry": "/foo2", "path": f"{tmp_dir}/foo2"},
289+
]
290+
291+
path_to_gitignore = tmp_dir / ".gitignore"
292+
293+
with open(path_to_gitignore, "a") as f:
294+
for entry in test_entries:
295+
f.write(entry["entry"] + "\n")
296+
297+
assert path_to_gitignore.exists()
298+
299+
git.ignore_remove(test_entries[0]["path"])
300+
assert path_to_gitignore.exists()
301+
302+
git.ignore_remove(test_entries[1]["path"])
303+
assert not path_to_gitignore.exists()

0 commit comments

Comments
 (0)