Complete Git Reset Command Reference

Master the art of undoing changes in Git

Git reset is a powerful command for undoing changes. This comprehensive guide covers all essential git reset commands with practical examples and safety information.

Git Reset Levels
Working Directory
(--hard resets here)
Staging Area (Index)
(--mixed/default resets here)
Commit History
(--soft resets here only)

Basic Reset Commands

git reset --soft HEAD~1 Safe

Moves HEAD pointer but keeps changes staged. Perfect for editing last commit message or combining commits.

$ git commit -m "Initial commit" $ git add forgotten_file.txt $ git reset --soft HEAD~1 # Keeps both changes staged $ git commit -m "Complete initial commit" [main abc1234] Complete initial commit
git reset HEAD~1 Safe

Moves HEAD pointer, unstages changes (default --mixed). Use to unstage files while keeping changes.

$ git add . Changes to be committed: file1.txt, file2.txt $ git reset HEAD # Unstage all files Unstaged changes after reset: file1.txt, file2.txt $ git reset file.txt # Unstage specific file Unstaged changes after reset: file.txt
git reset --hard HEAD~1 Dangerous

Moves HEAD pointer, discards all changes. Completely removes the last commit. Use with extreme caution!

$ git commit -m "Buggy commit" [main def5678] Buggy commit $ git reset --hard HEAD~1 # Completely removes the commit HEAD is now at abc1234 Previous good commit
git checkout -- file.txt Safe

Discard unstaged changes in a specific file. File-level undo that doesn't affect other files.

$ git status modified: file.txt $ git checkout -- file.txt $ git status nothing to commit, working tree clean

Advanced Reset Techniques

git reset abc1234 -- file.txt Warning

Revert one file to its state at a specific commit. Useful for selectively undoing changes to a single file.

$ git log --oneline -- file.txt def5678 Update file.txt abc1234 Initial version $ git reset abc1234 -- file.txt # Revert file.txt to abc1234 state
git reset -p HEAD~1 -- file.txt Safe

Selectively undo specific lines from last commit. Interactive patch mode for precise control.

$ git reset -p HEAD~1 -- file.txt diff --git a/file.txt b/file.txt index 1234567..89abcde 100644 --- a/file.txt +++ b/file.txt @@ -1,5 +1,5 @@ -Hello World +Hello Git Discard this hunk? [y,n,q,a,d,/,j,J,g,e,?]? y Unstaged changes after reset: M file.txt
git reset --hard origin/main Dangerous

Reset local branch to match remote exactly. Destructive operation that discards all local changes.

$ git fetch origin remote: Counting objects: 5, done. remote: Total 5 (delta 3), reused 5 (delta 3) $ git reset --hard origin/main HEAD is now at def5678 Latest commit from remote # WARNING: All local changes will be lost!
git reset '*.txt' Safe

Reset all txt files using pathspec. Useful for unstaging groups of files by pattern.

$ git add '*.txt' $ git status Changes to be committed: file1.txt, file2.txt $ git reset '*.txt' $ git status Changes not staged for commit: file1.txt, file2.txt
git reset --merge Safe

Abort a merge but keep changes. Useful when you want to stop a merge and try a different approach.

$ git merge feature-branch Auto-merging file.txt CONFLICT (content): Merge conflict in file.txt $ git reset --merge Merge aborted, changes preserved $ git status On branch main, nothing to commit
git reset --keep HEAD~1 Safe
Reset while preserving local changes. Similar to --merge but works outside of merge conflicts.
$ git reset --keep HEAD~1 HEAD is now at abc1234 Previous commit $ git status Changes not staged for commit: file1.txt, file2.txt # Local changes are preserved

Dangerous But Powerful Resets

git reset --hard && git clean -fd Dangerous

Nuclear reset - makes working directory match last commit exactly. Removes all changes and untracked files.

$ git reset --hard HEAD is now at abc1234 $ git clean -fd Removing untracked_file.txt Removing untracked_dir/ # WARNING: This cannot be undone!
git reset --hard HEAD~5 && git push --force Dangerous

Remove commits from shared history. Requires force push and should only be used on private branches.

$ git reset --hard HEAD~5 HEAD is now at def5678 $ git push --force + abc1234...def5678 main -> main (forced update) # WARNING: This rewrites public history!
git reset --hard "@{2024-03-15 14:30:00 -0400}" Dangerous

Time machine reset to a specific moment. Powerful but dangerous - can cause data loss.

git reset --hard "@{9am yesterday}..@{5pm yesterday}" # Undo all yesterday's work

$ git reset --hard "@{2024-03-15 14:30:00 -0400}" HEAD is now at abc1234 Commit from that time # Use git reflog to recover if needed

Pro Reset Patterns

git stash && git reset --hard HEAD~3 && git stash pop Safe

Keep working changes while resetting commits. Preserves uncommitted changes during history manipulation.

$ git stash Saved working directory and index state $ git reset --hard HEAD~3 HEAD is now at abc1234 $ git stash pop Restored working changes
git reset --soft HEAD~3 && git reset -p Safe

Split a commit into multiple logical changes. Powerful technique for creating clean commit history.

$ git reset --soft HEAD~3 # Rewind 3 commits, keep changes staged $ git reset -p # Interactive partial unstage Discard this hunk? [y,n,q,a,d,/,j,J,g,e,?]? y $ git commit -m "Feature part 1" $ git commit -m "Feature part 2" $ git commit -m "Feature part 3"
git fetch origin && git reset --hard origin/main --keep-index Warning

Precise branch resynchronization while preserving staged changes. Advanced technique for complex workflows.

$ git fetch origin $ git reset --hard origin/main --keep-index # Reset branch but preserve staged changes $ git stash # Stash working changes $ git stash apply # Reapply working changes
git reset --hard $FAILED_COMMIT && git push --force-with-lease Warning

CI/CD safe reset pattern. Uses --force-with-lease which is safer than --force for automated environments.

# In CI/CD pipeline script git reset --hard $FAILED_COMMIT HEAD is now at abc1234 Failed commit git push --force-with-lease To github.com:user/repo.git + def5678...abc1234 main -> main # Safer than --force as it checks remote state
git reset --mixed HEAD Safe

Standard unstage command. Use to unstage all files while keeping changes in working directory.

$ git add . Changes to be committed: file1.txt, file2.txt $ git reset --mixed HEAD Unstaged changes after reset: file1.txt, file2.txt $ git status Changes not staged for commit: file1.txt, file2.txt
git reflog && git reset --hard HEAD@{n} Warning

Recover from mistaken reset using reflog. Find the commit hash from before the reset and restore to it.

$ git reflog abc1234 HEAD@{0}: reset: moving to HEAD~1 def5678 HEAD@{1}: commit: Important work $ git reset --hard def5678 HEAD is now at def5678 Important work # Recovery successful!

Surgical File History Rewrite

git reset --hard @{1.day.ago} Dangerous

Rewind the entire repository to its state from exactly one day ago. Powerful but dangerous - can cause data loss.

$ git log --oneline -3 abc1234 (HEAD -> main) Today's work def5678 Yesterday's work ghi9012 Work from two days ago $ git reset --hard @{1.day.ago} HEAD is now at def5678 Yesterday's work # Repository is now exactly as it was 24 hours ago $ git status HEAD detached at def5678 nothing to commit, working tree clean
git checkout HEAD@{5} -- file.txt Safe

Retrieve a specific file from 5 commits ago without affecting the rest of your working directory.

$ git log --oneline -7 -- file.txt abc1234 Current version def5678 Removed feature X ghi9012 Added feature Y jkl3456 Added feature X # Restore file.txt to its state from 5 commits ago $ git checkout HEAD@{5} -- file.txt $ git status Changes not staged for commit: file.txt # file.txt now contains its content from 5 commits ago
git commit --amend Warning

Replace the current HEAD commit with a new one. Useful for fixing commit messages or adding forgotten changes.

$ git commit -m "Initial implmentation" [main abc1234] Initial implmentation # Oops, typo in commit message and forgot a file $ git add forgotten-file.txt $ git commit --amend # Editor opens to fix commit message [main def5678] Initial implementation # Commit hash changed, message fixed, file added

Advanced Reflog Navigation

git reflog --relative-date | grep "commit: Add" Safe

Search through reflog with relative dates to find lost commits by their commit message content.

