2025-02-20 Web Development

Understanding git reset: A Comprehensive Guide

By O. Wolfson

git reset is a powerful command in Git that allows developers to undo changes in their repositories. It is often used to move the current HEAD to a specified state, enabling developers to modify or discard certain commits. Understanding git reset is crucial for effective version control and maintaining clean project histories.

The Basics of git reset

git reset primarily operates on three distinct areas within a Git repository:

  • HEAD: The pointer to the current branch and its latest commit.
  • Index (Staging Area): The area that holds changes scheduled for the next commit.
  • Working Directory: The files in your local directory that you are actively working on.

The behavior of git reset depends on the mode used:

Modes of git reset

1. git reset --soft <commit>

  • HEAD is moved to <commit>.
  • Index remains unchanged.
  • Working Directory remains unchanged.
  • Use Case: Undoing the last commit while keeping changes staged for editing.

2. git reset --mixed <commit> (default)

  • HEAD is moved to <commit>.
  • Index is updated to match <commit>.
  • Working Directory remains unchanged.
  • Use Case: Undoing a commit and unstaging the changes for further modification.

3. git reset --hard <commit>

  • HEAD is moved to <commit>.
  • Index is updated to match <commit>.
  • Working Directory is updated to match <commit>.
  • Use Case: Discarding commits and changes permanently (Use with caution).

Examples

Resetting the Last Commit

bash
# Keep changes staged
git reset --soft HEAD~1

# Unstage changes but keep modifications
git reset --mixed HEAD~1

# Discard changes permanently
git reset --hard HEAD~1

Resetting to a Specific Commit

bash
git reset --soft <commit-hash>
git reset --mixed <commit-hash>
git reset --hard <commit-hash>

Key Differences Between git reset and git revert

CommandPurposeData LossSafe for Shared Branches
git resetMoves HEAD and modifies historyPotentialNo
git revertCreates a new commit to reverse changesNoYes

Precautions

  • Use --hard carefully as it can permanently delete changes.
  • Avoid git reset on public/shared branches to prevent rewriting history that others rely on.

Practical Step-by-Step Demonstration of git reset

We’ll walk through creating a simple file, making some commits, and performing various git reset operations to see the actual effect.

Step 1: Set Up a Test Repository

Open your terminal and follow these steps:

bash
mkdir git-reset-demo
cd git-reset-demo
git init

This creates an empty Git repository.


Step 2: Create a File and Make Commits

Create file.txt and Make Initial Commit

bash
echo "Line 1" > file.txt
git add file.txt
git commit -m "Add Line 1"

Add Another Line and Make a Second Commit

bash
echo "Line 2" >> file.txt
git add file.txt
git commit -m "Add Line 2"

Add a Third Line and Make a Third Commit

bash
echo "Line 3" >> file.txt
git add file.txt
git commit -m "Add Line 3"

Check the history:

bash
git log --oneline

Example output:

bash
abcd123 Add Line 3
efgh456 Add Line 2
ijkl789 Add Line 1

(Your commit hashes will differ.)


Step 3: Perform git reset Operations

We’ll demonstrate each type of reset using the third commit (HEAD) as the starting point.


A. git reset --soft: Undo Commit, Keep Changes Staged

Scenario: You want to undo the last commit but keep your changes ready for a new commit.

  1. Run:

    bash
    git reset --soft HEAD~1
    
  2. Observe the Result:

    • The last commit is removed, but changes from Line 3 are still staged.
    bash
    git status
    
  3. Check the Contents:

    bash
    cat file.txt
    

    Output:

    bash
    Line 1
    Line 2
    Line 3
    
  4. Recommit or Modify:

    bash
    git commit -m "Revised Line 3"
    

B. git reset --mixed: Undo Commit, Keep Changes in Working Directory

Scenario: You want to undo the last commit and unstage the changes, but keep the file edits.

  1. Run:

    bash
    git reset --mixed HEAD~1
    
  2. Observe the Result:

    • The last commit is removed.
    • Changes from Line 3 are in the working directory but NOT staged.
    bash
    git status
    
  3. Check the File:

    bash
    cat file.txt
    

    Output:

    bash
    Line 1
    Line 2
    Line 3
    
  4. Stage and Commit Again if Needed:

    bash
    git add file.txt
    git commit -m "Recommit Line 3"
    

C. git reset --hard: Undo Commit and Discard Changes (DANGEROUS)

Scenario: You want to undo the last commit and completely remove any changes from your working directory.

  1. Run:

    bash
    git reset --hard HEAD~1
    
  2. Observe the Result:

    • The last commit is removed.
    • Changes from Line 3 are discarded from both:
      • Working directory
      • Staging area
  3. Check the File:

    bash
    cat file.txt
    

    Output:

    bash
    Line 1
    Line 2
    

    Line 3 is GONE!

⚠️ Be Careful: This cannot be undone easily.


Step 4: Reset to a Specific Commit (Optional)

Assuming your commit history looks like this:

bash
abcd123 Add Line 3
efgh456 Add Line 2
ijkl789 Add Line 1

Reset to Commit efgh456 (Second Commit)

bash
git reset --mixed efgh456
  • Moves HEAD to Add Line 2 commit.
  • Line 3 is in the working directory but unstaged.

Check the file:

bash
cat file.txt

Step 5: View History and Status Throughout

Use these at any step to understand what’s happening:

bash
git log --oneline
git status
cat file.txt

Key Takeaways

CommandResult
git reset --soft HEAD~1Undo commit, keep changes staged
git reset --mixed HEAD~1 (default)Undo commit, keep changes unstaged
git reset --hard HEAD~1Undo commit, discard changes in working directory and staging

Conclusion

git reset is a versatile tool for managing commits, the index, and the working directory. Mastering its different modes enables developers to effectively control their project history and recover from mistakes. Understanding when to use git reset versus git revert is vital to ensuring smooth collaboration and preventing data loss in version-controlled projects.