Git

Common Mistakes & Recovery

Git · 9 entries

Force Push Dangers

syntax
git push --force-with-lease origin <branch>
example
# DANGEROUS — overwrites remote without checking:
git push --force origin main  # DON'T DO THIS

# SAFER — fails if someone else pushed since your last fetch:
git push --force-with-lease origin feature/my-work

Note NEVER force push to main/master or any shared branch. It rewrites remote history and other developers' work will be lost or corrupted. If you must force push (e.g., after rebase on a personal branch), always use --force-with-lease which checks that the remote hasn't changed since you last fetched.

Detached HEAD State

syntax
# You're in detached HEAD when:
git checkout <commit-hash>
git checkout <tag>

# To fix — create a branch:
git switch -c <new-branch>
example
git checkout a1b2c3d
# Warning: you are in 'detached HEAD' state.

# If you made commits here and want to keep them:
git switch -c rescue-branch

# If you just want to go back to a branch:
git switch main

Note Detached HEAD means you're not on any branch. Commits made here will be garbage-collected if you switch away without creating a branch. If you accidentally left commits behind, find them with git reflog.

Merge vs Rebase: When to Use Which

syntax
# Merge: preserves history as it happened
git merge feature/branch

# Rebase: creates linear history
git rebase main
example
# Team rule of thumb:
# - Rebase your local/personal feature branch onto main regularly
git switch feature/my-work
git rebase main

# - Merge the feature branch into main when done
git switch main
git merge --no-ff feature/my-work

Note The golden rule: NEVER rebase commits that exist on a remote branch others are using. Rebase rewrites history (new hashes), while merge preserves it. Use rebase to keep your feature branch up-to-date privately; use merge to integrate completed work publicly.

Recover Lost Commits

syntax
git reflog
git reset --hard <hash-from-reflog>
git cherry-pick <hash>
example
# Find the lost commit:
git reflog
# Look for the entry before the mistake:
# a1b2c3d HEAD@{5}: commit: Important work

# Option 1: Reset to that point:
git reset --hard a1b2c3d

# Option 2: Cherry-pick just that commit:
git cherry-pick a1b2c3d

# Option 3: Create a branch from it:
git branch recovery a1b2c3d

Note Reflog entries expire after ~90 days by default. As long as the commit is in the reflog, it hasn't been garbage-collected and you can recover it. If you ran git gc manually, some commits may be permanently lost.

.gitignore Not Ignoring Files

syntax
git rm --cached <file>
git rm -r --cached <directory>
example
# File was tracked before adding to .gitignore:
git rm --cached .env
git rm -r --cached node_modules/
git commit -m "Stop tracking ignored files"
output
rm '.env'
rm 'node_modules/package-lock.json'
...

Note .gitignore only prevents UNTRACKED files from being added. If a file is already tracked, .gitignore has no effect on it. You must remove it from tracking with git rm --cached (the file itself stays on disk). This is one of the most common Git gotchas.

Undo a Commit That's Already Pushed

syntax
git revert <commit>
git push
example
# The safe way — create a new commit that reverses the changes:
git revert a1b2c3d
git push origin main

# If you need to undo multiple commits:
git revert a1b2c3d..f4e5d6g
git push origin main

Note NEVER use git reset + force push on a shared branch. Use git revert instead, which creates a new commit that undoes the changes while preserving history. Everyone who pulled the original commit won't have conflicts.

Accidentally Committed a Secret

syntax
git filter-repo --invert-paths --path <secret-file>
# Then: rotate the credential immediately
example
# Step 1: ROTATE THE SECRET IMMEDIATELY
# (It's in the remote history even if you delete it)

# Step 2: Remove from all history:
pip install git-filter-repo
git filter-repo --invert-paths --path .env

# Step 3: Force push the rewritten history:
git push --force --all

# Step 4: Tell all collaborators to re-clone

Note CRITICAL: Even if you delete the file in a new commit, the secret is still in the Git history and anyone can find it. The FIRST thing to do is rotate/revoke the compromised credential. Rewriting history with filter-repo is step two. GitHub also has a 'secret scanning' feature that alerts you.

Committed to the Wrong Branch

syntax
# Move last commit to a different branch:
git switch <correct-branch>
git cherry-pick <commit>
git switch <wrong-branch>
git reset --hard HEAD~1
example
# Oops, committed to main instead of feature branch:
git log --oneline -1  # Note the hash: a1b2c3d

git switch feature/payments
git cherry-pick a1b2c3d

git switch main
git reset --hard HEAD~1

Note If the wrong branch hasn't been pushed yet, reset is safe. If it's already pushed, you'll need git revert on the wrong branch instead of reset, to avoid force-pushing shared history.

Accidentally Committed Large Files

syntax
git rm --cached <large-file>
git filter-repo --strip-blobs-bigger-than 50M
example
# If not yet pushed — remove and recommit:
git rm --cached data/huge-dataset.csv
echo 'data/*.csv' >> .gitignore
git commit -m "Remove large file, update gitignore"

# If already pushed — rewrite history:
git filter-repo --strip-blobs-bigger-than 50M

Note Git stores every version of every file forever. A 500MB file committed once bloats the repo permanently (even after deletion) unless you rewrite history. Use Git LFS for large files, and add size limits to your .gitignore proactively.