Volver al blog

Git Undo Last Commit: Keep Changes, Stay Safe

3 de septiembre de 2026

TL;DR: to undo the last commit but keep the changes, run git reset --soft HEAD~1 (changes stay staged) or git reset HEAD~1 (changes stay in your working tree). If the commit is already pushed, run git revert HEAD instead — it creates a new commit that undoes it without rewriting history. Those three commands cover almost every “I committed too early” moment. The rest of this guide walks through each case with copy-paste commands, explains the difference between --soft, --mixed and --hard, and shows how to recover if something goes wrong. Every command below works on any recent Git install on Linux, macOS or Windows.

How do I undo the last commit but keep the changes?

The most common situation: you committed, then spotted a typo, a missing file, or realised the change belongs in a different commit. Nothing is pushed yet. Undo the commit and put everything back where it was:

# Commit stays in history nowhere — changes go back to the staging area
git reset --soft HEAD~1

# Changes go back to the working tree (unstaged) instead
git reset HEAD~1

HEAD~1 means “one commit before where HEAD points now”. After either command your files are untouched on disk — only the branch pointer moved. Check it with git status: with --soft the changes are staged, ready to re-commit with fixes folded in; without a flag they are unstaged, so you can edit freely first.

A safer habit when you just want to add files to the last commit is not to undo it at all:

git add forgotten-file.txt
git commit --amend --no-edit

--amend replaces the last commit in place (no commit message change here). Note that amending a pushed commit rewrites history — more on that below.

What is the difference between —soft, —mixed and —hard?

This is the part worth memorising, because the flag decides where your changes end up — and whether they can be lost:

FlagCommit undone?Changes on diskChanges staged?Typical use
--softYesKeptYesRe-commit with small fixes
--mixed (default)YesKeptNoRe-group changes, re-stage selectively
--hardYesDeletedThrow the work away entirely
git revertNo (new commit)KeptUndo a commit that was already pushed

--hard is the only dangerous one: it discards the commit and the changes. Before any reset --hard, stash or branch what you have:

git branch backup-before-reset   # cheap insurance
git reset --hard HEAD~1          # commit + changes gone

If you already ran the dangerous version, all is not lost — git reflog remembers where HEAD has been:

git reflog                       # find the commit hash you lost
git reset --hard HEAD@{1}        # or: git reset --hard <hash>

The reflog keeps dangling commits for around 90 days by default, so “I hard-reset by mistake” is almost always recoverable if you act before garbage collection.

What if I already pushed the commit?

If the commit is on a shared branch (anything other than your own feature branch), do not rewrite history. Use git revert, which computes the opposite change and commits it:

git revert HEAD
git push

Everyone who pulls simply gets a new commit that removes the old one’s changes. No force-push, no broken colleagues. If you need to undo a run of commits, revert a range: git revert --no-commit HEAD~3..HEAD && git commit.

The alternative — git reset --hard HEAD~1 && git push --force-with-lease — is only acceptable on a branch nobody else builds on, and --force-with-lease (never plain --force) is the only safe form because it refuses if someone pushed in the meantime. Force-pushing shared branches is how teams lose commits and CI logs mysteriously stop matching anyone’s checkout.

How do I undo the last commit but keep it around for later?

Sometimes the commit is good work at the wrong address — on the wrong branch, or too early. Instead of undoing it, move it:

git branch stash-commit          # park the commit on a new branch
git reset --hard HEAD~1          # then clean your current branch

Or take just the commit to another branch without touching your current one:

git cherry-pick <hash>           # while on the target branch

Between reset --soft, cherry-pick and revert, there is no commit you cannot relocate or nullify — the trick is choosing “move” versus “undo” before reaching for a flag.

Which undo should I use? A quick decision guide

  1. Not pushed, want to fix and re-commitgit reset --soft HEAD~1
  2. Not pushed, want to re-stage selectivelygit reset HEAD~1 (mixed)
  3. Want the changes gone completelygit reset --hard HEAD~1 (reflog knows, if you regret it)
  4. Already pushed to a shared branchgit revert HEAD
  5. Commit belongs on another branchcherry-pick, don’t undo

One last operational tip: if a bad commit did make it to a server — a botched deploy hook, a CI runner misbehaving after a force-push — the next place to look is the machine’s logs, not Git. On any systemd box, journalctl -u <service> -n 100 shows you exactly what ran and when; our journalctl cheat sheet has the copy-paste patterns. And if your workflow includes local LLM tooling to review diffs, we compared the two main options in Ollama vs LM Studio.

— mrsaynothing

journalctl Cheat Sheet: Tail, Filter and Follow Linux Logs