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:
$ git statusOn branch mainUntracked files: .venv/
$ git add .$ git statusChanges 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:
# 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:
$ mkdir test-project$ cd test-project$ git initInitialized empty Git repository$ python -m venv .venv$ ls -la .venv/total 0drwxr-xr-x 11:00 .drwxr-xr-x 11:00 ..drwxr-xr-x 11:00 bindrwxr-xr-x 11:00 includedrwxr-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:
$ git statusOn branch mainUntracked files: .venv/
$ git add .$ git statusOn branch mainChanges 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:
$ virtualenv myenvcreated virtual environment in 1.2s$ ls -la myenv/total 0drwxr-xr-x 11:00 .drwxr-xr-x 11:00 ..-rw-r--r-- 11:00 .gitignoredrwxr-xr-x 11:00 bindrwxr-xr-x 11:00 includedrwxr-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:
$ uv init my-projectInitialized project at my-project$ cd my-project$ ls -latotal 0drwxr-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 requestsResolved 5 packages in 12msInstalled 5 packages in 45msThe uv approach is different but more comprehensive:
- Creates a
.gitignoreat 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:
-
No more forgetting: The
.gitignoreis created automatically. You can’t forget to add it. -
Smaller repositories: No more accidental commits of thousands of dependency files.
-
Faster clones: Git doesn’t waste time tracking venv contents.
-
Cleaner diffs: No noise from virtual environment changes in pull requests.
-
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:
# Wrong approach - manual entriesvenv/.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:
$ 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
lsby 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:
$ 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
+------------------------+---------------------+---------------------+---------------------+| 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:
$ python -m venv .venv$ source .venv/bin/activate$ pip install requestsFor real projects:
$ uv init my-project$ cd my-project$ uv add requestsThe uv approach gives me:
- Automatic project structure
- Fast dependency resolution
- Built-in
.gitignoreat 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:
- 👨💻 Python venv documentation
- 👨💻 uv - Python package manager
- 👨💻 Reddit discussion on virtual environments
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments