Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 8

Undoing Changes with Git: Checkout, Reset, and Revert

Recommended resources

Hello! In our last lesson, we navigated the complexities of merging branches and resolving conflicts. You even learned a crucial "undo" command, git merge --abort, which lets you safely back out of a problematic merge. Mistakes, however, aren't limited to merges. They can happen at any stage of your workflow.

This lesson completes your foundational Git toolkit by focusing on how to correct those mistakes. We will cover how to undo changes in your working directory, staging area, or previous commits using git checkout, reset, and revert. Mastering these commands will give you the confidence to experiment and work efficiently, knowing you can always fix a wrong turn. This is an essential safety net, especially when preparing to contribute to a live open-source project.

A Mental Model for Undoing Changes

To understand where each "undo" command fits, it helps to visualize the journey of a change in Git. As we've discussed, your work moves through distinct stages.

Git Workflow with Undo Commands
This flowchart shows the four areas your code lives in: the Working Directory (your local files), the Staging Area (changes marked for the next commit), the Local Repository (your committed history), and the Remote Repository. Undoing a change depends on which of these areas it's in.

We will structure this lesson around undoing changes in each of the first three areas:

  1. The Working Directory: Files you've modified but not yet staged.
  2. The Staging Area: Changes you've added with git add but not yet committed.
  3. The Local Repository: Changes you have already committed.

1. Undoing Changes in the Working Directory

This is the most straightforward scenario. You've made some edits to a file, but you decide you want to discard them and go back to the version from your last commit.

For this, you can use git checkout.

# This command will discard all local modifications to the file
git checkout -- <file-name>

Important: As the official Git documentation warns, this command is destructive. Your local changes are gone for good. There's no confirmation prompt. Use it only when you are certain you want to discard your work.

To learn more about this and a newer, more intuitive command for the same purpose (git restore), please read the following sections from the official Git documentation.

2.4 Git Basics - Undoing Things

The official Pro Git book provides a clear explanation for discarding local modifications. Pay attention to how git status itself often tells you the exact command you need.

First, read the section titled 'Unmodifying a Modified File' to understand the git checkout -- <file> command. Then, read 'Unmodifying a Modified File with git restore' to learn about the more modern git restore <file> command, which achieves the same goal with a clearer syntax.

As you saw, git restore <file-name> is now the recommended command for this operation in modern versions of Git, as its name more clearly communicates its function.


2. Undoing Changes in the Staging Area (Unstaging)

Let's say you've staged a file with git add, but then you realize you weren't ready to include it in the next commit. You need to "unstage" it, moving it from the Staging Area back to the Working Directory. The modifications themselves will remain in the file.

The classic command for this is git reset.

# This unstages the file, but its changes remain in your working directory
git reset HEAD <file-name>

Just as before, modern Git has introduced a more descriptive command for this.

2.4 Git Basics - Undoing Things

Let's return to the Pro Git book to see how to unstage a file.

Read the section 'Unstaging a Staged File' to see how git reset HEAD <file> works. Then, read 'Unstaging a Staged File with git restore' to learn about the git restore --staged <file> command.

So, you have two options for unstaging: git reset HEAD <file> or git restore --staged <file>. Both get the job done.


3. Undoing Commits

This is where things get more interesting and require more caution. Undoing a commit means altering the project's history. How you do this depends heavily on one question: Has the commit been pushed to a shared remote repository?

Amending the Most Recent Commit

Let's start with a simple case. You just made a commit, but you realize you misspelled something in the commit message or forgot to include a file. You can "amend" the previous commit.

# Stage any forgotten files
git add forgotten_file.py

# Amend the previous commit
git commit --amend

This opens your text editor, allowing you to change the commit message. When you save and close it, Git replaces your previous commit with a new one that includes both the original changes and any new staged changes. It's not so much editing the old commit as it is replacing it entirely.

Crucial Rule: Only amend commits that have not been pushed to a remote branch that others are using. Since it rewrites history, it can cause major problems for your collaborators.

The Safe Undo: git revert

When to use it: To undo a commit that has already been pushed and shared publicly.

git revert does not delete any commits. Instead, it figures out the changes in a specific commit and creates a brand new commit that does the exact opposite. If the old commit added a line, the new "revert commit" removes that line.

This is the safest way to undo changes on a collaborative project because it doesn't rewrite history. It adds to it, preserving a clear record of what happened.

The following video demonstrates this process clearly.

Beginner Git and GitHub #5 - Undo Changes (checkout, revert, reset)

Let's watch a practical demonstration of git revert to see how it creates a new commit to undo a previous one.

Watch from 02:41 to 06:05. Notice how after running git revert, the original commit still exists in the history (git log), but a new commit has been added on top of it to reverse its changes.

The Powerful (and Dangerous) Undo: git reset

When to use it: To discard one or more commits on your local, private branch that you have not pushed.

git reset is a powerful command that moves the current branch's pointer back to a previous commit, effectively erasing the commits that came after it. This rewrites the project history.

Git Revert vs. Reset Comparison
This image perfectly summarizes the core difference. `revert` creates a new commit to undo changes, preserving history, making it safe for public branches. `reset` moves the pointer back, effectively deleting commits, which alters history and is only safe for private branches.

git reset has three primary modes of operation, which control what happens to the changes from the discarded commits:

  • --soft: The commits are gone, but the changes from them are kept in your Staging Area.
  • --mixed (default): The commits are gone, and the changes are kept in your Working Directory.
  • --hard: The commits are gone, and the changes are completely discarded. This is destructive and your work will be lost. Be very careful with this!

This next video offers an excellent breakdown of these three modes.

Git Tutorial #34: How to Use Git Reset Soft, Mixed, and Hard | Learn Git

The video "How to Use Git Reset Soft, Mixed, and Hard" by GitKraken provides a fantastic conceptual overview of the three main reset modes.

Watch from 01:20 to 03:07. This will clearly explain the difference between --soft, --mixed, and --hard resets and what happens to your files in each case.

Test your understanding!

You pushed a commit to a feature branch on GitHub that you are sharing with a colleague. Later, you realize this commit introduced a bug. You need to undo the changes from that commit. Which command should you use and why?

  1. git reset --hard HEAD~1 followed by git push --force
  2. git revert <commit-hash> followed by git push
Show answer

The correct answer is #2: git revert <commit-hash>.

Since the commit was already pushed to a shared branch, you must not rewrite history. git reset rewrites history by removing the commit, which would cause significant issues for your colleague. git revert is the safe choice because it creates a new commit that undoes the buggy one, preserving the project history for everyone.


Bonus: Inspecting a Previous State with git checkout

Finally, what if you don't want to undo a commit, but just want to look at the state of your project at that point in time? For this, you can use git checkout with a commit hash.

# This will take you to a 'detached HEAD' state at that commit
git checkout <commit-hash>

This is like being a time-traveling observer. Your files will revert to how they were at that commit, but you're not on any branch. You can look around, but if you make new commits here, they'll be lost once you switch back to a branch. To get back to the present, you simply check out your branch again (git checkout main).


Summary

You now have a complete set of tools for correcting mistakes in Git. The key is to choose the right tool for the job, depending on where the change is and whether it's been shared.

For easy reference, this table from Atlassian's excellent guide summarizes the common use cases.

Command Scope Common use cases
git reset Commit-level Discard commits in a private branch or throw away uncommitted changes
git reset File-level Unstage a file (git reset HEAD <file>)
git checkout Commit-level Switch between branches or inspect old snapshots
git checkout File-level Discard changes in the working directory (git checkout -- <file>)
git revert Commit-level Undo commits in a public branch
git revert File-level (N/A)

Conclusion

Congratulations on completing the first module! You have built a solid foundation in Git and GitHub, from creating repositories and making commits to collaborating with branches, resolving conflicts, and now, fixing mistakes with confidence.

Key Takeaways:

  • To discard local, un-staged changes, use git restore <file> or git checkout -- <file>.
  • To unstage a file, use git restore --staged <file> or git reset HEAD <file>.
  • To fix the last local commit, use git commit --amend.
  • To undo a public, shared commit, use the safe git revert command, which creates a new commit.
  • To undo private, local commits, use the powerful git reset command, which rewrites history.

Preview of the next lesson:
With your Git skills established, it's time to put them into practice. In our next module, "Finding and Selecting an Open Source Project," we will move from theory to action. You'll learn how to use GitHub's search tools to discover projects that match your interests in security and AI/ML, how to evaluate if a project is beginner-friendly, and how to find your very first issue to work on. The journey to your first open-source contribution begins now