How can I revert a modified file to its previous revision at a specific commit hash (which I determined via git log
and git diff
)?
37 Answers
Assuming the hash of the commit you want is c5f567
:
git checkout c5f567 -- file1/to/restore file2/to/restore
The git checkout man page gives more information.
If you want to revert to the commit before c5f567
, append ~1
(where 1 is the number of commits you want to go back, it can be anything):
git checkout c5f567~1 -- file1/to/restore file2/to/restore
As a side note, I've always been uncomfortable with this command because it's used for both ordinary things (changing between branches) and unusual, destructive things (discarding changes in the working directory).
For the meaning of --
in the command, refer to In Git, what does --
(dash dash) mean?
There is also a new git restore
command that is specifically designed for restoring working copy files that have been modified. If your git is new enough you can use this command, but the documentation comes with a warning:
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
Because git restore
is experimental, it should not yet be promoted as the primary answer to this question. When the command is no longer marked as "experimental", then this answer can be amended to promote the use of git restore
. [At the time of writing, the git restore
command has been marked as "experimental" for at least four years.]
-
14@shadowhand: Is there a way to reverse that, so it's the version right after? Commented Apr 29, 2014 at 12:57
-
19@aliteralmind: No, unfortunately the Git history shortcut notation only goes backwards in history. Commented Apr 29, 2014 at 18:02
-
71If you're going to use a branch name for abcde (e.g.
develop
) you'll wantgit checkout develop -- file/to/restore
(note the double dash) Commented Oct 7, 2014 at 15:14 -
12@aliteralmind: Actually, yes, there's a way to do it: "git log --reverse -1 --ancestry-path yourgitrev..master" and then use the appropriate options to just get the git rev. --ancestry-path will "draw a line" between two commits and -1 will show you just one version, and --reverse will ensure the first entry emitted is the oldest one. Commented Nov 19, 2014 at 19:29
-
14
You can quickly review the changes made to a file using the diff command:
git diff <commit hash> <filename>
Then to revert a specific file to that commit use the reset command:
git reset <commit hash> <filename>
You may need to use the --hard
option if you have local modifications.
A good workflow for managaging waypoints is to use tags to cleanly mark points in your timeline. I can't quite understand your last sentence but what you may want is diverge a branch from a previous point in time. To do this, use the handy checkout command:
git checkout <commit hash>
git checkout -b <new branch name>
You can then rebase that against your mainline when you are ready to merge those changes:
git checkout <my branch>
git rebase master
git checkout master
git merge <my branch>
-
9'git checkout <commit hash>' command has given me back my older version of the project exactly this for which I was searching Thanks Chris. Commented Jan 27, 2013 at 9:26
-
79To revert the file
git checkout <commit hash> <filename>
worked better for me thangit reset
Commented Mar 7, 2013 at 16:53 -
5I wanted an early version of a single file because I had overwritten 150 lines with a badly chosen copy/paste.
git checkout <commit hash> <filename>
worked for me. This should not be the accepted answer, IMHO.git reset
did not. Commented Feb 27, 2014 at 20:58 -
32cannot use
git reset
to reset single file, you will get an errorfatal: Cannot do hard reset with paths
– slierCommented Dec 23, 2014 at 17:11 -
18What slier said: you cannot
git reset --hard <commit hash> <filename>
. This will error withfatal: Cannot do hard reset with paths.
What Motti Strom said: usegit checkout <commit hash> <filename>
Commented Feb 6, 2015 at 5:36
You can use any reference to a git commit, including the SHA-1 if that's most convenient. The point is that the command looks like this:
git checkout [commit-ref] -- [filename]
-
39What is the difference between this answer, which has
--
, and the accepted one which does not?– 2rs2tsCommented Oct 9, 2014 at 0:20 -
108In git, a ' -- ' before the file list tells git that all the next arguments should be interpreted as filenames, not as branch-names or anything else. It's a helpful disambiguator sometimes.– foxxtrotCommented Oct 9, 2014 at 14:32
-
67The '--' is not only a git convention, but something you find in various places in on the *nix commandline.
rm -- -f
(remove a file named-f
) seems to be the canonical example. More detail here Commented Feb 6, 2015 at 5:49 -
8Just add to what @HawkeyeParker said,
rm
command uses getopt(3) to parse its arguments.getopt
is the command to parse command arguments. gnu.org/software/libc/manual/html_node/Getopt.html– DevyCommented Jul 14, 2015 at 18:11 -
2@Honey Yes, that's what I mean, and yeah, probably not common at all. I've seen that example in various places, maybe just to make it sortof memorable: rm -f is well-known to be scary/dangerous. But, the point is, in *nix a file name can start with a '-', and this will confuse various commandline interpreters which, when they see a '-', expect a command option to follow. It could be any file starting with '-'; e.g., "-mySpecialFile". Commented Apr 5, 2017 at 20:35
git checkout -- foo
That will reset foo
to HEAD. You can also:
git checkout HEAD^ foo
for one revision back, etc.
-
19I'd suggest using syntax
git checkout -- foo
to avoid any mistakes iffoo
is anything special (like a directory or a file called-f
). With git, if you're unsure, always prefix all files and directories with the special argument--
. Commented Mar 18, 2013 at 7:22 -
13An additional note to Mikko's comment:
--
is not a git command and not special to git. It is a bash built-in to signify the end of command options. You can use it with many other bash commands too. Commented Mar 4, 2016 at 13:04 -
23@matthaeus it's also neither specific to bash nor a shell feature at all. It's a convention implemented in many different commands (and supported by getopt). Commented Mar 4, 2016 at 17:47
-
6No,
--
is not a builtin special word in bash. But it is a common convention supported by many commandline parsers and used by many CLIs, including git. Commented Sep 1, 2019 at 14:20 -
Windows treats
^
as an escape character, sogit checkout HEAD~1 foo
works for me. Commented Oct 22, 2022 at 6:00
As of git v2.23.0 there's a new git restore method which is supposed to assume part of what git checkout
was responsible for (even the accepted answer mentions that git checkout
is quite confusing). See highlights of changes on github blog.
The default behaviour of this command is to restore the state of a working tree with the content coming from the source
parameter (which in your case will be a commit hash).
So based on Greg Hewgill's answer (assuming the commit hash is c5f567
) the command would look like this:
git restore --source=c5f567 file1/to/restore file2/to/restore
Or if you want to restore to the content of one commit before c5f567:
git restore --source=c5f567~1 file1/to/restore file2/to/restore
-
17I suppose it's a dead thread kind of thing, but this is the correct "modern" answer.– DanCommented Apr 11, 2021 at 0:13
-
9
-
and... the correct answer is in position 5, with all sorts of used-to-be-correct upvoted answers in the lead. Not a shining example of Stackoverflow's technical curating capability (no it is not up to the community to "upvote this answer 7500 times" to have it appear first in default order). Commented Mar 15, 2023 at 18:51
-
6
-
@JLPeyret Worse, the top voted answer gets more votes per unit time than this one, so it will never overtake as things are going now. BUT, this answer looks on track to overtake the second-most upvoted answer in just 250 years, and maybe when it's second it might start to gather more upvotes than the first?– gerritCommented Jul 10, 2023 at 12:41
And to revert to last committed version, which is most frequently needed, you can use this simpler command.
git checkout HEAD file/to/restore
-
2what is the difference between this (git checkout HEAD file/to/restore) and git reset --hard file/to/restore ??? Commented Jan 26, 2016 at 13:23
-
31) easier to remember more general way 2) no worries to press Enter before entering file name Commented Jan 10, 2017 at 19:03
-
I had the same issue just now and I found this answer easiest to understand (commit-ref
is the SHA value of the change in the log you want to go back to):
git checkout [commit-ref] [filename]
This will put that old version in your working directory and from there you can commit it if you want.
If you know how many commits you need to go back, you can use:
git checkout master~5 image.png
This assumes that you're on the master
branch, and the version you want is 5 commits back.
I think I've found it....from http://www-cs-students.stanford.edu/~blynn/gitmagic/ch02.html
Sometimes you just want to go back and forget about every change past a certain point because they're all wrong.
Start with:
$ git log
which shows you a list of recent commits, and their SHA1 hashes.
Next, type:
$ git reset --hard SHA1_HASH
to restore the state to a given commit and erase all newer commits from the record permanently.
-
26Git never removes anything. Your old commits are still there but unless there is a branch tip pointing at them they are not reachable anymore. git reflog will still show them until you clean your repository with git-gc.– BombeCommented Dec 17, 2008 at 9:15
-
5
-
4If you have uncommitted changes, you will loose them if do a git reset --hard Commented Apr 24, 2012 at 15:30
-
2
-
5@Bombe - "Git never removes anything. Your old commits are still there but unless there is a branch tip pointing at them they are not reachable anymore." - but commits like this are pruned after some set time, so "Git never removes anything" is untrue. Commented Apr 29, 2014 at 7:07
This worked for me:
git checkout <commit hash> file
Then commit the change:
git commit -a
You have to be careful when you say "rollback". If you used to have one version of a file in commit $A, and then later made two changes in two separate commits $B and $C (so what you are seeing is the third iteration of the file), and if you say "I want to roll back to the first one", do you really mean it?
If you want to get rid of the changes both the second and the third iteration, it is very simple:
$ git checkout $A file
and then you commit the result. The command asks "I want to check out the file from the state recorded by the commit $A".
On the other hand, what you meant is to get rid of the change the second iteration (i.e. commit $B) brought in, while keeping what commit $C did to the file, you would want to revert $B
$ git revert $B
Note that whoever created commit $B may not have been very disciplined and may have committed totally unrelated change in the same commit, and this revert may touch files other than file you see offending changes, so you may want to check the result carefully after doing so.
-
I did this, but then a "git log file" would say that I was on the original commit, HEAD. It seemed that "git checkout" was failing. However, a git status showed that the file was actually changed and and a "git diff --staged file" would show the actual changes. Also, a "git status" showed the file changed as well. So don't use "git log" here to track which files changed. Commented Jun 8, 2018 at 18:35
-
@FrederickOllinger - that behavior makes sense, because
git log
shows commits, and you haven't committed the change (the reversion). If you dogit commit
after that revert, thengit log
will show the change. Commented Jan 9, 2021 at 21:40
- Git revert file to a specific commit
git checkout Last_Stable_commit_Number -- fileName
2.Git revert file to a specific branch
git checkout branchName_Which_Has_stable_Commit fileName
Amusingly, git checkout foo
will not work if the working copy is in a directory named foo
; however, both git checkout HEAD foo
and git checkout ./foo
will:
$ pwd
/Users/aaron/Documents/work/foo
$ git checkout foo
D foo
Already on "foo"
$ git checkout ./foo
$ git checkout HEAD foo
Here's how rebase
works:
git checkout <my branch> git rebase master git checkout master git merge <my branch>
Assume you have
---o----o----o----o master \---A----B <my branch>
The first two commands ... commit git checkout git rebase master
... check out the branch of changes you want to apply to the master
branch. The rebase
command takes the commits from <my branch>
(that are not found in master
) and reapplies them to the head of master
. In other words, the parent of the first commit in <my branch>
is no longer a previous commit in the master
history, but the current head of master
. The two commands are the same as:
git rebase master <my branch>
It might be easier to remember this command as both the "base" and "modify" branches are explicit.
. The final history result is:
---o----o----o----o master \----A'----B' <my branch>
The final two commands ...
git checkout master
git merge <my branch>
... do a fast-forward merge to apply all <my branch>
changes onto master
. Without this step, the rebase commit does not get added to master
. The final result is:
---o----o----o----o----A'----B' master, <my branch>
master
and <my branch>
both reference B'
. Also, from this point it is safe to delete the <my branch>
reference.
git branch -d <my branch>
First Reset Head For Target File
git reset HEAD path_to_file
Second Checkout That File
git checkout -- path_to_file
-
4+1, though not sure of the intent of resetting HEAD. It may or may not be needed. In my situation i only wanted to revert one particular file to the version in repository (which keeping remaining local changes intact. Just running the second step above was sufficient for me– fklCommented Jan 19, 2018 at 23:56
-
Yes I only need to run the 2nd command. Like --> shellhacks.com/git-revert-file-to-previous-commit Commented May 30, 2019 at 17:07
In the case that you want to revert a file to a previous commit (and the file you want to revert already committed) you can use
git checkout HEAD^1 path/to/file
or
git checkout HEAD~1 path/to/file
Then just stage and commit the "new" version.
Armed with the knowledge that a commit can have two parents in the case of a merge, you should know that HEAD^1 is the first parent and HEAD~1 is the second parent.
Either will work if there is only one parent in the tree.
-
1Shouldn't that file be stages automatically already? I would rather be interested in how to check out without auto-staging the file. Of course, I can manually unstage, too, but it would be interesting to know how to avoid auto-staging.– kriegaexCommented Jun 10, 2022 at 10:41
git-aliases, awk and shell-functions to the rescue!
git prevision <N> <filename>
where <N>
is the number of revisions of the file to rollback for file <filename>
.
For example, to checkout the immediate previous revision of a single file x/y/z.c
, run
git prevision -1 x/y/z.c
How git prevision works?
Add the following to your gitconfig
[alias]
prevision = "!f() { git checkout `git log --oneline $2 | awk -v commit="$1" 'FNR == -commit+1 {print $1}'` $2;} ;f"
The command basically
- performs a
git log
on the specified file and- picks the appropriate commit-id in the history of the file and
- executes a
git checkout
to the commit-id for the specified file.
Essentially, all that one would manually do in this situation,
wrapped-up in one beautiful, efficient git-alias - git-prevision
Many suggestions here, most along the lines of git checkout $revision -- $file
. A couple of obscure alternatives:
git show $revision:$file > $file
And also, I use this a lot just to see a particular version temporarily:
git show $revision:$file
or
git show $revision:$file | vim -R -
(OBS: $file
needs to be prefixed with ./
if it is a relative path for git show $revision:$file
to work)
And the even more weird:
git archive $revision $file | tar -x0 > $file
-
2This is a nice alternative if you're not sure which commit version you want and need to "peek" around without overwriting your working directory.– wisbuckyCommented Feb 16, 2018 at 22:25
I have to plug EasyGit here, which is a wrapper to make git more approachable to novices without confusing seasoned users. One of the things it does is give more meanings to git revert
. In this case, you would simply say:
eg revert foo/bar foo/baz
-
1It should be
eg revert --in REVISON -- FILENAME
. The--in
is important. For the Windows users out there: Open git bash. Executeecho %PATH
. The first path should be in your user directory ending withbin
. Create that path. Store eg there. Name iteg
. Noteg.txt
.– kopporCommented Dec 2, 2016 at 7:13
Note, however, that git checkout ./foo
and git checkout HEAD ./foo
are not exactly the same thing; case in point:
$ echo A > foo
$ git add foo
$ git commit -m 'A' foo
Created commit a1f085f: A
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 foo
$ echo B >> foo
$ git add foo
$ echo C >> foo
$ cat foo
A
B
C
$ git checkout ./foo
$ cat foo
A
B
$ git checkout HEAD ./foo
$ cat foo
A
(The second add
stages the file in the index, but it does not get
committed.)
Git checkout ./foo
means revert path ./foo
from the index;
adding HEAD
instructs Git to revert that path in the index to its
HEAD
revision before doing so.
For me none of the reply seemed really clear and therefore I would like to add mine which seems super easy.
I have a commit abc1
and after it I have done several (or one modification) to a file file.txt
.
Now say that I messed up something in the file file.txt
and I want to go back to a previous commit abc1
.
1.git checkout file.txt
: this will remove local changes, if you don't need them
2.git checkout abc1 file.txt
: this will bring your file to your wanted version
3.git commit -m "Restored file.txt to version abc1"
: this will commit your reversion.
git push
: this will push everything on the remote repository
Between the step 2 and 3 of course you can do git status
to understand what is going on. Usually you should see the file.txt
already added and that is why there is no need of a git add
.
-
2OK so I guess steps 1. and 2. are mutually exclusive: if abc1 is your last commit there is no need for 2. and if there were other commits after abc1 you can directly do 2. Commented Nov 15, 2017 at 10:58
git log --oneline // you see commits, find commit hash to which you want reset
git diff y0urhash src/main/.../../YourFile.java // to see difference
git reset y0urhash src/main/.../../YourFile.java // revert to y0urhash commit
git status // check files to commit
git commit -m "your commit message"
git push origin
-
` Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes `– john kCommented Jul 3, 2023 at 20:58
Many answers here claims to use git reset ... <file>
or git checkout ... <file>
but by doing so, you will loose every modifications on <file>
committed after the commit you want to revert.
If you want to revert changes from one commit on a single file only, just as git revert
would do but only for one file (or say a subset of the commit files), I suggest to use both git diff
and git apply
like that (with <sha>
= the hash of the commit you want to revert) :
git diff <sha>^ <sha> path/to/file.ext | git apply -R
Basically, it will first generate a patch corresponding to the changes you want to revert, and then reverse-apply the patch to drop those changes.
Of course, it shall not work if reverted lines had been modified by any commit between <sha1>
and HEAD
(conflict).
-
1That should be the approved answer. May I suggest a slightly simplified version:
git show -p <sha> path/to/file.ext|git apply -R
– Amaury DCommented Sep 19, 2019 at 13:49 -
Git 2.23.0+
Revert file to state as in origin/main
git restore --source origin/main filename
Revert file to state as in specific commit
git restore --source <hash> filename
Before Git 2.23.0
Revert file to state as in origin/main
git checkout origin/main filename
Revert file to state as in specific commit
git checkout <hash> filename
-
-
My answer improves on simplicity, goes straight to the point and addresses use case more probable for git novices. Originally I wanted to answer here stackoverflow.com/questions/37972753/… but it is closed as duplicate, so I think it can be useful at least here. Thank you for feedback.– MenyTCommented Mar 8 at 4:21
-
From the question : "... its previous revision at a specific commit hash ...". Come on. Commented Mar 8 at 8:24
-
1You improved your answer indeed. Upvoted for the effort. 7695 more and you're on top ;-) Commented Mar 8 at 13:16
In order to go to a previous commit version of the file, get the commit number, say eb917a1 then
git checkout eb917a1 YourFileName
If you just need to go back to the last commited version
git reset HEAD YourFileName
git checkout YourFileName
This will simply take you to the last committed state of the file
git checkout ref|commitHash -- filePath
e.g.
git checkout HEAD~5 -- foo.bar
or
git checkout 048ee28 -- foo.bar
This is a very simple step. Checkout file to the commit id we want, here one commit id before, and then just git commit amend and we are done.
# git checkout <previous commit_id> <file_name>
# git commit --amend
This is very handy. If we want to bring any file to any prior commit id at the top of commit, we can easily do.
-
Thanks, Abhishek. Based on your answer, I made this Shellscipt: gist.github.com/ivanleoncz/c20033e5f4b24304cbc39e0bac1d43e8 Feel free to improve :). Commented Jul 22, 2020 at 0:22
-
didnt work. Only seems to undo the one specified commit. Doesn't roll back all changes to that commit.– john kCommented Jul 3, 2023 at 21:04
You can do it in 4 steps:
- revert the entire commit with the file you want to specifically revert - it will create a new commit on your branch
- soft reset that commit - removes the commit and moves the changes to the working area
- handpick the files to revert and commit them
- drop all other files in your work area
What you need to type in your terminal:
git revert <commit_hash>
git reset HEAD~1
git add <file_i_want_to_revert>
&&git commit -m 'reverting file'
git checkout .
good luck
-
-
1@arcee123 Yes, but the subsequent reset undoes the revert of all changes. The problem is that
git-revert
only operates on the whole repo, so to compensate we have to undo everything else.– TimothyCommented Feb 5, 2019 at 22:01 -
2I recommend using: 1.
git revert --no-commit <commit_hash>
2.git reset HEAD
This saves an extra commit floating around and does all the changes only in your working directory.– TimothyCommented Feb 5, 2019 at 22:04 -
@greg-hewgill 's answer is better and spot on. This one is lousy and should not be used. Commented Feb 28, 2019 at 16:27
-
This is exactly what is needed for a true revert of specific files. I needed to undo changes to a few files from an earlier commit that had already been pushed to the remote repository. I reverted, reset, and committed the result:
git revert _oldcommit_ --no-commit
git reset -- _unchanged1_ _unchanged2_ ...
git commit -m "branch without changes to specific files"
The new branch tip reflected all changes except the reverted files. Commented Mar 21, 2019 at 15:30
Use git log
to obtain the hash key for specific version and then use git checkout <hashkey>
Note: Do not forget to type the hash before the last one. Last hash points your current position (HEAD) and changes nothing.
Obviously someone either needs to write an intelligible book on git, or git needs to be better explained in the documentation. Faced with this same problem I guessed that
cd <working copy>
git revert master
would undo the last commit which is seemed to do.
Ian
--cached
when checkinggit diff
. link