Join us

How to Fix Common Git Problems

How to Fix Common Git Problems

TL;DR:

Every developer breaks git. The difference between a junior and a senior is not avoiding the mess, it's knowing the two commands that get you out of it. This post is a field guide: the problem you're facing, the command that fixes it, and just enough context to use it without making things worse. At the end is a cheat sheet for quick reference.


Learn Git in a Day (source)

Working directory problems

Undo uncommitted edits: You changed a file, hated the result, and want the last committed version back:

FILE="src/app.py"
git restore "$FILE"

This is destructive. Your edits are gone, no undo. If you might want them later, stash instead.

Unstage a file: You ran git add . and swept in a file that doesn't belong in this commit:

FILE="debug.log"
git restore --staged "$FILE"

The file stays modified in your working directory. Only the staging is undone.

Pause your work: Someone pings you with an urgent bug and your current work is half-finished:

git stash
# fix the bug, commit, push
git stash pop

Use git stash -u if you have untracked files, since plain stash ignores them. And if pop says nothing came back, check git stash list, then git stash apply stash@{n} to recover a specific entry.

Clear out untracked files: Build artifacts, editor backups, and experiment files pile up. git clean deletes them, and it does not go through the trash:

git clean -n    # preview what would be deleted
git clean -fd   # delete untracked files and directories

Always run -n first. Add -x only if you also want to remove ignored files (build caches, node_modules), and expect a slow reinstall afterward.

Git tracks a file that's in .gitignore: Adding a file to .gitignore does nothing if git already tracks it. You have to remove it from the index:

FILE="config/local.env"
git rm --cached "$FILE"
git commit -m "stop tracking $FILE"

The file stays on disk. It just leaves git's index.

Last-commit problems

These fixes rewrite the most recent commit. Safe before pushing, dangerous after.

Fix a commit message typo:

git commit --amend -m "add rate limiting to the API gateway"

Add a forgotten file:

FILE="tests/test_gateway.py"
git add "$FILE"
git commit --amend --no-edit

Undo the commit but keep the work: You committed too early, or bundled unrelated changes:

git reset --soft HEAD~1

Your changes come back staged. Recommit them properly, maybe as two commits this time.

Nuke the commit and the work:

git reset --hard HEAD~1

Both the commit and the changes disappear from your working directory. The commit itself survives in the reflog, so even this is recoverable (see below) - but once it's unreachable, git's default is to keep it for only about 30 days, so don't sit on it.

Undo a pushed commit: Once a commit is on a shared branch, do not rewrite it. Revert it instead:

git revert HEAD

This creates a new commit that inverts the bad one. History stays intact, teammates stay unbroken.

Clean up your commits before pushing: You have five commits named "wip", "fix", "fix again", "typo", and "actually works". Interactive rebase lets you squash, reorder, reword, and drop them before anyone sees the mess:

N=5
git rebase -i HEAD~"$N"

Git opens an editor listing the commits. Change pick to squash (or s) to fold a commit into the one above it, reword (or r) to edit its message, drop to delete it. Save, close, done. Same rule as amend: only do this to commits you haven't pushed.

Wrong-place problems

Committed on the wrong branch: You were "on main" in your head but on feature/x in reality:

SHA=$(git rev-parse HEAD)
git switch main
git cherry-pick "$SHA"
git switch feature/x
git reset --hard HEAD~1

Copy the commit to where it belongs, then remove it from where it doesn't.

Detached HEAD: You checked out a tag or a raw SHA and git is warning you about a detached HEAD. Nothing is broken. If you made commits you want to keep, put a branch on them:

git switch -c rescue-branch

If you made nothing worth keeping:

git switch main

Cherry-pick a single commit: You need one fix from another branch without merging the whole thing:

SHA="a1b2c3d"
git cherry-pick "$SHA"

Branch synchronization problems

Your branch is behind main: Before you've pushed, rebase for a clean linear history:

git fetch origin
git rebase origin/main

After you've pushed and others may have pulled, merge instead:

git merge origin/main

The rule: rebase private history, merge shared history.

Abort a rebase: Conflicts piled up and you want out:

git rebase --abort

You're back exactly where you started. Same escape hatch exists for merges (git merge --abort) and cherry-picks (git cherry-pick --abort).

Force push safely: You rebased or amended a pushed branch and now git rejects your push. Never use bare --force on a branch someone else touches:

git push --force-with-lease

--force-with-lease refuses the push if the remote moved since you last fetched, which means you can't silently erase a teammate's commits. Bare --force can.

A pull made a mess: You pulled, got an ugly merge or unexpected conflicts, and want to pretend it never happened:

git reset --hard ORIG_HEAD

ORIG_HEAD points to where your branch was before the last drastic operation (pull, merge, rebase).

Disaster recovery

The reflog is your time machine: Git keeps a local log of everywhere HEAD has been. Reachable history sticks around for about 90 days, but a commit that becomes unreachable - a deleted branch tip, a hard-reset-away commit, a botched rebase - is kept for only about 30 days by default before garbage collection can reclaim it. So almost nothing is truly lost, as long as you recover it within the month.

Deleted a branch:

git reflog
# find the SHA of the branch tip, e.g. a1b2c3d
BRANCH="feature/payments"
SHA="a1b2c3d"
git branch "$BRANCH" "$SHA"

Hard-reset past commits you needed:

git reflog
SHA="a1b2c3d"
git reset --hard "$SHA"

Lost a commit and not sure how (a botched rebase, an amend, whatever): inspect it before deciding what to do with it:

git reflog
SHA="a1b2c3d"
git checkout "$SHA"   # look around, run the tests
git switch -c recovered "$SHA"   # keep it on a branch

Undo a merge commit: Reverting a merge needs the -m 1 flag to tell git which parent is the mainline:

