Repository: pypa/pip

Issue:
pip download behaves differently for editable and non-editable VCS requirements
**Environment**

* pip version: 20.3.3
* Python version: irrelevant
* OS: irrelevant

**Description**

Assume the following `requirements.txt`:

```-e git+https://github.com/pypa/packaging#egg=packaging``` 

```pip download -r requirements.txt``` does a VCS export, hence does not include the `.git`  directory in the resulting zip file.

Without `-e`, the same pip download command produces a zip file that contains the `.git` directory.

**Analysis**

This VCS export mechanism was presumably done as a performance optimization. However it has correctness issues if the build backend requires the VCS information to prepare metadata (#9337).

Possible approaches:

1. Remove the VCS export pip feature: this will be correct but may create performance issues in some scenarios that rely on it (with the presence of a possibly large .git directory in the resulting zip file and a larger download), this is done in #9274.
2. Do a VCS clone for preparing metadata (as it is currently done for non-editable VCS requirements), then do a VCS export (2a) to prepare the zip file, possibly using the local clone as a source (2b), or using the build backend to create a sdist (2c). This will have some performance implications, but produce smaller archives as output (i.e. without the .git directory), and produce the same result with and without `-e`.
3. Keep the discrepancy and do not fix #9337, reintroduce the distinction between pip wheel and pip download in order to fix #9273.


Discussion:

Resolving patch:
diff --git a/src/pip/_internal/operations/prepare.py b/src/pip/_internal/operations/prepare.py
--- a/src/pip/_internal/operations/prepare.py
+++ b/src/pip/_internal/operations/prepare.py
@@ -570,7 +570,7 @@ def prepare_editable_requirement(
                     'hash.'.format(req)
                 )
             req.ensure_has_source_dir(self.src_dir)
-            req.update_editable(self.download_dir is None)
+            req.update_editable()
 
             dist = _get_prepared_distribution(
                 req, self.req_tracker, self.finder, self.build_isolation,
diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py
--- a/src/pip/_internal/req/req_install.py
+++ b/src/pip/_internal/req/req_install.py
@@ -617,8 +617,8 @@ def ensure_has_source_dir(
             )
 
     # For editable installations
-    def update_editable(self, obtain=True):
-        # type: (bool) -> None
+    def update_editable(self):
+        # type: () -> None
         if not self.link:
             logger.debug(
                 "Cannot update repository at %s; repository location is "
@@ -651,10 +651,7 @@ def update_editable(self, obtain=True):
                     )
                 deprecated(reason, replacement, gone_in="21.0", issue=7554)
             hidden_url = hide_url(self.link.url)
-            if obtain:
-                vcs_backend.obtain(self.source_dir, url=hidden_url)
-            else:
-                vcs_backend.export(self.source_dir, url=hidden_url)
+            vcs_backend.obtain(self.source_dir, url=hidden_url)
         else:
             assert 0, (
                 'Unexpected version control type (in {}): {}'.format(


Test patch:
diff --git a/tests/functional/test_wheel.py b/tests/functional/test_wheel.py
--- a/tests/functional/test_wheel.py
+++ b/tests/functional/test_wheel.py
@@ -169,6 +169,25 @@ def test_pip_wheel_builds_editable(script, data):
     result.did_create(wheel_file_path)
 
 
+@pytest.mark.network
+def test_pip_wheel_git_editable_keeps_clone(script, tmpdir):
+    """
+    Test that `pip wheel -e giturl` preserves a git clone in src.
+    """
+    script.pip(
+        'wheel',
+        '--no-deps',
+        '-e',
+        'git+https://github.com/pypa/pip-test-package#egg=pip-test-package',
+        '--src',
+        tmpdir / 'src',
+        '--wheel-dir',
+        tmpdir,
+    )
+    assert (tmpdir / 'src' / 'pip-test-package').exists()
+    assert (tmpdir / 'src' / 'pip-test-package' / '.git').exists()
+
+
 def test_pip_wheel_builds_editable_does_not_create_zip(script, data, tmpdir):
     """
     Test 'pip wheel' of editables does not create zip files