diff --git a/docs/changelog/1806.feature.rst b/docs/changelog/1806.feature.rst new file mode 100644 index 000000000..75d4ee0a1 --- /dev/null +++ b/docs/changelog/1806.feature.rst @@ -0,0 +1,2 @@ +Generate ignore file for version control systems to avoid tracking virtual environments by default. Users should +remove these files if still want to track. For now we support only **git** by :user:`gaborbernat`. diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 4ed55a568..eefbaf760 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -19,13 +19,15 @@ The tool works in two phases: - **Phase 1** discovers a python interpreter to create a virtual environment from (by default this is the same python as the one ``virtualenv`` is running from, however we can change this via the :option:`p` option). - **Phase 2** creates a virtual environment at the specified destination (:option:`dest`), this can be broken down into - three further sub-steps: + four further sub-steps: - create a python that matches the target python interpreter from phase 1, - install (bootstrap) seed packages (one or more of :pypi:`pip`, :pypi:`setuptools`, :pypi:`wheel`) in the created virtual environment, - install activation scripts into the binary directory of the virtual environment (these will allow end user to *activate* the virtual environment from various shells). + - create files that mark the virtual environment as to be ignored by version control systems (currently we support + Git only, as Mercurial, Bazaar or SVN does not support ignore files in subdirectories). The python in your new virtualenv is effectively isolated from the python that was used to create it. diff --git a/src/virtualenv/create/creator.py b/src/virtualenv/create/creator.py index af5ad5f6e..81fcd157b 100644 --- a/src/virtualenv/create/creator.py +++ b/src/virtualenv/create/creator.py @@ -8,6 +8,7 @@ from argparse import ArgumentTypeError from ast import literal_eval from collections import OrderedDict +from textwrap import dedent from six import add_metaclass @@ -154,6 +155,7 @@ def run(self): safe_delete(self.dest) self.create() self.set_pyenv_cfg() + self.setup_ignore_vcs() def set_pyenv_cfg(self): self.pyenv_cfg.content = OrderedDict() @@ -162,6 +164,23 @@ def set_pyenv_cfg(self): self.pyenv_cfg["version_info"] = ".".join(str(i) for i in self.interpreter.version_info) self.pyenv_cfg["virtualenv"] = __version__ + def setup_ignore_vcs(self): + """Generate ignore instructions for version control systems.""" + # mark this folder to be ignored by VCS, handle https://www.python.org/dev/peps/pep-0610/#registered-vcs + (self.dest / ".gitignore").write_text( + dedent( + """ + # created by virtualenv automatically + * + """, + ).lstrip(), + ) + # Mercurial - does not support the .hgignore file inside a subdirectory directly, but only if included via the + # subinclude directive from root, at which point on might as well ignore the directory itself, see + # https://www.selenic.com/mercurial/hgignore.5.html for more details + # Bazaar - does not support ignore files in sub-directories, only at root level via .bzrignore + # Subversion - does not support ignore files, requires direct manipulation with the svn tool + @property def debug(self): """ diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py index d17a8cc84..be1f21f7d 100644 --- a/tests/unit/create/test_creator.py +++ b/tests/unit/create/test_creator.py @@ -233,6 +233,9 @@ def list_to_str(iterable): make_file = debug["makefile_filename"] assert os.path.exists(make_file) + git_ignore = (dest / ".gitignore").read_text() + assert git_ignore.splitlines() == ["# created by virtualenv automatically", "*"] + @pytest.mark.skipif(not CURRENT.has_venv, reason="requires interpreter with venv") def test_venv_fails_not_inline(tmp_path, capsys, mocker):