SHA="d4e5f6a"
git revert -m 1 "$SHA"

Warning: after reverting a merge, re-merging the same branch later brings nothing in, because git considers those commits already merged. You'd have to revert the revert first.

You committed a secret: Two steps, in this order:

  1. Rotate the credential immediately. Assume it's compromised the moment it left your machine. Rewriting history does not un-leak anything that was pushed.
  2. Then rewrite history with git-filter-repo:
FILE="config/secrets.env"
git filter-repo --path "$FILE" --invert-paths

Everyone on the team must re-clone afterward, since all SHAs change.

Investigation

Find the commit that broke things: git bisect binary-searches your history. On a 1000-commit range, it finds the culprit in about 10 steps:

GOOD_SHA="a1b2c3d"
git bisect start
git bisect bad
git bisect good "$GOOD_SHA"
# test each checkout, then mark it:
git bisect good   # or: git bisect bad
# when done:
git bisect reset

If you have a test script, automate the whole thing:

git bisect run ./test.sh

Find who changed a line and why:

FILE="src/gateway.py"
git blame "$FILE"
SHA="a1b2c3d"          # a SHA from the blame output
git show "$SHA"

blame gives you the SHA per line, show gives you the full commit with its message. The message is usually where the "why" lives, assuming your team writes real commit messages.

Housekeeping

Rename a branch:

NEW_NAME="feature/rate-limiting"
git branch -m "$NEW_NAME"
# if already pushed:
git push origin -u "$NEW_NAME"
git push origin --delete <old-name>

Fix line-ending chaos: Mixed Windows/Linux teams see phantom diffs where every line changed. Set this once per machine:

# Linux / macOS
git config --global core.autocrlf input
# Windows
git config --global core.autocrlf true

Better yet, commit a .gitattributes file so the repo enforces it for everyone:

* text=auto

Three rules cover 90% of git recovery

  1. Uncommitted work is the only thing git can truly lose: restore, reset --hard, and checkout destroy uncommitted changes with no undo. Commit or stash before anything risky.

  2. Committed work is almost never lost: The reflog keeps it even after resets and deleted branches - roughly 30 days once it's unreachable, so recover it within the month.

  3. Private history is yours to rewrite, shared history is not: Amend and rebase freely before pushing. After pushing, revert instead, and if you must force push, use --force-with-lease.

The cheat sheet

ProblemFix
I want to undo my uncommitted editsgit restore <file>
I staged a file by mistakegit restore --staged <file>
I committed something wronggit revert HEAD
I need to pause my workgit stash → do other work → git stash pop
I made a typo in my last commit messagegit commit --amend -m "fixed message"
I forgot to add a file to my last commitgit add <file>git commit --amend --no-edit
My branch is behind maingit fetch then git rebase origin/main (before pushing) or git merge origin/main (after pushing)
I want to abandon a rebasegit rebase --abort
I'm in detached HEADgit switch main
I want to undo my last commit but keep the changesgit reset --soft HEAD~1
I want to nuke my last commit entirelygit reset --hard HEAD~1
I committed on the wrong branchgit switch <right-branch>git cherry-pick <sha> → clean up the wrong branch
I deleted a branch and I need it backgit refloggit branch <name> <sha>
I hard-reset and lost commitsgit refloggit reset --hard <sha>
A merge went sidewaysgit merge --abort
I pushed and then rewrote historygit push --force-with-lease
Git keeps tracking a file that's in .gitignoregit rm --cached <file> → commit
I committed a secretRotate the secret first, then rewrite history with git filter-repo
I need one commit from another branchgit cherry-pick <sha>
I need to find which commit broke thingsgit bisect startgit bisect badgit bisect good <sha>
Who wrote this line and whygit blame <file>git show <sha>
My branch name is wronggit branch -m <new-name>
I want to undo a merge commitgit revert -m 1 <merge-sha>
My pull created a messgit reset --hard ORIG_HEAD
I stashed something and lost itgit stash listgit stash apply stash@{n}
I think I lost a commitgit refloggit checkout <sha>
I have messy untracked files to clear outgit clean -n (preview) → git clean -fd
I want to clean up my commits before pushinggit rebase -i HEAD~<n>
Line endings are driving me crazygit config core.autocrlf (input on Linux/macOS, true on Windows)

Find the most updated version of this guide at eon01/GitCheatSheet.

Don't forget to checkout my book Learn Git in a Day - The Visual Guide for a more in-depth, visual approach to learning git.


Let's keep in touch!

Stay updated with my latest posts and news. I share insights, updates, and exclusive content.

Unsubscribe anytime. By subscribing, you share your email with @eon01 and accept our Terms & Privacy.

Give this a Pawfive!


Only registered users can post comments. Please, login or signup.

Start writing about what excites you in tech — connect with developers, grow your voice, and get rewarded.

Join other developers and claim your FAUN.dev() account now!

FAUN.dev()
FAUN.dev()

FAUN.dev() is a developer-first platform built with a simple goal: help engineers stay sharp withou…

Avatar

Aymen El Amri

Founder, FAUN.dev

@eon01
Founder of FAUN.dev(), author, maker, trainer & software engineer
Developer Influence
9

Influence

457k

Total Hits

73

Posts

Featured Course(s)
Learn Git in a Day - The Visual Guide
Learn Git in a Day - The Visual Guide

Everything you need, nothing you don't

> Get Your Copy

GitOps the Hard Way, with Argo CD
GitOps the Hard Way, with Argo CD

Build Real GitOps Pipelines From Empty Clusters to Automated Deploys

> Get Your Copy

Cloud Native CI/CD with GitLab
Cloud Native CI/CD with GitLab

From Commit to Production Ready

> Get Your Copy