diff --git a/dvc/config.py b/dvc/config.py
index 50cd8feb3..6e1ccd7f5 100644
--- a/dvc/config.py
+++ b/dvc/config.py
@@ -179,6 +179,7 @@ SCHEMA = {
                     "gdrive_service_account_email": str,
                     "gdrive_service_account_user_email": str,
                     "gdrive_service_account_p12_file_path": str,
+                    Optional("gdrive_trash_only", default=False): Bool,
                     **REMOTE_COMMON,
                 },
                 "http": {**HTTP_COMMON, **REMOTE_COMMON},
diff --git a/dvc/path_info.py b/dvc/path_info.py
index 613a76c01..4f757b00b 100644
--- a/dvc/path_info.py
+++ b/dvc/path_info.py
@@ -115,7 +115,7 @@ class URLInfo(_BasePath):
         assert not p.query and not p.params and not p.fragment
         assert p.password is None
 
-        self.fill_parts(p.scheme, p.hostname, p.username, p.port, p.path)
+        self._fill_parts(p.scheme, p.hostname, p.username, p.port, p.path)
 
     @classmethod
     def from_parts(
@@ -127,10 +127,10 @@ class URLInfo(_BasePath):
             return cls("{}://{}{}".format(scheme, netloc, path))
 
         obj = cls.__new__(cls)
-        obj.fill_parts(scheme, host, user, port, path)
+        obj._fill_parts(scheme, host, user, port, path)
         return obj
 
-    def fill_parts(self, scheme, host, user, port, path):
+    def _fill_parts(self, scheme, host, user, port, path):
         assert scheme != "remote"
         assert isinstance(path, (str, bytes, _URLPathInfo))
 
@@ -244,6 +244,8 @@ class CloudURLInfo(URLInfo):
 
 
 class HTTPURLInfo(URLInfo):
+    __hash__ = URLInfo.__hash__
+
     def __init__(self, url):
         p = urlparse(url)
         stripped = p._replace(params=None, query=None, fragment=None)
@@ -280,7 +282,7 @@ class HTTPURLInfo(URLInfo):
             )
 
         obj = cls.__new__(cls)
-        obj.fill_parts(scheme, host, user, port, path)
+        obj._fill_parts(scheme, host, user, port, path)
         obj.params = params
         obj.query = query
         obj.fragment = fragment
@@ -314,6 +316,3 @@ class HTTPURLInfo(URLInfo):
             and self._path == other._path
             and self._extra_parts == other._extra_parts
         )
-
-    def __hash__(self):
-        return hash(self.parts)
diff --git a/dvc/remote/gdrive.py b/dvc/remote/gdrive.py
index 484bd1a82..a695dd09b 100644
--- a/dvc/remote/gdrive.py
+++ b/dvc/remote/gdrive.py
@@ -39,12 +39,14 @@ class GDriveMissedCredentialKeyError(DvcException):
 
 
 def gdrive_retry(func):
-    retry_re = re.compile(r"HttpError (403|500|502|503|504)")
-
     def should_retry(exc):
         from pydrive2.files import ApiRequestError
 
-        return isinstance(exc, ApiRequestError) and retry_re.search(str(exc))
+        if not isinstance(exc, ApiRequestError):
+            return False
+
+        retry_codes = [403, 500, 502, 503, 504]
+        return exc.error.get("code", 0) in retry_codes
 
     # 15 tries, start at 0.5s, multiply by golden ratio, cap at 20s
     return retry(
@@ -54,6 +56,19 @@ def gdrive_retry(func):
     )(func)
 
 
+def _location(exc):
+    from pydrive2.files import ApiRequestError
+
+    assert isinstance(exc, ApiRequestError)
+
+    # https://cloud.google.com/storage/docs/json_api/v1/status-codes#errorformat
+    return (
+        exc.error["errors"][0].get("location", "")
+        if exc.error.get("errors", [])
+        else ""
+    )
+
+
 class GDriveURLInfo(CloudURLInfo):
     def __init__(self, url):
         super().__init__(url)
@@ -95,6 +110,7 @@ class RemoteGDrive(RemoteBASE):
             )
 
         self._bucket = self.path_info.bucket
+        self._trash_only = config.get("gdrive_trash_only")
         self._use_service_account = config.get("gdrive_use_service_account")
         self._service_account_email = config.get(
             "gdrive_service_account_email"
@@ -119,8 +135,6 @@ class RemoteGDrive(RemoteBASE):
             )
         )
 
