Repository: iterative/dvc

Issue:
`exp run`: data gets re-imported on every call
# Bug Report

## Description

When a pipeline uses an imported data file (with `dvc import`), the data gets cloned(?) and hashed every time `dvc exp run` is called.

### Reproduce

1. dvc import git@github.com:iterative/dataset-registry.git use-cases/cats-dogs
2. dvc stage add -n foo -d cats-dogs echo foo
3. dvc exp run

### Expected

When using `dvc repro` the imported data doesn't get re-hashed. I would expect `dvc exp run` to behave the same.

### Environment information

**Output of `dvc doctor`:**

```console
$ dvc doctor
DVC version: 2.6.3 (pip)
---------------------------------
Platform: Python 3.9.6 on macOS-10.16-x86_64-i386-64bit
Supports:
        gdrive (pydrive2 = 1.9.1),
        http (requests = 2.26.0),
        https (requests = 2.26.0)
Cache types: reflink, hardlink, symlink
Cache directory: apfs on /dev/disk1s1s1
Caches: local
Remotes: None
Workspace directory: apfs on /dev/disk1s1s1
Repo: dvc, git
```

**Additional Information (if any):**

```console
$ dvc repro -v
2021-08-25 11:11:55,186 DEBUG: Computed stage: 'cats-dogs.dvc' md5: '5a135b297ee3c96465ce4b320f44fb8b'
'cats-dogs.dvc' didn't change, skipping
Stage 'foo' didn't change, skipping
Data and pipelines are up to date.
```

```console
$ dvc exp run -v
2021-08-25 11:12:15,672 DEBUG: Detaching HEAD at 'HEAD'               
2021-08-25 11:12:15,690 DEBUG: Stashing workspace
2021-08-25 11:12:15,700 DEBUG: No changes to stash
2021-08-25 11:12:15,749 DEBUG: Creating external repo git@github.com:iterative/dataset-registry.git@ca140591a21c6d75a7057d1e2eb3f51d3115c5f5
2021-08-25 11:12:15,749 DEBUG: erepo: git clone 'git@github.com:iterative/dataset-registry.git' to a temporary dir
Computing file/dir hashes (only done once)  
. . .                                                                         
```




Discussion:
Issue occurs because we force `dvc commit` to preserve any initial changes to DVC data in the experiment. The problem is that the `dvc commit` implementation uses `stage.changed_entries()` to determine whether or not it needs to call `stage.save()`

https://github.com/iterative/dvc/blob/ed2ccaf54c4106db757bcdcfbaf6d82af8af8b2c/dvc/repo/commit.py#L57-L65

`stage.changed_entries()` returns `workspace_status()` which is fine for everything except imports. In the import case, `workspace_status` actually reports whether or not an upstream update is available, which requires this additional erepo clone to check the upstream, and is not particularly useful in the `dvc commit` case, except maybe as a warning to the user that they may have forgotten to do a `dvc update`.

In the even that we call commit with `force=True` we should definitely be skipping this status check for imports, and I'm not entirely sure it's still useful even when `force=False`

Resolving patch:
diff --git a/dvc/repo/commit.py b/dvc/repo/commit.py
--- a/dvc/repo/commit.py
+++ b/dvc/repo/commit.py
@@ -56,10 +56,13 @@ def commit(
     ]
     for stage_info in stages_info:
         stage = stage_info.stage
-        changes = stage.changed_entries()
-        if any(changes):
-            prompt_to_commit(stage, changes, force=force)
+        if force:
             stage.save(allow_missing=allow_missing)
+        else:
+            changes = stage.changed_entries()
+            if any(changes):
+                prompt_to_commit(stage, changes, force=force)
+                stage.save(allow_missing=allow_missing)
         stage.commit(
             filter_info=stage_info.filter_info, allow_missing=allow_missing
         )


Test patch: