A walkthrough of the Undo a Commit tutorial: why the last commit is broken, and how git reset --soft lets you fix it without losing work.
This scenario starts in a portfolio project where the last commit is subtly broken. You will read the history, undo that commit while keeping your changes, and re-commit it properly. Here is what is happening at each step and why.
The situation
The project has two commits. The latest one, "Add header section", added a navigation header to index.html. The matching CSS for that header was written in style.css, but it was never staged: it is still sitting in the working tree as an uncommitted change.
So the commit is incomplete. The committed site has header markup that points at styles which were never saved. Anyone checking out that commit gets a broken header.
Start by running git log --oneline and git status. The log shows the "Add header section" commit; the status shows style.css as modified but not staged. That mismatch is the whole problem.
The fix, step by step
Inspect what was committed
git log confirms the last commit, and git status shows that style.css is still modified in the working tree. You now know the commit captured index.html but not style.css.
Undo the commit, keep the changes
git reset --soft HEAD~1
This moves the branch pointer back one commit. The index.html change that was in the commit returns to the staging area, ready to be committed again. Nothing in your files is deleted.
Stage everything this time
git add index.html style.css
Now both the markup and its styles are staged together, so the next commit will be complete.
Re-commit the complete change
git commit -m "Add header section"
The history once again has a single "Add header section" commit, but this time it includes style.css. The site is whole.
Why --soft is the right mode here
git reset has three modes, and the difference is only about where your changes land:
--soft moves HEAD back and keeps the changes staged. Ideal here, because you immediately want to re-commit.
--mixed (the default) keeps the changes but unstaged, in the working tree.
--hard discards the changes entirely.
git reset --hard HEAD~1 here would delete the header work along with the commit. Reach for --hard only when you truly want the changes gone.
If you ever run --hard by accident, the commit is usually still recoverable with git reflog, which lists every position HEAD has held. The "Recover Lost Commits" tutorial covers that flow.
One caveat: shared commits
Everything above rewrites history, which is perfectly safe for a commit that only exists on your machine. Once a commit has been pushed and pulled by others, rewriting it forces everyone onto a diverged branch. On a shared branch, undo the change with a new commit instead:
git revert HEAD