As software for version control, Git makes it predictably easy to roll back changes. But even the concept of undoing a change is more complicated than you might first think. A Git repository isn’t quite the same thing as the set of files you're working on locally. Undoing changes means considering exactly where you want to undo them.

git checkout, git reset, and git restore are commands that can help you revert to a previous version not just of your codebase, but of individual files, too. Get to know the details of these commands and you’ll be jumping around your file history like an expert in no time.

What Does Resetting a File Mean, Anyway?

It’s important to note that resetting a file might mean different things to different people under different circumstances. Also, the git reset command might not match your expectations for what resetting means.

Sometimes, you’ll want to undo local changes so a file is back in sync with the current repository. On other occasions, you might want to roll back changes that you've already committed to the repository.

The following terms are key to understanding the difference: working tree, staging area, and repository. The files you edit locally belong to the working tree. Files that you commit ultimately end up in the repository. When you’re in the process of gathering changes, you stage files. A file can have different contents in each of these locations.

See also: Advanced Git Tutorial

You may think of resetting a file as undoing changes. But the state of your file will determine what changes you’re actually undoing. The obvious case is when you make some changes, commit them, then later decide you don’t want them anymore.

Another case might be that you staged a file and now want to unstage it.

How Do I Roll Back a Previously Committed File?

Let’s deal with a case that's easier to understand: you committed a file and now you want to roll back the changes to it.

The Git command to do this is, somewhat unintuitively, named checkout. You might’ve used checkout before to switch branches, but that’s a small part of what the command can do. It also enables you to update files in your working tree to match those at any point in the repository’s history. You can do this for a specific tag, branch, or even a particular commit.

The most useful, general-purpose form of this command is:

        git checkout [commit ID] -- path/to/file
    

Here, we're passing a specific path (path/to/file) that identifies just a single file. We’re also specifying a commit ID to get the file as it existed at that specific commit. This command will update the file in our working tree only.

A terminal session showing how to rollback a repository commit in git

Note that checking out an earlier version of the file modifies the working copy, without committing or even staging it. To fully complete the undo to the repository, you’ll need to stage the file and create a new commit.

See also: How to Inspect a Project’s History With git log

How Do I Change What I’m Staging?

The other type of undo involves your staging area. This contains the changes you’ll commit next to the repository. If you’ve staged a version of a file and later decide you don’t want to include it in the next commit, you’ll want to unstage it first.

You can use the git reset command to unstage a staged file:

        git reset HEAD path/to/file
    
Terminal session showing a file being unstaged from git

Can I Quickly Undo Local Changes?

Yes, you can undo changes to a local file before it's staged. Use the following command:

        git checkout -- path/to/file
    

Note that this is similar to rolling back a repository change, it just omits the commit ID. Once you execute this command, Git will undo any changes to your working copy.

A terminal session showing how to use git to undo local changes

What About git restore?

Later versions of Git have a newer command: restore. For the simple cases we’ve discussed here, you can use the following equivalents. To undo a change to the repository:

        git restore --source [commit id] path/to/file
    

To unstage a file use:

        git restore --staged path/to/file
    

And to undo working copy changes:

        git restore path/to/file
    

Mastering Git’s Versioning Power Is Invaluable

Although resetting a file might seem like a common thing to do, you’ll find it happens pretty rarely in practice. It’s more likely that you’ll be rolling back entire commits rather than individual files. However, on the occasions that you do need to do so, Git at least makes it fairly straightforward.