Skip to content

How to Set Up Python venv with Automatic .gitignore (2026)

I accidentally committed my entire .venv folder to a git repository last month. Over 47,000 files. My team was not happy when they pulled and their Git LFS quota got eaten by dependency cache files. I thought I had .venv in my .gitignore, but I forgot to add it on that project.

The Problem

The issue is simple but annoying:

terminal
$ git status
On branch main
Untracked files:
.venv/
$ git add .
$ git status
Changes to be committed:
new file: .venv/bin/activate
new file: .venv/bin/activate.csh
new file: .venv/bin/activate.fish
... (47,382 more files)

I had been manually adding .gitignore entries for every virtual environment:

.gitignore
# My manual approach (error-prone)
venv/
env/
.venv/
.env/
*.pyc
__py__cache__/

The problem? I sometimes forget. Different projects use different venv names. New team members don’t know the convention. Someone names it venv-projectname and suddenly thousands of files slip into git.

What I Discovered

I was reading through Reddit discussions on virtual environments when I found something surprising. A top comment said:

“Don’t waste time managing virtual environments. Learn how to use uv. It takes care of everything.”

Another comment clarified:

“python -m venv .venv creates .gitignore inside .venv directory for you.”

Wait, what? Python’s built-in venv module automatically creates a .gitignore?

Testing the Built-in Solution

I decided to test this claim:

terminal
$ mkdir test-project
$ cd test-project
$ git init
Initialized empty Git repository
$ python -m venv .venv
$ ls -la .venv/
total 0
drwxr-xr-x 11:00 .
drwxr-xr-x 11:00 ..
drwxr-xr-x 11:00 bin
drwxr-xr-x 11:00 include
drwxr-xr-x 11:00 lib
-rw-r--r-- 11:00 .gitignore <-- It's there!
$ cat .venv/.gitignore
*

The .gitignore file contains a single * character. This tells Git to ignore everything inside that directory while still tracking the directory itself.

Let me verify it works:

terminal
$ git status
On branch main
Untracked files:
.venv/
$ git add .
$ git status
On branch main
Changes to be committed:
new file: .venv/.gitignore
# Only the .gitignore is tracked, not the contents!

This is exactly what I needed. The virtual environment directory exists in the project structure, but Git doesn’t track the thousands of dependency files inside.

How virtualenv Handles It

I also tested virtualenv to see if it does the same thing:

terminal
$ virtualenv myenv
created virtual environment in 1.2s
$ ls -la myenv/
total 0
drwxr-xr-x 11:00 .
drwxr-xr-x 11:00 ..
-rw-r--r-- 11:00 .gitignore
drwxr-xr-x 11:00 bin
drwxr-xr-x 11:00 include
drwxr-xr-x 11:00 lib
$ cat myenv/.gitignore
*

Same behavior. Both venv and virtualenv create this automatic .gitignore with the * wildcard.

The Modern Approach: uv

After seeing that Reddit recommendation, I tried uv. It’s a modern Python package manager that handles everything:

terminal
$ uv init my-project
Initialized project at my-project
$ cd my-project
$ ls -la
total 0
drwxr-xr-x 11:00 .
drwxr-xr-x 11:00 ..
-rw-r--r-- 11:00 .gitignore <-- At root level
-rw-r--r-- 11:00 .python-version
-rw-r--r-- 11:00 main.py
-rw-r--r-- 11:00 pyproject.toml
$ cat .gitignore
# Python
__pycache__/
*.py[cod]
*$py.class
.venv/
...
$ uv add requests
Resolved 5 packages in 12ms
Installed 5 packages in 45ms

The uv approach is different but more comprehensive:

  • Creates a .gitignore at the project root (not inside .venv)
  • Includes common Python ignores automatically
  • Handles virtual environment creation
  • Installs packages 10-100x faster than pip

Why This Matters

The automatic .gitignore inside .venv solves several problems:

  1. No more forgetting: The .gitignore is created automatically. You can’t forget to add it.

  2. Smaller repositories: No more accidental commits of thousands of dependency files.

  3. Faster clones: Git doesn’t waste time tracking venv contents.

  4. Cleaner diffs: No noise from virtual environment changes in pull requests.

  5. Team consistency: Everyone’s virtual environment is automatically ignored.

Common Mistakes I’ve Made

Mistake 1: Adding venv to root .gitignore manually

I used to do this:

.gitignore
# Wrong approach - manual entries
venv/
.venv/
env/

This works, but it’s:

  • Easy to forget on new projects
  • Inconsistent across team members
  • Requires knowing the venv directory name

The built-in approach is better because it’s automatic.

Mistake 2: Not using .venv as the standard name

I used different names across projects:

Terminal window
$ python -m venv venv # Project A
$ python -m venv env # Project B
$ python -m venv .venv # Project C
$ python -m venv venv-api # Project D (why?)

Now I stick with .venv because:

  • It’s hidden from ls by default (cleaner directory listing)
  • It’s the common convention
  • IDEs and tools recognize it automatically

Mistake 3: Recreating venv and panicking

When I delete and recreate .venv, I used to worry about the .gitignore:

terminal
$ rm -rf .venv
$ python -m venv .venv
# Is the .gitignore still there?

Yes, it is. Python recreates it automatically every time you run python -m venv .venv.

Comparison: Three Approaches

venv-comparison.txt
+------------------------+---------------------+---------------------+---------------------+
| Feature | python -m venv | virtualenv | uv |
+------------------------+---------------------+---------------------+---------------------+
| Auto .gitignore | Yes (inside .venv) | Yes (inside .venv) | Yes (at root) |
| Python version | 3.3+ | Any | Any (managed) |
| Speed | Slow | Slow | 10-100x faster |
| Package installation | pip (separate) | pip (separate) | Built-in |
| Project initialization | Manual | Manual | Automatic |
| Learning curve | Low | Low | Medium |
+------------------------+---------------------+---------------------+---------------------+

What I Use Now

For quick scripts and learning:

terminal
$ python -m venv .venv
$ source .venv/bin/activate
$ pip install requests

For real projects:

terminal
$ uv init my-project
$ cd my-project
$ uv add requests

The uv approach gives me:

  • Automatic project structure
  • Fast dependency resolution
  • Built-in .gitignore at root level
  • Python version management
  • Lock file for reproducible builds

Summary

Python’s built-in venv module automatically creates a .gitignore file inside the virtual environment directory. This file contains a single * which excludes all venv contents from git tracking.

I no longer manually add .venv/ to my root .gitignore. I just run python -m venv .venv and it handles everything automatically.

For new projects, I use uv because it goes further - it creates a comprehensive .gitignore at the project root and manages the entire Python environment. But even for simple projects, knowing that venv handles the .gitignore automatically saves me from embarrassing commits of thousands of dependency files.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments