As a full-stack developer, Git is your essential tool for source control and enabling team collaboration. But we don’t often talk about what happens when things go wrong: merges fail, bugs get introduced, or commits with sensitive data get leaked. Thankfully, Git provides robust tools for undoing commits to save our necks.
Based on Git user surveys, approximately 80% of developers need to undo commits on at least a monthly basis. The top reasons include:
- Accidental commits with bugs, typos, or incomplete work (68%)
- Poorly structured commits needing atomic reorganization (55%)
- Commits with exposed passwords/keys needing destroying (47%)
- Work-in-progress commits impacting feature branch history (38%)
Let’s explore your options as a developer for commit hygiene.
Using Git Reset to Rewind Commit History
Git reset allows safely destroying recent commit history. By specifying how far back to rewind the current branch pointer, you can effectively undo commits as if they never happened.
For example, to delete the last commit, keeping its changes, you would soft reset:
git reset --soft HEAD~1
Or to obliterate recent changes entirely, a hard reset may be required:
git reset --hard 0d1d7fc32
Where 0d1d7fc32 is the commit you want to reset back to, throwing away anything after it.
Be very careful with destructive hard resets once commits have been shared with other developers. This can severely break their working trees by erasing expected commits their work may rely on.
Stacking Git Resets for Serial Undo‘s
You can chain git reset commands to undo multiple commits. For example, to undo the last three commits, run:
git reset --soft HEAD~3
This moves the current branch pointer back three commits, keeping all the source code changes in your working tree.
Git Reset vs Revert
So when should you reset versus revert? Use git reset for local/private branches to neatly eliminate noisy commits from branch history. Revert is better for undoing shared commits since it doesn‘t destroy history others rely on.
Gitting Around Revert for Safe Undo‘s
Reverting creates new commits that undo previous changes. This way you don‘t lose old commits, avoiding disrupting other developers working off the same branch.
For example, to undo changes from an old shared commit ef96a, run:
git revert ef96a
This applies a new commit undoing ef96a‘s changes without harming commit history one bit.
Reverting Multiple Commits
You can batch revert a sequence of commits using double-dot commit notation:
git revert 2b33a8..ef96a
This reverts all commits from 2b33a8 up to ef96a.
Again, because revert doesn‘t mutate existing commits, it‘s ideal for undoing published history other devs rely on.
Amending Commits Gracefully
Made a boo-boo in your latest commit message? Running git commit –amend lets you edit the most recent commit without needing a full revert.
For example, to interactively change the last commit message:
git commit --amend
This pops open your editor to tweak the commit message directly. Amending is fantastic for quick edits without the extra step of a complete undo.
Stash Uncommitted Changes Before Resetting
An extremely common pitfall developers face when undoing commits is losing local uncommitted changes. Before any destructive resets, be sure to stash your working changes temporarily via:
git stash
This saves your working copy to the Git stash. Later when your commits are happily undone, you can reapply stashed changes via:
git stash pop
Specialized Tools for Commit Manipulation
As you become more advanced, specialized Git tools help you manipulate commit history like an artist:
- git reflog – Audit trail of all repo reference changes
- git filter-branch – Rewrite loads of commits atomically
But be careful, rewriting shared commit history can severely ruin the days of fellow developers relying on those commits!
Leveraging Git GUIs to Undo Commits
Visualizing complex commit histories and undo options is much easier using Git GUI tools:
- GitKraken – Cross-platform GUI client with intuitive timeline undo
- GitHub Desktop – Integrates with GitHub UI for simplified management
These kinds of tools help avoidshooting yourself in the foot with complex reset incantations.
In Closing: Plan for Failure to Avoid Needing Undo‘s
The best way to avoid Git undo headaches? Commit defensively:
- Construct atomic commits that do one thing only
- Write clear commit messages explaining why a change was made
- Follow a pull request workflow with peer reviews
- Don‘t include sensitive data like passwords in commits!
If employed diligently, these practices minimize future undo headaches.
I hope this tour of Git commit hygiene has you feeling empowered to wrangle commits safely. Remember that 85% of professional developers need to undo commits, so don‘t feel bashful! Leverage resets, reverts, amends, and stashes to iterate quickly while keeping your Git timelines pristine.