How to revert a file to a specific commit

You made some changes to a file, but you want to revert that file to a specific commit. This is the only file you want to revert. You don't want to revert the entire repository.

Initial situation

Let’s say you are on a branch with multiple commits.

alina

94e6fe5a8b2b1f2b61754bf51c6c4fa21451da58fdmainHEAD

The git log command displays the commit history.

alina

alina git:( main ) git log

commit 94e6fe54dd927e5ac654cf5dd851d26b0d7cb580 (HEAD -> main)

Author: alina <alina@email.com>

Date:   Mon Jun 26 07:50:10 2023 -0700

    add line 5

commit a8b2b1f48c144070d3095362843007af730dc9ec

Author: alina <alina@email.com>

Date:   Mon Jun 26 07:50:06 2023 -0700

    add line 4

commit 2b61754bf4c66dfc0401ae57c0b3f3a0db020173

:

Author: alina <alina@email.com>

Date:   Mon Jun 26 07:50:01 2023 -0700

    add line 3

commit bf51c6c13d763025aadc3091f248bb2d9c5cefb9

Author: alina <alina@email.com>

Date:   Mon Jun 26 07:49:57 2023 -0700

    add line 2

commit 4fa21452a43aaaf8509a9638b875a1db1503da24

Author: alina <alina@email.com>

:

Date:   Mon Jun 26 07:49:53 2023 -0700

    add line 1

commit 1da58fdd1e1ee0a686730f8b721b5204f15fac87 (origin/main, origin/HEAD)

Author: gitpowerup <gitpowerup@mail.com>

Date:   Mon Jun 26 07:49:32 2023 -0700

    Initial commit

alina git:( main )

You realize that you want to revert a single file to a specific commit: you want the content of the file file.txt to match that of the commit 2b61754.

Your current file file.txt has the following content:

alina

alina git:( main ) cat file.txt

1

2

3

4

5

alina git:( main )

and you want to revert it to the content of the file file.txt in the commit 2b61754 (where the last 2 lines were not there).

First, you can do a diff to confirm that this is the commit you want to revert to.

alina

alina git:( main ) git diff 2b61754 -- file.txt

diff --git a/file.txt b/file.txt

index 01e79c3..8a1218a 100644

--- a/file.txt

+++ b/file.txt

@@ -1,3 +1,5 @@

 1

 2

 3

+4

+5

alina git:( main )

When you use file name in a git command line, it is safer to use the double dash -- before the file name. This is not required in this case, because the file name file.txt is not ambiguous.

You have multiple ways to reset the file to the commit 2b61754. These 2 commands differ in the way they affect your working directory.

option #1 : git reset

The git reset command will revert the file to the state of the commit 2b61754.

alina

alina git:( main ) git reset 2b61754 -- file.txt

Unstaged changes after reset:

M       file.txt

alina git:( main )

If you check the content of the file file.txt, you will see that it was not changed:

alina

alina git:( main ) cat file.txt

1

2

3

4

5

alina git:( main )

And the git status shows that the file file.txt is modified: the git reset command did not change the file in your working directory, but it did stage the file from the 2b61754 commit.

alina

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 5 commits.

  (use "git push" to publish your local commits)

Changes to be committed:

  (use "git restore --staged <file>..." to unstage)

        modified:   file.txt

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git restore <file>..." to discard changes in working directory)

        modified:   file.txt

alina git:( main )

The git diff command shows that the file file.txt differs from the staging area:

alina

alina git:( main ) git diff

diff --git a/file.txt b/file.txt

index 01e79c3..8a1218a 100644

--- a/file.txt

+++ b/file.txt

@@ -1,3 +1,5 @@

 1

 2

 3

+4

+5

alina git:( main )

and this is the same diff as the one between the staging area and your current HEAD:

alina

alina git:( main ) git diff --staged

diff --git a/file.txt b/file.txt

index 8a1218a..01e79c3 100644

--- a/file.txt

+++ b/file.txt

@@ -1,5 +1,3 @@

 1

 2

 3

-4

-5

alina git:( main )

So here you have 2 options:

  • if you commit the file file.txt now, you will have the same content as the commit 2b61754, but you would still have to revert the changes in your local directory.
  • you can change your mind and git add the file to ignore the change you made.

option #2 : git restore

Let’s go back to our initial state.

alina

alina git:( main ) git reset --hard main

HEAD is now at 94e6fe5 add line 5

alina git:( main )

with our initial commit tree:

alina

94e6fe5a8b2b1f2b61754bf51c6c4fa21451da58fdmainHEAD

The git restore command can be used to restore a file to a specific commit, and also update your working directory:

alina

alina git:( main ) git restore --source 2b61754 file.txt

alina git:( main )

Your working directory now contains the content of the file file.txt from the commit 2b61754:

alina

alina git:( main ) cat file.txt

1

2

3

alina git:( main )

but the staging area has not been updated:

alina

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 5 commits.

  (use "git push" to publish your local commits)

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git restore <file>..." to discard changes in working directory)

        modified:   file.txt

no changes added to commit (use "git add" and/or "git commit -a")

alina git:( main )

The git diff command confirms this:

alina

alina git:( main ) git diff

diff --git a/file.txt b/file.txt

index 8a1218a..01e79c3 100644

--- a/file.txt

+++ b/file.txt

@@ -1,5 +1,3 @@

 1

 2

 3

-4

-5

alina git:( main )

The git restore command is available since git 2.23.0. Before that the command to use would have been:git checkout 2b61754 -- file.txt.