$ git reflog --relative-date | grep "commit: Add" abc1234 HEAD@{2 days ago}: commit: Add user authentication def5678 HEAD@{3 days ago}: commit: Add database schema ghi9012 HEAD@{5 days ago}: commit: Add initial project structure # Found the commit where authentication was added $ git show abc1234 commit abc1234... Author: John Doe Date: 2 days ago Add user authentication
git reset --hard HEAD@{git reflog | grep -m1 "checkout:" | cut -d' ' -f1} Dangerous

Complex command to reset to the first checkout operation found in reflog. Advanced recovery technique.

$ git reflog abc1234 HEAD@{0}: reset: moving to HEAD~1 def5678 HEAD@{1}: checkout: moving from feature to main ghi9012 HEAD@{2}: commit: Important work on feature # Extract the first checkout reference $ git reset --hard HEAD@{git reflog | grep -m1 "checkout:" | cut -d' ' -f1} HEAD is now at def5678 # Now at the state right after the checkout operation

Multi-Level Undo System

git reset --soft HEAD~3 Safe

Undo the last 3 commits but keep all changes staged. First step in a multi-level undo operation.

$ git log --oneline -4 abc1234 (HEAD -> main) Commit 3 def5678 Commit 2 ghi9012 Commit 1 jkl3456 Base commit $ git reset --soft HEAD~3 HEAD is now at jkl3456 Base commit $ git status Changes to be committed: (all changes from last 3 commits)
git reset HEAD~2 Safe

Undo 2 more commits, unstaging the changes. Second step in a multi-level undo operation.

# Continuing from previous reset --soft $ git reset HEAD~2 Unstaged changes after reset: (changes from last 2 commits) $ git status Changes not staged for commit: (changes from last 2 commits) Changes to be committed: (changes from first commit only)
git reset --hard HEAD~1 Dangerous

Final step: completely discard all changes. Use with caution as this cannot be undone.

# Continuing from previous reset $ git reset --hard HEAD~1 HEAD is now at mno7890 (earlier than base commit) $ git status nothing to commit, working tree clean # All changes from the last 3 commits are now gone

Index-Only Reset (Skip Worktree)

git reset --mixed HEAD Safe

Standard unstage command. Resets the index to match HEAD while keeping working directory changes.

$ git add . Changes to be committed: file1.txt, file2.txt $ git reset --mixed HEAD Unstaged changes after reset: file1.txt, file2.txt $ git status Changes not staged for commit: file1.txt, file2.txt # Files are unstaged but changes are preserved
git ls-files -z | xargs -0 git update-index --no-assume-unchanged Safe

Reset all skip-worktree flags. Useful when you want to start tracking previously ignored files again.

$ git ls-files -v | grep '^S' S config/local.properties S temp/test-data.json # These files have skip-worktree flag set $ git ls-files -z | xargs -0 git update-index --no-assume-unchanged $ git ls-files -v | grep '^S' # No output - all skip-worktree flags are cleared $ git status Changes not staged for commit: config/local.properties, temp/test-data.json

Advanced Merge Conflict Reset

git reset --merge ORIG_HEAD Safe

Abort a merge and reset to ORIG_HEAD (state before merge began). Preserves your working directory changes.

$ git merge feature-branch Auto-merging file.txt CONFLICT (content): Merge conflict in file.txt Automatic merge failed; fix conflicts and then commit the result. # Changed your mind about the merge $ git reset --merge ORIG_HEAD Unstaged changes after reset: file.txt $ git status Changes not staged for commit: file.txt no changes added to commit # Merge aborted, back to pre-merge state
git reset --keep HEAD~1 Safe

Alternative to --merge with better change preservation. Resets index to specified commit but keeps working tree changes.

$ git reset --keep HEAD~1 Unstaged changes after reset: file1.txt, file2.txt $ git status Changes not staged for commit: file1.txt, file2.txt no changes added to commit # Working tree changes preserved, index reset to HEAD~1
Pro Tip

Always check git status and git log before using reset commands, especially --hard. Consider using git revert for public commits instead of resetting, as it doesn't rewrite history.

Use git reflog to recover from mistaken resets - it keeps a history of all reference changes for 90 days by default.


When using advanced reset techniques, always:

  1. Check git status and git log before performing resets
  2. Understand the difference between --soft, --mixed, and --hard resets
  3. Use git reflog to recover from mistaken resets
  4. Consider creating a backup branch before performing complex history operations