-        self._list_params = None
-
     def _validate_config(self):
         # Validate Service Account configuration
         if self._use_service_account and (
@@ -326,10 +340,35 @@ class RemoteGDrive(RemoteBASE):
 
     @gdrive_retry
     def _delete_remote_file(self, remote_id):
+        from pydrive2.files import ApiRequestError
+
         param = {"id": remote_id}
         # it does not create a file on the remote
         item = self.drive.CreateFile(param)
-        item.Delete()
+
+        try:
+            item.Trash() if self._trash_only else item.Delete()
+        except ApiRequestError as exc:
+            http_error_code = exc.error.get("code", 0)
+            if (
+                http_error_code == 403
+                and self.list_params["corpora"] == "drive"
+                and _location(exc) == "file.permissions"
+            ):
+                raise DvcException(
+                    "Insufficient permissions to {}. You should have {} "
+                    "access level for the used shared drive. More details "
+                    "at {}.".format(
+                        "move the file into Trash"
+                        if self._trash_only
+                        else "permanently delete the file",
+                        "Manager or Content Manager"
+                        if self._trash_only
+                        else "Manager",
+                        "https://support.google.com/a/answer/7337554",
+                    )
+                ) from exc
+            raise
 
     @gdrive_retry
     def _get_remote_item(self, name, parents_ids):
diff --git a/dvc/remote/local.py b/dvc/remote/local.py
index 25d409f67..7a93434f3 100644
--- a/dvc/remote/local.py
+++ b/dvc/remote/local.py
@@ -448,13 +448,17 @@ class RemoteLOCAL(RemoteBASE):
         try:
             os.chmod(path, mode)
         except OSError as exc:
-            # In share cache scenario, we might not own the cache file, so we
+            # There is nothing we need to do in case of a read-only file system
+            if exc.errno == errno.EROFS:
+                return
+
+            # In shared cache scenario, we might not own the cache file, so we
             # need to check if cache file is already protected.
             if exc.errno not in [errno.EPERM, errno.EACCES]:
                 raise
 
-            actual = os.stat(path).st_mode
-            if actual & mode != mode:
+            actual = stat.S_IMODE(os.stat(path).st_mode)
+            if actual != mode:
                 raise
 
     def _get_unpacked_dir_path_info(self, checksum):
diff --git a/dvc/repo/diff.py b/dvc/repo/diff.py
index 9c54e7bc1..d18389e05 100644
--- a/dvc/repo/diff.py
+++ b/dvc/repo/diff.py
@@ -3,6 +3,7 @@ import os
 from dvc.exceptions import DvcException
 from dvc.repo import locked
 from dvc.scm.git import Git
+from dvc.scm.tree import is_working_tree
 
 
 @locked
@@ -36,10 +37,23 @@ def diff(self, a_rev="HEAD", b_rev=None):
                 else os.path.join(str(output), "")
             )
 
+        on_working_tree = is_working_tree(self.tree)
+
+        def _to_checksum(output):
+            if on_working_tree:
+                return self.cache.local.get_checksum(output.path_info)
+            return output.checksum
+
+        def _exists(output):
+            if on_working_tree:
+                return output.exists
+            return True
+
         return {
-            _to_path(output): output.checksum
+            _to_path(output): _to_checksum(output)
             for stage in self.stages
             for output in stage.outs
+            if _exists(output)
         }
 
     working_tree = self.tree
diff --git a/dvc/repo/metrics/diff.py b/dvc/repo/metrics/diff.py
index 1ed20e387..ef25d09d8 100644
--- a/dvc/repo/metrics/diff.py
+++ b/dvc/repo/metrics/diff.py
@@ -68,7 +68,11 @@ def _diff(old_raw, new_raw):
     if isinstance(new, dict) or isinstance(old, dict):
         return _diff_dicts(old, new)
 
-    return {"": _diff_vals(old, new)}
+    val_diff = _diff_vals(old, new)
+    if val_diff:
+        return {"": val_diff}
+
+    return {}
 
 
 def _get_metrics(repo, *args, rev=None, **kwargs):
diff --git a/dvc/version.py b/dvc/version.py
index ce5f6b8e6..9ffc08ac6 100644
--- a/dvc/version.py
+++ b/dvc/version.py
@@ -7,7 +7,7 @@ import os
 import subprocess
 
 
