H Heygents Docs Open App

Updated July 31, 2026 · Maintenance · Medium severity

Build output, .bak files, and venvs are committed to git

Why is my git repo huge and full of build files, .bak copies, and venvs? Your repo is bloated because compiled output, deploy backup copies, and a virtualenv were committed instead of ignored. Add a .gitignore, run git rm --cached to untrack them without deleting the working files, then commit. If .git itself is huge, history rewriting is only worth it when clone size actually blocks people; otherwise leave history alone.

Seen in 8 of 450 scanned projects (2%). Based on Deep Scan runs across 450 audited repositories.

Common stacks: git node python deploy

How to tell you have it

  • git clone of the project takes minutes and pulls down hundreds of megabytes
  • git status shows thousands of changed files after every build
  • the deploy directory has app.js.bak, config.json.prev, and dated .old copies next to the live files
  • a venv/ or node_modules/ folder shows up in git ls-files
  • CI checkout or git pull on the server is noticeably slower than it should be

Why it matters

When a build directory gets committed, every rebuild changes hundreds or thousands of generated files, so every diff and every git status becomes noise. Reviewers cannot tell a real code change from a regenerated bundle hash, and merge conflicts start happening in files nobody hand-edited.

Deploy scripts that copy the current file to app.js.bak or config.json.prev before overwriting it are a manual, ad hoc form of version control that fights the real one. Those backups add tens of megabytes with zero diff value, since git already stores every prior version, and they make it unclear which .bak is the one that actually matters if a rollback is needed.

Orphaned data files, an old sqlite file or a JSON export that predates the current database, are dead weight that also creates confusion. A new engineer sees data.json in the repo root and reasonably assumes it is live, wastes time cross checking it against the real database, and eventually someone edits it thinking it does something.

A virtualenv or dependency cache baked into the first commit sets the pattern for every commit after it. Once .gitignore is missing on day one, every following contributor commits their own local artifacts too, and by the time anyone notices, gigabytes of binary blobs are permanently embedded in git history on the default branch, not just the working tree.

How Heygents detects it

Deep Scan runs git ls-files and git status --porcelain to find tracked build output, .bak/.prev files, and dependency directories, checks for a missing or incomplete .gitignore, and inspects git log and repo size on disk to see whether the bloat is only in the working tree or already baked into history on the default branch.

How to fix it

  1. Add a .gitignore before touching anything else Stop the bleeding first. Cover build output, backup copies, virtualenvs, and caches so nothing new gets committed while you clean up the rest.
  2. Untrack committed artifacts without deleting them git rm --cached removes files from git tracking but leaves them on disk, which matters because a live deploy directory may still need those files present to keep serving traffic during the cleanup.
  3. Delete the actual .bak and .prev copies from the deploy root Once git rm --cached has run, the backup files are just disk clutter, not version control. Confirm nothing references them, then remove them from the filesystem to reclaim space immediately.
  4. Remove the orphaned data file once the real database is confirmed authoritative Verify the JSON or sqlite file is not read by any running process, then move it out of the repo entirely instead of leaving it as a landmine for the next engineer.
  5. Confirm the untracked files actually shrank the working tree diff Run a status check after the cleanup commit lands. A clean status on a fresh build confirms the .gitignore rules are effective, not just present.
  6. Only rewrite history if .git size is a real, current blocker If .git is still tens or hundreds of megabytes after untracking, the artifacts are baked into old commits. Rewriting history with a tool like git filter-repo removes them permanently, but it changes every commit hash, breaks every existing clone and open branch, and requires every collaborator to re-clone. Only do this on a solo repo, or after coordinating a hard cutover with the whole team, and only when clone time or storage cost is an actual measured problem, not a tidiness preference.

Add a .gitignore before touching anything else

dist/
build/
.next/
*.bak
*.prev
*.old
venv/
.venv/
__pycache__/
node_modules/
.cache/
*.pyc

Untrack committed artifacts without deleting them

git rm -r --cached dist/ build/ venv/
git rm --cached *.bak *.prev
git add .gitignore
git commit -m "Stop tracking build output, backups, and venv"

Delete the actual .bak and .prev copies from the deploy root

find /var/www/<app> -maxdepth 2 -name '*.bak' -o -name '*.prev' | xargs -I{} ls -la {}
find /var/www/<app> -maxdepth 2 \( -name '*.bak' -o -name '*.prev' \) -delete

Remove the orphaned data file once the real database is confirmed authoritative

grep -rn "data.json\|legacy.sqlite" src/ scripts/
mkdir -p ~/archive
mv data.json ~/archive/data.json.$(date +%F)
git rm --cached data.json

Confirm the untracked files actually shrank the working tree diff

rm -rf dist/ build/ && npm run build
git status --porcelain
du -sh .git/

Find this in your own projects, automatically

Heygents runs a read-only Deep Scan across every project you own, finds issues like this one, and hands you a ready-to-run fix an AI agent can execute and verify. A solo developer gets the audit, the backlog and the fix loop in one place.

Open Heygents →

Frequently asked questions

Will git rm --cached delete my files from the server?

No. git rm --cached only removes a file from git's tracked index; the file stays exactly where it is on disk. This is what makes it safe to run against a live deploy directory, since the app keeps serving from the same files while you fix the repo underneath it.

Do I need to rewrite git history to fix this?

Usually not. Adding .gitignore and running git rm --cached stops new bloat and shrinks every future clone going forward. History rewriting only helps if the old commits themselves, not the current working tree, are what is making .git large, and it comes with real coordination cost for anyone else with a clone.

Why did my repo size double even though I deleted the build folder?

Deleting a tracked folder from the working tree does not remove it from history. Every commit that ever included those files still stores them in .git, so git log and du -sh .git/ will keep showing the bloat until you either avoid ever committing it again or rewrite history.

Is committing a virtualenv or node_modules ever acceptable?

In rare cases teams vendor dependencies on purpose for reproducibility or offline deploys, but this should be a deliberate, documented decision, not an accident from missing a .gitignore on the first commit. For most projects, lockfiles plus a clean install step are enough and keep the repo lean.

How do I stop deploy scripts from creating .bak files at all?

Replace the manual copy-before-overwrite pattern with git itself: deploy from a clean checkout or a tagged release, and use git revert or a previous tag to roll back instead of a hand-made .prev file. This removes the need for backup copies entirely and keeps rollback history in one place.