Repository: iterative/dvc

Issue:
remove: remove dvc.yaml and dvc.lock if they are empty
https://github.com/iterative/dvc/pull/4074#issuecomment-648097445

```
$ cat dvc.lock
{}                                               
$ cat dvc.yaml
stages: {}                                       
```

Discussion:

Patch:
diff --git a/dvc/command/checkout.py b/dvc/command/checkout.py
index ecc750e62..3752342e1 100644
--- a/dvc/command/checkout.py
+++ b/dvc/command/checkout.py
@@ -112,7 +112,9 @@ def add_parser(subparsers, parent_parser):
     checkout_parser.add_argument(
         "targets",
         nargs="*",
-        help="DVC-files to checkout. Optional. "
-        "(Finds all DVC-files in the workspace by default.)",
+        help=(
+            "Limit command scope to these tracked files/directories, "
+            ".dvc files, or stage names."
+        ),
     ).complete = completion.DVC_FILE
     checkout_parser.set_defaults(func=CmdCheckout)
diff --git a/dvc/command/data_sync.py b/dvc/command/data_sync.py
index 3701c59d9..5b931177e 100644
--- a/dvc/command/data_sync.py
+++ b/dvc/command/data_sync.py
@@ -103,8 +103,10 @@ def shared_parent_parser():
     parent_parser.add_argument(
         "targets",
         nargs="*",
-        help="Limit command scope to these DVC-files. "
-        "Using -R, directories to search DVC-files in can also be given.",
+        help=(
+            "Limit command scope to these tracked files/directories, "
+            ".dvc files, or stage names."
+        ),
     ).complete = completion.DVC_FILE
 
     return parent_parser
diff --git a/dvc/dvcfile.py b/dvc/dvcfile.py
index 8269edaa8..5b0f2f38c 100644
--- a/dvc/dvcfile.py
+++ b/dvc/dvcfile.py
@@ -233,7 +233,11 @@ class PipelineFile(FileMixin):
 
         logger.debug("Removing '%s' from '%s'", stage.name, self.path)
         del d["stages"][stage.name]
-        dump_yaml(self.path, d)
+
+        if d["stages"]:
+            dump_yaml(self.path, d)
+        else:
+            super().remove()
 
 
 class Lockfile(FileMixin):
@@ -286,7 +290,10 @@ class Lockfile(FileMixin):
         logger.debug("Removing '%s' from '%s'", stage.name, self.path)
         del d[stage.name]
 
-        dump_yaml(self.path, d)
+        if d:
+            dump_yaml(self.path, d)
+        else:
+            self.remove()
 
 
 class Dvcfile:
diff --git a/dvc/version.py b/dvc/version.py
index 8a041adb4..158982c60 100644
--- a/dvc/version.py
+++ b/dvc/version.py
@@ -6,7 +6,7 @@
 import os
 import subprocess
 
-_BASE_VERSION = "1.1.9"
+_BASE_VERSION = "1.1.10"
 
 
 def _generate_version(base_version):


Test patch:
diff --git a/tests/func/test_dvcfile.py b/tests/func/test_dvcfile.py
index 8c7978d64..5ba42a093 100644
--- a/tests/func/test_dvcfile.py
+++ b/tests/func/test_dvcfile.py
@@ -285,6 +285,23 @@ def test_remove_stage_preserves_comment(tmp_dir, dvc, run_copy):
     )
 
 
+def test_remove_stage_removes_dvcfiles_if_no_stages_left(
+    tmp_dir, dvc, run_copy
+):
+    tmp_dir.gen("foo", "foo")
+    run_copy("foo", "bar", name="run_copy")
+
+    dvc_file = Dvcfile(dvc, PIPELINE_FILE)
+
+    assert dvc_file.exists()
+    assert (tmp_dir / PIPELINE_LOCK).exists()
+    assert (tmp_dir / "foo").exists()
+
+    dvc_file.remove_stage(dvc_file.stages["run_copy"])
+    assert not dvc_file.exists()
+    assert not (tmp_dir / PIPELINE_LOCK).exists()
+
+
 def test_dvcfile_dump_preserves_meta(tmp_dir, dvc, run_copy):
     tmp_dir.gen("foo", "foo")
     stage = run_copy("foo", "bar", name="run_copy")