-_BASE_VERSION = "0.91.0"
+_BASE_VERSION = "0.91.1"
 
 
 def _generate_version(base_version):
diff --git a/setup.py b/setup.py
index d9a29bbc3..573024882 100644
--- a/setup.py
+++ b/setup.py
@@ -88,7 +88,7 @@ install_requires = [
 # Extra dependencies for remote integrations
 
 gs = ["google-cloud-storage==1.19.0"]
-gdrive = ["pydrive2>=1.4.6"]
+gdrive = ["pydrive2>=1.4.8"]
 s3 = ["boto3>=1.9.201"]
 azure = ["azure-storage-blob==2.1.0"]
 oss = ["oss2==2.6.1"]

diff: compare dirty vs committed workspace by default
By default `dvc diff` compares workspace to HEAD (or to a single commit if only one arg is provided). This is the one of the most important use cases. I would like to see the "uncommitted" (in a DVC-sense - when we update md5) changes to data files and directories:

```
git clone https://github.com/iterative/example-get-started
cd example-get-started
dvc pull
rm -f data/data.xml
touch data/features/foo
dvc diff
```

The last command produces an empty result. Not very informative to compare my "current" experiment with the baseline.

UPDATE:

Another interesting point that `dvc status` does exactly this - it analyzes actual changes.

diff --git a/tests/func/test_diff.py b/tests/func/test_diff.py
index bb474cd24..918f5ba40 100644
--- a/tests/func/test_diff.py
+++ b/tests/func/test_diff.py
@@ -159,21 +159,51 @@ def test_directories(tmp_dir, scm, dvc):
 
 
 def test_diff_no_cache(tmp_dir, scm, dvc):
-    (stage,) = tmp_dir.dvc_gen(
-        {"dir": {"file": "file content"}}, commit="first"
-    )
+    tmp_dir.dvc_gen({"dir": {"file": "file content"}}, commit="first")
     scm.tag("v1")
+
     tmp_dir.dvc_gen(
         {"dir": {"file": "modified file content"}}, commit="second"
     )
+    scm.tag("v2")
 
-    remove(first(stage.outs).cache_path)
-    remove("dir")
+    remove(dvc.cache.local.cache_dir)
 
     # invalidate_dir_info to force cache loading
     dvc.cache.local._dir_info = {}
 
-    diff = dvc.diff("v1")
+    diff = dvc.diff("v1", "v2")
     assert diff["added"] == []
     assert diff["deleted"] == []
     assert first(diff["modified"])["path"] == os.path.join("dir", "")
+
+
+def test_diff_dirty(tmp_dir, scm, dvc):
+    tmp_dir.dvc_gen(
+        {"file": "file_content", "dir": {"dir_file1": "dir file content"}},
+        commit="initial",
+    )
+
+    (tmp_dir / "file").unlink()
+    tmp_dir.gen({"dir": {"dir_file2": "dir file 2 content"}})
+    tmp_dir.dvc_gen("new_file", "new_file_content")
+
+    result = dvc.diff()
+
+    assert result == {
+        "added": [
+            {"hash": "86d049de17c76ac44cdcac146042ec9b", "path": "new_file"}
+        ],
+        "deleted": [
+            {"hash": "7f0b6bb0b7e951b7fd2b2a4a326297e1", "path": "file"}
+        ],
+        "modified": [
+            {
+                "hash": {
+                    "new": "38175ad60f0e58ac94e0e2b7688afd81.dir",
+                    "old": "92daf39af116ca2fb245acaeb2ae65f7.dir",
+                },
+                "path": os.path.join("dir", ""),
+            }
+        ],
+    }
diff --git a/tests/func/test_metrics.py b/tests/func/test_metrics.py
index 8339b45ba..fab19c86d 100644
--- a/tests/func/test_metrics.py
+++ b/tests/func/test_metrics.py
@@ -895,6 +895,20 @@ def test_metrics_diff_raw(tmp_dir, scm, dvc):
     }
 
 
+def test_metrics_diff_raw_unchanged(tmp_dir, scm, dvc):
+    def _gen(val):
+        tmp_dir.gen({"metrics": val})
+        dvc.run(cmd="", metrics=["metrics"])
+        dvc.scm.add(["metrics.dvc"])
+        dvc.scm.commit(str(val))
+
+    _gen("raw 1")
+    _gen("raw 2")
+    _gen("raw 1")
+
+    assert dvc.metrics.diff(a_rev="HEAD~2") == {}
+
+
 @pytest.mark.parametrize("xpath", [True, False])
 def test_metrics_diff_json(tmp_dir, scm, dvc, xpath):
     def _gen(val):
