[2026] Git reset vs revert — undo commits safely (rebase, reflog, interactive rebase)
이 글의 핵심
Differences between reset, revert, restore, and checkout; interactive rebase (squash, fixup, reword); conflict resolution; force push and reflog recovery; merge vs rebase team rules—practical focus.
[Git in practice #4] Undo, rebase, and cleanup
Previous: Remote repos and collaboration (#3) covered push, pull, and PRs.
Think of a commit as a snapshot of the project. When you need to fix a bad snapshot or straighten a line of snapshots, the main tools are reset (move HEAD to change history, staging, and working tree), revert (add a new commit that undoes another while keeping history), and rebase (replay commits on top of another base to tidy history). This article covers each, including cautions for the last commit, shared branches, and more.
After reading you will:
- Understand
git reset --soft,--mixed, and--hard, and how they differ fromgit restoreandgit switch. - Know when to choose
git revertvsgit reset, including patterns after a push. - Use
git rebase, interactive rebase (squash, fixup, reword, edit), and resolve rebase conflicts. - Recognize risks of
git reset --hardandgit push --force, recover with reflog, and align with merge vs rebase team rules.
Table of contents
- Overview
- git reset: undo commits and staging
- git revert: create a commit that undoes another
- git rebase: linear history
- Practical cautions
- FAQ
1. Overview
| Goal | Command | Behavior |
|---|---|---|
| Undo only the last commit and keep editing | git reset --soft HEAD~1 | Commit undone; staging and working tree unchanged |
| Undo commit and staging | git reset HEAD~1 (or --mixed) | Commit and staging undone; file edits remain |
| Fully go back before that commit (risky) | git reset --hard HEAD~1 | Commit, staging, and working tree changes removed |
| Make a pushed commit look “undone” safely | git revert <commit> | New “inverse” commit; history preserved |
| Linearize branch history | git rebase main | Replays commits on top of main (history changes) |
If a commit is already on the remote, using reset —hard and rewriting history conflicts with others—prefer revert to add an explicit undo commit. Rebase changes history, so use it mainly on local branches not yet pushed.
2. git reset
reset —soft
Only the commit is undone; the index and working tree stay as they were:
git reset --soft HEAD~1
# git reset: move the HEAD pointer
# --soft: undo only the commit (keep staging and working tree)
# HEAD~1: the parent of the current HEAD
#
# What happens:
# 1. HEAD moves to the previous commit
# 2. Changes from the undone commit stay staged
# 3. Working tree unchanged
#
# Result:
# git status → changes appear under "Changes to be committed"
# You can git commit again
Typical scenarios:
# Scenario 1: fix the last commit message
git commit -m "Fix bug" # typo spotted!
git reset --soft HEAD~1
git commit -m "Fix authentication bug" # corrected message
# Scenario 2: add a file and recommit
git commit -m "Add feature"
# Oops—one file was missing
git reset --soft HEAD~1
git add forgotten_file.js
git commit -m "Add feature" # all files included
# Scenario 3: squash several commits into one
git reset --soft HEAD~3 # undo last 3 commits
git commit -m "Implement user authentication" # single combined commit
HEAD notation:
HEAD~1 # one commit back
HEAD~2 # two commits back
HEAD~3 # three commits back
HEAD^ # one commit back (same as HEAD~1)
HEAD^^ # two commits back (same as HEAD~2)
# You can also reset to a specific hash
git reset --soft abc1234
reset —mixed (default)
Undoes the commit and staging; only file edits remain in the working tree. Use when you want to undo the commit and unstage, then stage only part of the changes again.
git reset HEAD~1
# or
git reset --mixed HEAD~1
Then git status shows changes as unstaged; git add what you need and git commit again.
reset —hard
Moves commit, index, and working tree back to the target state. Uncommitted work is discarded, so stash or branch first if you might need it.
git reset --hard HEAD~1
On a branch already pushed, reset —hard followed by force push can break others’ history—avoid in team workflows when possible.
3. git revert
What revert does
revert applies the inverse of a commit as a new commit:
git revert HEAD
# git revert: create a new commit that undoes a given commit
# HEAD: revert the latest commit
#
# What happens:
# 1. Git analyzes the changes in HEAD
# 2. Applies the opposite (add → remove, remove → add)
# 3. Creates a new "Revert" commit
# 4. History is unchanged (old commits remain)
#
# Result:
# A → B → C (HEAD)
# ↓
# A → B → C → C' (revert of C, new HEAD)
# C' contains the inverse of C
# Revert a specific commit
git revert abc1234
# New commit that undoes abc1234
# Revert a merge commit
git revert abc1234 -m 1
# -m 1: use first parent as base for the revert
# -m 2: use second parent
# Merge commits have two parents, so -m is required
reset vs revert:
# reset: rewrite history (commit disappears)
# A → B → C (HEAD)
git reset --hard HEAD~1
# A → B (HEAD) ← C is gone from history
# Risk: if others pulled C, histories diverge
# revert: keep history (new commit)
# A → B → C (HEAD)
git revert HEAD
# A → B → C → C' (HEAD) ← C' undoes C
# Safer for collaboration: full history remains
Revert conflicts:
git revert HEAD
# conflict!
# 1. Edit conflicted files
vim conflicted_file.js
# 2. Stage
git add conflicted_file.js
# 3. Continue the revert
git revert --continue
# Or abort the revert
git revert --abort
Production-style example:
# Scenario: a buggy commit was pushed to production
git log --oneline
# abc1234 Add buggy feature ← problematic
# def5678 Update docs
# 789abcd Initial commit
# Fix: revert safely
git revert abc1234
# Creates "Revert 'Add buggy feature'"
git push origin main
# History preserved; bug is effectively rolled back
4. git rebase
Meaning
Rebase replays your branch’s commits on top of another branch (or another point). History looks linear, but commit hashes change, so rebasing a branch already pushed without coordination causes problems.
Example: update feature onto latest main
git checkout feature/login
git rebase main
Commits from feature/login are replayed on top of main’s tip. On conflicts: fix files → git add → git rebase —continue. To cancel: git rebase —abort.
Cautions
- Rebasing a branch already on the remote usually requires git push —force (or
--force-with-lease) and can confuse collaborators—prefer local-only branches. - Do not casually rebase shared integration branches like main/master.
5. Practical cautions
- Before push: reset and rebase are fine for local cleanup.
- After push: to “undo” what was pushed, prefer revert. Use force push only with team agreement.
- merge vs rebase: standardizing on “merge into main” keeps history predictable; restrict rebase to personal feature branches to reduce surprises.
6. FAQ
Can I recover after reset --hard?
A. Right after reset —hard, git reflog usually shows the previous HEAD. Example: git reflog → git reset --hard HEAD@{1} to return. After a long time or after reflog GC, recovery may fail—use branches or stash before destructive resets.
revert vs reset?
A. reset moves HEAD and can make commits disappear from the recorded history. revert adds a new commit without erasing history. For commits already pushed, revert is usually safer.
Conflicts during rebase?
A. Edit conflicts, then git add <file> and git rebase —continue. Repeat if needed. git rebase —abort returns to the state before the rebase started.
Closing
- reset —soft / —mixed: undo commits (and maybe staging) while keeping work—great for local fixes.
- reset —hard: resets commit, index, and working tree—avoid on shared pushed branches.
- revert: add an undo commit—safe for shared history.
- rebase: linearize history—prefer on unpushed branches.
One line: Use reset/revert/rebase to undo and tidy commits; on branches already pushed, revert is usually the safe choice. See the Git series index for more topics.
Previous: Git in practice #3: Remote collaboration
Series index: Full Git series
Reset touches three layers (summary)
flowchart LR
subgraph layers [Per commit]
H[HEAD / commit]
I[Staging index]
W[Working tree]
end
H --> I --> W
Explanation: --soft moves HEAD only; --mixed also unstages; --hard aligns all three with the base commit.
- Push, pull, and PRs
- Branches and merge conflicts
- Git basics
Practical tips
Debugging
- Read compiler and linter output first
- Reproduce with a minimal test case
Performance
- Do not optimize without profiling
- Define measurable goals first
Code review
- Check common review feedback early
- Follow team conventions
Checklist
Before you rewrite history
- Is this the best fix for the problem?
- Will teammates understand and maintain the result?
- Are performance requirements met?
While resolving conflicts
- Are all compiler warnings addressed?
- Are edge cases covered?
- Is error handling appropriate?
During review
- Is intent clear?
- Are tests sufficient?
- Is documentation updated if behavior changed?
Use this checklist to reduce mistakes and improve quality.
Keywords (search)
Git, undo, reset, revert, rebase, git reset, git revert, reflog, restore, interactive rebase, force push, undo commit, history
Related posts
- Git basics
- Branches and merging
- Remote collaboration
- Git series index