How do I revert a Git repository to a previous commit?

Learn how do i revert a git repository to a previous commit? with practical examples, diagrams, and best practices. Covers git, git-checkout, git-reset development techniques with visual explanations.

How to Revert a Git Repository to a Previous Commit

Hero image for How do I revert a Git repository to a previous commit?

Learn the essential Git commands – git reset, git revert, and git checkout – to undo changes and restore your repository to a desired past state safely and effectively.

Accidentally introduced a bug? Need to undo a series of commits? Git provides powerful tools to navigate your project's history and revert to previous states. This article will guide you through the primary methods for undoing changes in Git: git reset, git revert, and git checkout. Each command serves a different purpose and has distinct implications for your repository's history, especially when working in a collaborative environment.

Understanding Git's State and History

Before diving into the commands, it's crucial to understand how Git manages your project's state. Git tracks changes through a series of commits, each representing a snapshot of your project at a specific point in time. Your working directory contains the files you're currently editing, the staging area (or index) holds changes you've marked for the next commit, and the local repository stores your committed history. Understanding these states helps in choosing the right reversion strategy.

graph TD
    A[Working Directory] --> B{git add .}
    B --> C[Staging Area (Index)]
    C --> D{git commit -m "Message"}
    D --> E[Local Repository (HEAD)]
    E --> F[Remote Repository (git push)]

Git's three-tree architecture: Working Directory, Staging Area, and Local Repository.

Method 1: git reset – Rewriting History

git reset is a powerful command used to undo changes by moving the HEAD pointer and optionally modifying the staging area and working directory. It's often used to discard local changes or to uncommit commits. Because it rewrites history, git reset should be used with caution, especially on branches that have been pushed to a shared remote repository, as it can cause conflicts for collaborators.

There are three main modes for git reset:

1. git reset --soft <commit-hash>

Moves HEAD to the specified commit, but keeps the changes from the undone commits in your staging area. This means the changes are ready to be re-committed.

2. git reset --mixed <commit-hash> (Default)

Moves HEAD to the specified commit and unstages the changes from the undone commits. The changes remain in your working directory, allowing you to modify them before staging and committing again.

3. git reset --hard <commit-hash>

Moves HEAD to the specified commit, and discards all changes from the undone commits from both the staging area and the working directory. This is a destructive operation, as all uncommitted changes and the changes from the undone commits will be lost.

# View your commit history to find the target commit hash
git log --oneline

# Example: Reset to a specific commit, keeping changes in staging
git reset --soft HEAD~1 # Resets to the commit before the last one
git reset --soft <commit-hash>

# Example: Reset to a specific commit, keeping changes in working directory
git reset --mixed HEAD~2 # Resets two commits back, unstaging changes
git reset --mixed <commit-hash>

# Example: Reset to a specific commit, discarding all changes
git reset --hard HEAD~3 # Resets three commits back, destroying changes
git reset --hard <commit-hash>

Examples of git reset commands with different modes.

Method 2: git revert – Creating New History

git revert is the safest way to undo changes, especially on shared branches. Instead of rewriting history, git revert creates a new commit that undoes the changes introduced by a previous commit. This means the original commit remains in the project history, and a new commit is added that effectively cancels out its effects. This approach preserves the integrity of the commit history, making it ideal for collaborative projects.

sequenceDiagram
    participant DevA as Developer A
    participant DevB as Developer B
    participant Repo as Remote Repository

    DevA->>Repo: git push (Commit C1)
    DevB->>Repo: git push (Commit C2)
    DevA->>Repo: git push (Commit C3 - introduced bug)

    Note over DevA,Repo: Bug discovered in C3

    DevA->>DevA: git revert C3
    DevA->>Repo: git push (Commit C4 - reverts C3)

    Note over DevA,Repo: History is preserved, C3 is undone by C4

How git revert creates a new commit to undo changes, preserving history.

# View your commit history to find the commit to revert
git log --oneline

# Revert a specific commit (this will open your editor to write a commit message)
git revert <commit-hash>

# Revert a specific commit without opening an editor (uses default message)
git revert -m "Revert commit <commit-hash> due to bug" <commit-hash>

# Revert multiple commits (reverts them in reverse order of specification)
git revert <commit-hash-1> <commit-hash-2>

Examples of git revert commands.

Method 3: git checkout – Navigating History and Discarding Local Changes

git checkout is primarily used for switching branches or restoring files to a previous state. While not a direct

revert

command in the sense of undoing commits, it's essential for navigating your repository's history and discarding uncommitted changes.

1. Discarding uncommitted changes in the working directory

If you've made changes to files but haven't staged or committed them, git checkout -- <file> or git restore <file> (Git 2.23+) can discard those changes and restore the file to its last committed state.

2. Restoring a file from a specific commit

You can restore a single file to how it looked in a previous commit without affecting the rest of your project's history. This is useful for retrieving an older version of a specific file.

3. Switching to a previous commit (detached HEAD state)

You can checkout a specific commit to inspect the project at that point in time. This puts you in a 'detached HEAD' state, meaning you're not on any branch. Any new commits made in this state won't belong to a branch unless you explicitly create one.

# Discard uncommitted changes in a specific file
git checkout -- my_file.txt
# Or using git restore (Git 2.23+)
git restore my_file.txt

# Restore a file to its state in a previous commit
git checkout <commit-hash> -- my_file.txt

# Switch to a previous commit (detached HEAD)
git checkout <commit-hash>

# To return to your branch after a detached HEAD state
git checkout main # Or your branch name

Examples of git checkout for file restoration and history navigation.