@@ -919,6 +933,25 @@ def test_metrics_diff_json(tmp_dir, scm, dvc, xpath):
     assert expected == dvc.metrics.diff(a_rev="HEAD~2")
 
 
+@pytest.mark.parametrize("xpath", [True, False])
+def test_metrics_diff_json_unchanged(tmp_dir, scm, dvc, xpath):
+    def _gen(val):
+        metrics = {"a": {"b": {"c": val, "d": 1, "e": str(val)}}}
+        tmp_dir.gen({"m.json": json.dumps(metrics)})
+        dvc.run(cmd="", metrics=["m.json"])
+        dvc.metrics.modify("m.json", typ="json")
+        if xpath:
+            dvc.metrics.modify("m.json", xpath="a.b.c")
+        dvc.scm.add(["m.json.dvc"])
+        dvc.scm.commit(str(val))
+
+    _gen(1)
+    _gen(2)
+    _gen(1)
+
+    assert dvc.metrics.diff(a_rev="HEAD~2") == {}
+
+
 def test_metrics_diff_broken_json(tmp_dir, scm, dvc):
     metrics = {"a": {"b": {"c": 1, "d": 1, "e": "3"}}}
     tmp_dir.gen({"m.json": json.dumps(metrics)})
diff --git a/tests/unit/remote/test_local.py b/tests/unit/remote/test_local.py
index d18e3b4fb..04e216bde 100644
--- a/tests/unit/remote/test_local.py
+++ b/tests/unit/remote/test_local.py
@@ -1,4 +1,5 @@
 import os
+import errno
 
 import pytest
 
@@ -58,3 +59,30 @@ def test_is_protected(tmp_dir, link_name):
         assert remote.is_protected(foo)
     else:
         assert not remote.is_protected(foo)
+
+
+@pytest.mark.parametrize("err", [errno.EPERM, errno.EACCES])
+def test_protect_ignore_errors(tmp_dir, mocker, err):
+    tmp_dir.gen("foo", "foo")
+    foo = PathInfo("foo")
+    remote = RemoteLOCAL(None, {})
+
+    remote.protect(foo)
+
+    mock_chmod = mocker.patch(
+        "os.chmod", side_effect=OSError(err, "something")
+    )
+    remote.protect(foo)
+    assert mock_chmod.called
+
+
+def test_protect_ignore_erofs(tmp_dir, mocker):
+    tmp_dir.gen("foo", "foo")
+    foo = PathInfo("foo")
+    remote = RemoteLOCAL(None, {})
+
+    mock_chmod = mocker.patch(
+        "os.chmod", side_effect=OSError(errno.EROFS, "read-only fs")
+    )
+    remote.protect(foo)
+    assert mock_chmod.called

pip install -e .[all]
parse_log_pytest
pytest
pytest pytest-cov pytest-xdist pytest-mock pytest-lazy-fixture flaky mock xmltodict awscli google-compute-engine Pygments collective.checkdocs flake8 psutil flake8-docstrings pydocstyle jaraco.windows mock-ssh-server moto rangehttpserver beautifulsoup4 flake8-bugbear flake8-comprehensions flake8-string-format pylint pylint-pytest pylint-plugin-utils wget filelock
apt-get update apt-get install -y gcc
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aliyun-python-sdk-core==2.16.0
aliyun-python-sdk-core-v3==2.13.33
aliyun-python-sdk-kms==2.16.5
appdirs==1.4.4
astroid==2.15.8
atpublic==3.1.2
attrs @ file:///croot/attrs_1668696182826/work
autocommand==2.2.2
awscli==1.31.13
azure-common==1.1.28
azure-storage-blob==2.1.0
azure-storage-common==2.1.0
bcrypt==4.2.1
beautifulsoup4==4.13.3
boto==2.49.0
boto3==1.33.13
botocore==1.33.13
cachetools==4.2.4
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
collective.checkdocs==0.2
colorama==0.4.4
configobj==5.0.9
coverage==7.2.7
crcmod==1.7
cryptography==44.0.2
decorator==5.1.1
dill==0.3.7
distro==1.9.0
docutils==0.16
dpath==2.2.0
-e git+https://github.com/iterative/dvc.git@9de8d1e0faf6cc9460cd2e1e30835ac64fc6ff4d#egg=dvc
execnet==2.0.2
filelock==3.12.2
flake8==5.0.4
flake8-bugbear==23.3.12
flake8-comprehensions==3.13.0
flake8-docstrings==1.7.0
flake8-string-format==0.3.0
flaky==3.8.1
flatten-json==0.1.14
flit_core @ file:///opt/conda/conda-bld/flit-core_1644941570762/work/source/flit_core
flufl.lock==7.1.1
funcy==2.0
future==1.0.0
gitdb==4.0.12
GitPython==3.1.44
google-api-core==2.10.2
google-api-python-client==2.166.0
google-auth==1.35.0
google-auth-httplib2==0.2.0
google-cloud-core==1.7.3
google-cloud-storage==1.19.0
google-compute-engine==2.8.13
google-crc32c==1.5.0
google-resumable-media==2.7.2
googleapis-common-protos==1.69.2
grandalf==0.6
httplib2==0.22.0
humanize==4.6.0
idna==3.10
importlib-metadata==4.2.0
importlib-resources==5.12.0
inflect==3.0.2
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
isort==5.11.5
jaraco.classes==3.2.3
jaraco.collections==4.2.0
jaraco.context==4.3.0
jaraco.functools==3.7.0
jaraco.structures==2.1.0
jaraco.text==3.11.1
jaraco.ui==2.3.0
jaraco.windows==5.7.0
Jinja2==3.1.6
jmespath==0.10.0
jsonpath-ng==1.7.0
lazy-object-proxy==1.9.0
MarkupSafe==2.1.5
mccabe==0.7.0
mock==5.2.0
mock-ssh-server==0.9.1
more-itertools==9.1.0
moto==4.2.14
nanotime==0.5.2
networkx==2.3
numpy==1.21.6
oauth2client==4.1.3
oss2==2.6.1
packaging @ file:///croot/packaging_1671697413597/work
paramiko==3.5.1
path==16.6.0
pathspec==0.11.2
platformdirs==4.0.0
pluggy @ file:///tmp/build/80754af9/pluggy_1648042572264/work
ply==3.11
protobuf==4.24.4
psutil==7.0.0
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyarrow==0.15.1
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycodestyle==2.9.1
pycparser==2.21
pycryptodome==3.22.0
pydantic==1.10.21
pydocstyle==6.3.0
pydot==2.0.0
PyDrive2==1.15.4
pyflakes==2.5.0
Pygments==2.17.2
pygtrie==2.3.2
pylint==2.17.7
pylint-plugin-utils==0.8.2
pylint-pytest==1.1.8
PyNaCl==1.5.0
pyOpenSSL==25.0.0
pyparsing==3.1.4
pytest==7.1.2
pytest-cov==4.1.0
pytest-lazy-fixture==0.6.3
pytest-mock==3.11.1
pytest-xdist==3.5.0
python-dateutil==2.8.0
PyYAML==5.1.2
rangehttpserver==1.4.0
requests==2.31.0
responses==0.23.3
rsa==4.7.2
ruamel.yaml==0.18.10
ruamel.yaml.clib==0.2.8
s3transfer==0.8.2
shortuuid==1.0.13
six==1.17.0
smmap==5.0.2
snowballstemmer==2.2.0
soupsieve==2.4.1
texttable==1.7.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
tomlkit==0.12.5
tqdm==4.67.1
treelib==1.7.1
typed-ast==1.5.5
types-PyYAML==6.0.12.12
typing_extensions==4.7.1
uritemplate==4.1.1
urllib3==1.26.20
voluptuous==0.14.1
Werkzeug==2.2.3
wget==3.2
wrapt==1.16.0
xmltodict==0.14.2
zc.lockfile==3.0.post1
zipp @ file:///croot/zipp_1672387121353/work

