After the last commit, I modified a bunch of files in my working copy, but I want to undo the changes to one of those files, as in reset it to the same state as the most recent commit.
However, I only want to undo the working copy changes of just that one file alone, nothing else with it.
How do I do that?
You can use
git checkout -- file
You can do it without the --
(as suggested by nimrodm), but if the filename looks like a branch or tag (or other revision identifier), it may get confused, so using --
is best.
You can also check out a particular version of a file:
git checkout v1.2.3 -- file # tag v1.2.3
git checkout stable -- file # stable branch
git checkout origin/master -- file # upstream master
git checkout HEAD -- file # the version from the most recent commit
git checkout HEAD^ -- file # the version before the most recent commit
Just use
git checkout filename
This will replace filename with the latest version from the current branch.
WARNING: your changes will be discarded — no backup is kept.
git checkout x
and x happens to be a branch name as well as a file name, I'm not sure what the default behavior is but I think git will assume you want to switch to branch x. When you use --
you're saying that what follows is file name(s).
--
from it. While still correct, as @hasen points out, if there is an ambiguity between filename and branch names you may end up with very undesired behavior here!
--
, nice and easy. When you name branches using file names, there must be bad thinking somewhere...
git checkout <commit> <filename>
I used this today because I realized that my favicon had been overwritten a few commits ago when I upgrated to drupal 6.10, so I had to get it back. Here is what I did:
git checkout 088ecd favicon.ico
git log --oneline <filename>
will give you a more compact log, and only include changes to the specific file
git reflog <filename>
If your file is already staged (happens when you do a git add etc after the file is edited) to unstage your changes.
Use
git reset HEAD <file>
Then
git checkout <file>
If not already staged, just use
git checkout <file>
I have Done through git bash:
(use "git checkout -- <file>..." to discard changes in working directory)
Git status. [So we have seen one file wad modified.] git checkout -- index.html [i have changed in index.html file : git status [now those changes was removed]
https://i.stack.imgur.com/onOB1.jpg
If you want to just undo the previous commit's changes to that one file, you can try this:
git checkout branchname^ filename
This will checkout the file as it was before the last commit. If you want to go a few more commits back, use the branchname~n
notation.
branchname^
This answers is for command needed for undoing local changes which are in multiple specific files in same or multiple folders (or directories). This answers specifically addresses question where a user has more than one file but the user doesn't want to undo all local changes:
if you have one or more files you could apply the same command (git checkout -- file ) to each of those files by listing each of their location separated by space as in:
git checkout -- name1/name2/fileOne.ext nameA/subFolder/fileTwo.ext
mind the space above between name1/name2/fileOne.ext nameA/subFolder/fileTwo.ext
For multiple files in the same folder:
If you happen to need to discard changes for all of the files in a certain directory, use the git checkout as follows:
git checkout -- name1/name2/*
The asterisk in the above does the trick of undoing all files at that location under name1/name2.
And, similarly the following can undo changes in all files for multiple folders:
git checkout -- name1/name2/* nameA/subFolder/*
again mind the space between name1/name2/* nameA/subFolder/* in the above.
Note: name1, name2, nameA, subFolder - all of these example folder names indicate the folder or package where the file(s) in question may be residing.
Git 2.23 introduced a restore
to do just that, in an attempt, I think, to make the answer to these kind of questions straightforward.
git restore [--] <pathspec>...
As always, the --
could be needed but when a file name starts with a dash. (The confusion with a branch name is not possible here, as restore
's perimeter does not include branches, unlike the do-all checkout
)
To be complete, restore
can also restore staged files with --staged
, and restore from a different commit than HEAD
with --source=<tree>
.
git restore .
I always get confused with this, so here is a reminder test case; let's say we have this bash
script to test git
:
set -x
rm -rf test
mkdir test
cd test
git init
git config user.name test
git config user.email test@test.com
echo 1 > a.txt
echo 1 > b.txt
git add *
git commit -m "initial commit"
echo 2 >> b.txt
git add b.txt
git commit -m "second commit"
echo 3 >> b.txt
At this point, the change is not staged in the cache, so git status
is:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: b.txt
no changes added to commit (use "git add" and/or "git commit -a")
If from this point, we do git checkout
, the result is this:
$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean
If instead we do git reset
, the result is:
$ git reset HEAD -- b.txt
Unstaged changes after reset:
M b.txt
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: b.txt
no changes added to commit (use "git add" and/or "git commit -a")
So, in this case - if the changes are not staged, git reset
makes no difference, while git checkout
overwrites the changes.
Now, let's say that the last change from the script above is staged/cached, that is to say we also did git add b.txt
at the end.
In this case, git status
at this point is:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: b.txt
If from this point, we do git checkout
, the result is this:
$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean
If instead we do git reset
, the result is:
$ git reset HEAD -- b.txt
Unstaged changes after reset:
M b.txt
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: b.txt
no changes added to commit (use "git add" and/or "git commit -a")
So, in this case - if the changes are staged, git reset
will basically make staged changes into unstaged changes - while git checkout
will overwrite the changes completely.
I restore my files using the SHA id, What i do is git checkout <sha hash id> <file name>
For me only this one worked
git checkout -p filename
https://i.stack.imgur.com/Ev1Zj.png
If you have not yet pushed or otherwise shared your commit:
git diff --stat HEAD^...HEAD | \
fgrep filename_snippet_to_revert | cut -d' ' -f2 | xargs git checkout HEAD^ --
git commit -a --amend
If it is already committed, you can revert the change for the file and commit again, then squash new commit with last commit.
git restore file
See this duplicate answer (be sure to scroll down to the 2020 update): https://stackoverflow.com/a/31281748/12763497
git checkout a3156ae4913a0226caa62d8627e0e9589b33d04c -p */SearchMaster.jsp
Breakdown: a3156ae4913a0226caa62d8627e0e9589b33d04c = This is the hash value of the commit. It's on my own personal branch (not master).
The -p flag is the path.
*/SearchMaster.jsp is the filename.
Success story sharing
git reset HEAD <filename> ; git checkout -- <filename>
HEAD^^
for 2 commits from the most recent, orHEAD^^^
for 3 commits back. You can also useHEAD~2
, orHEAD~3
, which gets more convenient if you want to go more commits back, whileHEAD^2
means "the second parent of this commit"; because of merge commits, a commit can have more than one previous commit, so withHEAD^
a number selects which of those parents, while withHEAD~
a number always selects the first parent but that number of commits back. Seegit help rev-parse
for more details.