Should You Commit pycache?
No. Never commit __pycache__/ to your Git repository. It holds compiled bytecode (.pyc files) that Python writes automatically the first time it imports a module, purely to make the next startup faster. Every file in there is regenerated on demand from the .py source you already commit, so it adds nothing to your history except churn — and worse, the files are tagged to one specific interpreter version, so a .pyc written by your machine is useless on a teammate's.
If __pycache__ is already tracked in your repo, this guide covers how to walk that back too.
The short answer
| Question | Answer |
|---|---|
Commit __pycache__/? |
No — it's a regenerated bytecode cache. |
| Will ignoring it break anything? | No — Python rebuilds it on the next import. |
Commit individual .pyc files? |
No — same reason, and they're version-locked. |
What about .pyo / .pyd files? |
No — optimized bytecode and Windows extension modules belong in the same ignore rule. |
| The one real exception? | Shipping a closed-source .pyc-only distribution, which is a deliberate build step, not your working repo. |
The principle is the same one that governs node_modules/ and a dist/ folder: commit source, ignore generated output. __pycache__ is output. Your .py files are the source, and they contain everything Python needs to recreate the cache from scratch.
What's actually in pycache
When Python imports a module, it compiles the source to bytecode — a low-level, platform-independent instruction format that the Python virtual machine executes. To avoid recompiling on every run, CPython caches that bytecode in a __pycache__ directory next to the source file. The folder appears automatically the moment a module is imported; you never ask for it.
Inside, each file is named for the module plus the interpreter that compiled it:
__pycache__/
├── arithmetic.cpython-311.pyc
├── helpers.cpython-311.pyc
└── __init__.cpython-311.pyc
The cpython-311 tag is the important part. It encodes the implementation (CPython) and version (3.11). The naming convention exists precisely so that bytecode from different Python releases can coexist in the same folder without colliding — which is a strong hint that these files are tied to one environment, not portable artifacts you'd want to share.
Each .pyc also begins with a header containing a magic number that identifies the exact Python version, plus either a source timestamp or a source hash used for cache invalidation. If the source .py changes, or you run a different interpreter, Python notices the mismatch and recompiles. The cache is disposable by design.
Why pycache should never be in Git
Three reasons, each sufficient on its own.
It's completely reproducible
Your .py files are the source of truth. The bytecode is a derived artifact that Python regenerates the first time it needs it — no configuration, no manual step. Committing __pycache__ is like committing a compiled binary next to its source: the input already contains everything required to produce the output. There is no information in a .pyc that isn't recoverable from the .py beside it.
It's tied to one interpreter version and not deterministic
A .pyc compiled by CPython 3.11 carries a magic number for 3.11. Hand that file to someone running 3.12 and the interpreter rejects it and recompiles — so the committed copy was dead weight. Timestamp-based .pyc files also embed the source file's modification time, which differs across machines and checkouts, so the same source can produce byte-different caches on two computers. The result is constant, meaningless diffs: files that change without any code changing.
It's noise that buries real changes
A modest Python project can generate dozens of .pyc files across its packages. Tracking them means every git status is cluttered, every pull risks a cache conflict, and code review drowns in binary blobs nobody reads. Compiled caches — like most binary files derived from source — simply don't belong in version control.
What to do instead
Ignore the cache and let Python manage it. Add the standard Python bytecode rules to your .gitignore. These are the opening lines of GitHub's official Python.gitignore template, used by virtually every Python project:
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
That covers everything:
__pycache__/— the cache directory itself.*.py[cod]— a glob matching.pyc(bytecode),.pyo(legacy optimized bytecode), and.pyd(Windows extension modules).*$py.class— bytecode produced by Jython.
If you scaffold a project with a modern tool — Poetry, uv, Hatch, or cookiecutter templates — this block is almost always included already. If yours isn't, add it now. You commit your .py source and your lock file (which Python lock file?); Python takes care of the rest at runtime.
Stopping Python from writing the cache at all
In some environments — short-lived containers, read-only filesystems, or CI runs that execute once and exit — writing bytecode is pure waste. You can suppress it without touching .gitignore:
# Per invocation
python -B script.py
# For the whole environment
export PYTHONDONTWRITEBYTECODE=1
Both prevent Python from writing .pyc files on import. Alternatively, PYTHONPYCACHEPREFIX=/tmp/pycache redirects every __pycache__ to a directory outside your source tree, which keeps the cache (and its startup benefit) while guaranteeing it never lands anywhere near your repo. None of these are required for correctness — ignoring the folder in Git is enough — but they're handy when you want the source tree to stay pristine.
If you already committed pycache
.gitignore only affects untracked files, so if the cache is already in history you have to stop tracking it explicitly. Remove it from the index while leaving it on disk:
# Stop tracking every __pycache__ directory and stray .pyc file
git rm -r --cached "**/__pycache__"
git rm --cached "**/*.pyc"
# Then commit with the ignore rules in place
git add .gitignore
git commit -m "Stop tracking __pycache__ bytecode cache"
The --cached flag removes the files from Git's index but keeps them on your filesystem, so nothing about your local setup breaks — Python just keeps using the cache that's already there. Going forward, the .gitignore rules keep new .pyc files out.
If the committed cache has bloated your repository's history and you need to reclaim space, you'll have to rewrite history with git-filter-repo:
git filter-repo --path-glob '**/__pycache__' --invert-paths
This rewrites commit hashes, so every collaborator must re-clone afterward. Only do it if the repository size is genuinely a problem — for almost every project, the plain git rm --cached is all you need.
The one real exception
There is exactly one situation where shipping .pyc files is legitimate: distributing closed-source Python where you want to withhold the original .py. Because the interpreter can execute a .pyc directly, some commercial tools ship bytecode-only packages to make casual source inspection harder. Even then, this is a build and packaging decision — you compile the bytecode as a deliberate release step for a specific target interpreter and bundle it into an artifact — not something you commit to your working repository. Your development repo still commits .py source and ignores __pycache__. (And note that bytecode is trivially decompilable, so it's obfuscation, not protection.)
pycache vs other generated directories
__pycache__ follows the same source-vs-output rule as every other build cache and generated folder. The question is never really about Python specifically:
| Directory | Created by | Default call | Why |
|---|---|---|---|
__pycache__/ |
Python import | Ignore | Regenerated bytecode cache, version-tagged. |
node_modules/ |
npm / pnpm / yarn | Ignore | Reinstallable from the lock file; platform-specific. |
dist/ / build/ |
Bundlers, setup.py |
Ignore | Build output, rebuilt from source. |
.pytest_cache/ |
pytest | Ignore | Test-run cache, no shared value. |
htmlcov/ / coverage data |
coverage tools | Ignore | Generated report, regenerated on each run. |
If a directory is produced by running a tool over files you already commit, it's output, and output stays out of Git. __pycache__ is the Python instance of a pattern you'll apply across your whole stack.
The bottom line
Don't commit __pycache__. It's a bytecode cache Python writes automatically to speed up imports, every file in it is regenerated from the .py source you already track, and each .pyc is locked to one interpreter version — so a committed cache is useless to anyone on a different Python and produces nothing but noisy, nondeterministic diffs.
Add the standard three lines (__pycache__/, *.py[cod], *$py.class) to your .gitignore, and if the cache is already tracked, git rm -r --cached it and commit. The only time bytecode ships is a deliberate closed-source distribution build — never your working repo. Commit the source; let Python manage the cache.
See Also
- Should You Commit node_modules to Git? — the same regenerated-output rule for JavaScript dependencies
- Should You Commit the dist Folder? — build output that's rebuilt from source
- Should You Commit the coverage Directory? — another generated folder that stays ignored
- Should You Commit poetry.lock? — the Python file you do commit alongside your source
- The Developer's Guide to What Belongs in Your Git Repository — the full committed-vs-ignored reference