name: dvc
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=22.1.0=py37h06a4308_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=22.0=py37h06a4308_0
  - pip=22.3.1=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - py=1.11.0=pyhd3eb1b0_0
  - pytest=7.1.2=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py37h06a4308_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aliyun-python-sdk-core==2.16.0
      - aliyun-python-sdk-core-v3==2.13.33
      - aliyun-python-sdk-kms==2.16.5
      - appdirs==1.4.4
      - astroid==2.15.8
      - atpublic==3.1.2
      - autocommand==2.2.2
      - awscli==1.31.13
      - azure-common==1.1.28
      - azure-storage-blob==2.1.0
      - azure-storage-common==2.1.0
      - bcrypt==4.2.1
      - beautifulsoup4==4.13.3
      - boto==2.49.0
      - boto3==1.33.13
      - botocore==1.33.13
      - cachetools==4.2.4
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - collective-checkdocs==0.2
      - colorama==0.4.4
      - configobj==5.0.9
      - coverage==7.2.7
      - crcmod==1.7
      - cryptography==44.0.2
      - decorator==5.1.1
      - dill==0.3.7
      - distro==1.9.0
      - docutils==0.16
      - dpath==2.2.0
      - dvc==0.91.0+9de8d1
      - execnet==2.0.2
      - filelock==3.12.2
      - flake8==5.0.4
      - flake8-bugbear==23.3.12
      - flake8-comprehensions==3.13.0
      - flake8-docstrings==1.7.0
      - flake8-string-format==0.3.0
      - flaky==3.8.1
      - flatten-json==0.1.14
      - flufl-lock==7.1.1
      - funcy==2.0
      - future==1.0.0
      - gitdb==4.0.12
      - gitpython==3.1.44
      - google-api-core==2.10.2
      - google-api-python-client==2.166.0
      - google-auth==1.35.0
      - google-auth-httplib2==0.2.0
      - google-cloud-core==1.7.3
      - google-cloud-storage==1.19.0
      - google-compute-engine==2.8.13
      - google-crc32c==1.5.0
      - google-resumable-media==2.7.2
      - googleapis-common-protos==1.69.2
      - grandalf==0.6
      - httplib2==0.22.0
      - humanize==4.6.0
      - idna==3.10
      - importlib-metadata==4.2.0
      - importlib-resources==5.12.0
      - inflect==3.0.2
      - isort==5.11.5
      - jaraco-classes==3.2.3
      - jaraco-collections==4.2.0
      - jaraco-context==4.3.0
      - jaraco-functools==3.7.0
      - jaraco-structures==2.1.0
      - jaraco-text==3.11.1
      - jaraco-ui==2.3.0
      - jaraco-windows==5.7.0
      - jinja2==3.1.6
      - jmespath==0.10.0
      - jsonpath-ng==1.7.0
      - lazy-object-proxy==1.9.0
      - markupsafe==2.1.5
      - mccabe==0.7.0
      - mock==5.2.0
      - mock-ssh-server==0.9.1
      - more-itertools==9.1.0
      - moto==4.2.14
      - nanotime==0.5.2
      - networkx==2.3
      - numpy==1.21.6
      - oauth2client==4.1.3
      - oss2==2.6.1
      - paramiko==3.5.1
      - path==16.6.0
      - pathspec==0.11.2
      - platformdirs==4.0.0
      - ply==3.11
      - protobuf==4.24.4
      - psutil==7.0.0
      - pyarrow==0.15.1
      - pyasn1==0.5.1
      - pyasn1-modules==0.3.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pycryptodome==3.22.0
      - pydantic==1.10.21
      - pydocstyle==6.3.0
      - pydot==2.0.0
      - pydrive2==1.15.4
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pygtrie==2.3.2
      - pylint==2.17.7
      - pylint-plugin-utils==0.8.2
      - pylint-pytest==1.1.8
      - pynacl==1.5.0
      - pyopenssl==25.0.0
      - pyparsing==3.1.4
      - pytest-cov==4.1.0
      - pytest-lazy-fixture==0.6.3
      - pytest-mock==3.11.1
      - pytest-xdist==3.5.0
      - python-dateutil==2.8.0
      - pyyaml==5.1.2
      - rangehttpserver==1.4.0
      - requests==2.31.0
      - responses==0.23.3
      - rsa==4.7.2
      - ruamel-yaml==0.18.10
      - ruamel-yaml-clib==0.2.8
      - s3transfer==0.8.2
      - shortuuid==1.0.13
      - six==1.17.0
      - smmap==5.0.2
      - snowballstemmer==2.2.0
      - soupsieve==2.4.1
      - texttable==1.7.0
      - tomlkit==0.12.5
      - tqdm==4.67.1
      - treelib==1.7.1
      - typed-ast==1.5.5
      - types-pyyaml==6.0.12.12
      - typing-extensions==4.7.1
      - uritemplate==4.1.1
      - urllib3==1.26.20
      - voluptuous==0.14.1
      - werkzeug==2.2.3
      - wget==3.2
      - wrapt==1.16.0
      - xmltodict==0.14.2
      - zc-lockfile==3.0.post1
