# Buggy code
def diff(self, a_rev="HEAD", b_rev=None):
    """
    By default, it compares the workspace with the last commit's tree.

    This implementation differs from `git diff` since DVC doesn't have
    the concept of `index`, but it keeps the same interface, thus,
    `dvc diff` would be the same as `dvc diff HEAD`.
    """

    def _paths_checksums():
        """
        A dictionary of checksums addressed by relpaths collected from
        the current tree outputs.

        To help distinguish between a directory and a file output,
        the former one will come with a trailing slash in the path:

            directory: "data/"
            file:      "data"
        """

        def _to_path(output):
            return (
                str(output)
                if not output.is_dir_checksum
                else os.path.join(str(output), "")
            )

        on_working_tree = isinstance(self.tree, LocalTree)

        def _to_checksum(output):
            if on_working_tree:
                return self.cache.local.tree.get_hash(output.path_info)[1]
            return output.checksum

        def _exists(output):
            if on_working_tree:
                return output.exists
            return True

        return {
            _to_path(output): _to_checksum(output)
            for stage in self.stages
            for output in stage.outs
            if _exists(output)
        }

    if self.scm.no_commits:
        return {}

    working_tree = self.tree
    a_tree = self.scm.get_tree(a_rev)
    b_tree = self.scm.get_tree(b_rev) if b_rev else working_tree

    try:
        self.tree = a_tree
        old = _paths_checksums()

        self.tree = b_tree
        new = _paths_checksums()
    finally:
        self.tree = working_tree

    # Compare paths between the old and new tree.
    # set() efficiently converts dict keys to a set
    added = sorted(set(new) - set(old))
    deleted = sorted(set(old) - set(new))
    modified = sorted(set(old) & set(new))

    ret = {
        "added": [{"path": path, "hash": new[path]} for path in added],
        "deleted": [{"path": path, "hash": old[path]} for path in deleted],
        "modified": [
            {"path": path, "hash": {"old": old[path], "new": new[path]}}
            for path in modified
            if old[path] != new[path]
        ],
    }

    return ret if any(ret.values()) else {}


# Traceback (dvc.exceptions.RemoteCacheRequiredError)
2020-07-01 17:14:02,947 DEBUG: fetched: [(3,)]
2020-07-01 17:14:03,123 DEBUG: Removing output 'some_target' of stage: 'some_target.dvc'.
Importing 's3://some_bucket/some_target' -> 'some_target'
2020-07-01 17:14:03,123 DEBUG: Computed stage: 'some_target.dvc' md5: '2f8b87d3b22efd1638f414c3b3f65614'
2020-07-01 17:14:03,123 DEBUG: 'md5' of stage: 'some_target.dvc' changed.
2020-07-01 17:14:04,088 DEBUG: fetched: [(0,)]
2020-07-01 17:14:04,146 ERROR: failed to import s3://some_bucket/some_target. You could also try downloading it manually, and adding it with `dvc add`. - Current operation was unsuccessful because 's3://some_bucket/some_target' requires existing cache on 's3' remote. See <https://man.dvc.org/config#cache> for information on how to set up remote cache.
------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python3.8/site-packages/dvc/command/imp_url.py", line 14, in run
self.repo.imp_url(
File "/usr/lib/python3.8/site-packages/dvc/repo/__init__.py", line 36, in wrapper
ret = f(repo, *args, **kwargs)
File "/usr/lib/python3.8/site-packages/dvc/repo/scm_context.py", line 4, in run
result = method(repo, *args, **kw)
File "/usr/lib/python3.8/site-packages/dvc/repo/imp_url.py", line 54, in imp_url
stage.run()
File "/home/anotherbugmaster/.local/lib/python3.8/site-packages/funcy/decorators.py", line 39, in wrapper
return deco(call, *dargs, **dkwargs)
File "/usr/lib/python3.8/site-packages/dvc/stage/decorators.py", line 35, in rwlocked
return call()
File "/home/anotherbugmaster/.local/lib/python3.8/site-packages/funcy/decorators.py", line 60, in __call__
return self._func(*self._args, **self._kwargs)
File "/usr/lib/python3.8/site-packages/dvc/stage/__init__.py", line 424, in run
sync_import(self, dry, force)
File "/usr/lib/python3.8/site-packages/dvc/stage/imports.py", line 29, in sync_import
stage.save_deps()
File "/usr/lib/python3.8/site-packages/dvc/stage/__init__.py", line 387, in save_deps
dep.save()
File "/usr/lib/python3.8/site-packages/dvc/output/base.py", line 268, in save
self.info = self.save_info()
File "/usr/lib/python3.8/site-packages/dvc/output/base.py", line 192, in save_info
return self.remote.save_info(self.path_info)
File "/usr/lib/python3.8/site-packages/dvc/remote/base.py", line 762, in save_info
return self.tree.save_info(path_info, **kwargs)
File "/usr/lib/python3.8/site-packages/dvc/remote/base.py", line 329, in save_info
self.PARAM_CHECKSUM: self.get_hash(path_info, tree=tree, **kwargs)
File "/usr/lib/python3.8/site-packages/dvc/remote/base.py", line 297, in get_hash
hash_ = self.get_dir_hash(path_info, tree, **kwargs)
File "/usr/lib/python3.8/site-packages/dvc/remote/base.py", line 311, in get_dir_hash
raise RemoteCacheRequiredError(path_info)
dvc.exceptions.RemoteCacheRequiredError: Current operation was unsuccessful because 's3://some_bucket/some_target' requires existing cache on 's3' remote. See <https://man.dvc.org/config#cache> for information on how to set up remote cache.
------------------------------------------------------------

Having any troubles? Hit us up at https://dvc.org/support, we are always happy to help!

# Fixed code
def diff(self, a_rev="HEAD", b_rev=None):
    """
    By default, it compares the workspace with the last commit's tree.

    This implementation differs from `git diff` since DVC doesn't have
    the concept of `index`, but it keeps the same interface, thus,
    `dvc diff` would be the same as `dvc diff HEAD`.
    """

    def _paths_checksums():
        """
        A dictionary of checksums addressed by relpaths collected from
        the current tree outputs.

        To help distinguish between a directory and a file output,
        the former one will come with a trailing slash in the path:

            directory: "data/"
            file:      "data"
        """

        def _to_path(output):
            return (
                str(output)
                if not output.is_dir_checksum
                else os.path.join(str(output), "")
            )

        on_working_tree = isinstance(self.tree, LocalTree)

        def _to_checksum(output):
            if on_working_tree:
                return self.cache.local.tree.get_hash(output.path_info).value
            return output.checksum

        def _exists(output):
            if on_working_tree:
                return output.exists
            return True

        return {
            _to_path(output): _to_checksum(output)
            for stage in self.stages
            for output in stage.outs
            if _exists(output)
        }

    if self.scm.no_commits:
        return {}

    working_tree = self.tree
    a_tree = self.scm.get_tree(a_rev)
    b_tree = self.scm.get_tree(b_rev) if b_rev else working_tree

    try:
        self.tree = a_tree
        old = _paths_checksums()

        self.tree = b_tree
        new = _paths_checksums()
    finally:
        self.tree = working_tree

    # Compare paths between the old and new tree.
    # set() efficiently converts dict keys to a set
    added = sorted(set(new) - set(old))
    deleted = sorted(set(old) - set(new))
    modified = sorted(set(old) & set(new))

    ret = {
        "added": [{"path": path, "hash": new[path]} for path in added],
        "deleted": [{"path": path, "hash": old[path]} for path in deleted],
        "modified": [
            {"path": path, "hash": {"old": old[path], "new": new[path]}}
            for path in modified
            if old[path] != new[path]
        ],
    }

    return ret if any(ret.values()) else {}