prefix: /opt/conda/envs/dvc

tests/func/test_diff.py::test_diff_dirty tests/func/test_metrics.py::test_metrics_diff_raw_unchanged tests/unit/remote/test_local.py::test_protect_ignore_erofs
tests/func/test_diff.py::test_no_scm tests/func/test_diff.py::test_added tests/func/test_diff.py::test_no_cache_entry tests/func/test_diff.py::test_deleted tests/func/test_diff.py::test_modified tests/func/test_diff.py::test_refs tests/func/test_diff.py::test_directories tests/func/test_diff.py::test_diff_no_cache tests/func/test_metrics.py::test_show_dirty tests/func/test_metrics.py::TestMetrics::test_formatted_output tests/func/test_metrics.py::TestMetrics::test_show tests/func/test_metrics.py::TestMetrics::test_show_all_should_be_current_dir_agnostic tests/func/test_metrics.py::TestMetrics::test_type_case_normalized tests/func/test_metrics.py::TestMetrics::test_unknown_type_ignored tests/func/test_metrics.py::TestMetrics::test_xpath_all tests/func/test_metrics.py::TestMetrics::test_xpath_all_columns tests/func/test_metrics.py::TestMetrics::test_xpath_all_rows tests/func/test_metrics.py::TestMetrics::test_xpath_all_with_header tests/func/test_metrics.py::TestMetrics::test_xpath_is_empty tests/func/test_metrics.py::TestMetrics::test_xpath_is_none tests/func/test_metrics.py::TestMetricsRecursive::test tests/func/test_metrics.py::TestMetricsReproCLI::test tests/func/test_metrics.py::TestMetricsReproCLI::test_binary tests/func/test_metrics.py::TestMetricsReproCLI::test_dir tests/func/test_metrics.py::TestMetricsCLI::test tests/func/test_metrics.py::TestMetricsCLI::test_binary tests/func/test_metrics.py::TestMetricsCLI::test_dir tests/func/test_metrics.py::TestMetricsCLI::test_non_existing tests/func/test_metrics.py::TestMetricsCLI::test_wrong_type_add tests/func/test_metrics.py::TestMetricsCLI::test_wrong_type_modify tests/func/test_metrics.py::TestMetricsCLI::test_wrong_type_show tests/func/test_metrics.py::TestNoMetrics::test tests/func/test_metrics.py::TestNoMetrics::test_cli tests/func/test_metrics.py::TestCachedMetrics::test_add tests/func/test_metrics.py::TestCachedMetrics::test_run tests/func/test_metrics.py::TestMetricsType::test_show tests/func/test_metrics.py::test_display_missing_metrics tests/func/test_metrics.py::test_show_xpath_should_override_stage_xpath tests/func/test_metrics.py::test_show_multiple_outputs tests/func/test_metrics.py::test_metrics_diff_raw tests/func/test_metrics.py::test_metrics_diff_json[True] tests/func/test_metrics.py::test_metrics_diff_json[False] tests/func/test_metrics.py::test_metrics_diff_json_unchanged[True] tests/func/test_metrics.py::test_metrics_diff_json_unchanged[False] tests/func/test_metrics.py::test_metrics_diff_broken_json tests/func/test_metrics.py::test_metrics_diff_no_metrics tests/func/test_metrics.py::test_metrics_diff_new_metric tests/func/test_metrics.py::test_metrics_diff_deleted_metric tests/unit/remote/test_local.py::test_status_download_optimization tests/unit/remote/test_local.py::test_is_protected[hardlink] tests/unit/remote/test_local.py::test_is_protected[symlink] tests/unit/remote/test_local.py::test_protect_ignore_errors[1] tests/unit/remote/test_local.py::test_protect_ignore_errors[13]
dvc/config.py dvc/version.py dvc/remote/gdrive.py setup.py dvc/path_info.py dvc/remote/local.py dvc/repo/metrics/diff.py dvc/repo/diff.py
dvc/config.py dvc/version.py dvc/remote/gdrive.py setup.py dvc/path_info.py dvc/remote/local.py dvc/repo/metrics/diff.py dvc/repo/diff.py