Undo working copy modifications of one file in Git
Asked Answered
C

15

2064

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?

Cheung answered 28/3, 2009 at 5:9 Comment(0)
B
2683

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

More details included based on comments

First check the the commits of the file

git log -- <filename>

Then you can run this

git checkout <sha-reference> -- filename

where the sha-reference is a reference to the sha of a commit, in any form (branch, tag, parent, etc.

Bellini answered 28/3, 2009 at 6:12 Comment(15)
what's the difference between HEAD and HEAD^?Cheung
HEAD is the most recent commit on the current branch, and HEAD^ is the commit before that on the current branch. For the situation you describe, you could use git checkout HEAD -- filename.Fantast
In short "git checkout sha-reference -- filename" where the sha-reference is a reference to the sha of a commit, in any form (branch, tag, parent, etc.)Berck
HEAD^ , sorry but i am out of touch here little bit. What is last char in HEAD^? Can't find it in windows keyboardMather
@Mather It's a caret; on a US keyboard, you usually get it by typing Shift-6.Bellini
git checkout HEAD^ -- filename to revert to file state before last commitJonajonah
NOTE: If the file is already staged, you need to reset it, first. git reset HEAD <filename> ; git checkout -- <filename>Fowlkes
Then does that mean you can you do HEAD^^ for 2 commits from the most recent?Hevesy
@gwho Yes, you can do HEAD^^ for 2 commits from the most recent, or HEAD^^^ for 3 commits back. You can also use HEAD~2, or HEAD~3, which gets more convenient if you want to go more commits back, while HEAD^2 means "the second parent of this commit"; because of merge commits, a commit can have more than one previous commit, so with HEAD^ a number selects which of those parents, while with HEAD~ a number always selects the first parent but that number of commits back. See git help rev-parse for more details.Bellini
@BrianCampbell How can I do the inverse, keep local changes in one file and discard incoming change. I have 'error: Your local changes to the following files would be overwritten by merge:'Irate
HEAD is just a movable pointer that can point to anywhere. Search the DETACHED HEAD section from here: git-scm.com/docs/git-checkoutTrademark
PUT THIS INTO MEMORY.Corrigan
git checkout <commit-blob> -- /path/to/file/FileName.ccBally
This soooo doesn't do what it's meant to. No changes to the file.Alvinaalvine
Remember to provide the full path to file, e.g git checkout -- src/js/filename!!!Colicroot
C
215

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.

Conn answered 28/3, 2009 at 5:55 Comment(4)
@duckx it's to disambiguate branch names from filenames. if you say 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).Cheung
ic thanks for clearing that up. everyone just assumes you know what -- means when they show you examples. and its not something you can google easily too.Dowski
Looks like the answer was edited to remove the -- from it. While still correct, as @Cheung points out, if there is an ambiguity between filename and branch names you may end up with very undesired behavior here!Polaris
I like it the way it is, without --, nice and easy. When you name branches using file names, there must be bad thinking somewhere...Arise
S
156
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
Serpentine answered 28/3, 2009 at 10:25 Comment(5)
How do I get the commit (of a previously deleted file) except of scrolling throw tons of "git log --stat" output?Italianize
IMO it's kind of difficult via the commandline to scan through gits log and find the right file. It's much easier with a GUI app, such as sourcetreeapp.comSerpentine
git log --oneline <filename> will give you a more compact log, and only include changes to the specific fileConscious
alternatively, you can use git reflog <filename>Sawyers
This is a universal answer. If unwanted content was already committed then most of the other answers will not work, since they target restoring the file content from the last commit.Boche
R
100

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>
Ritualize answered 3/7, 2012 at 5:46 Comment(1)
This has been more helpful than the accepted one haha. It's easy to forget what changes have been staged and what haven't, so resetting helped. Although I also tried "git reset --hard" before, it did not do what "git reset HEAD" did. I wonder why?Keewatin
M
36

I have Done through git bash:

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

  1. Git status. [So we have seen one file wad modified.]
  2. git checkout -- index.html [i have changed in index.html file :
  3. git status [now those changes was removed]

enter image description here

Magocsi answered 10/4, 2018 at 14:54 Comment(0)
L
29

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>.

Legibility answered 12/4, 2021 at 15:0 Comment(2)
Maybe obvious for some but it wasn't for me: To just restore everything: git restore .Probity
This is the right answer for the modern eraBorrow
G
26

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.

Gabfest answered 28/3, 2009 at 5:25 Comment(3)
This won't remove the changes from the commit, it will just apply the diff to the version on the HEAD.Fryer
While true, the original poster just wanted to revert his working copy modifications (I think), not revert changes from the last commit. The original poster's question was a little unclear, so I can understand the confusion.Motmot
maybe not OP's use, but I was looking for how to overwrite my branch with the master's copy - this works quite nicely when replacing branchname^Italianize
T
12

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.

Twitty answered 23/1, 2017 at 21:26 Comment(0)
D
9

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 [email protected]
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.

Dunne answered 9/2, 2016 at 8:56 Comment(0)
A
5

I restore my files using the SHA id, What i do is git checkout <sha hash id> <file name>

Ausgleich answered 22/5, 2012 at 20:39 Comment(0)
I
5

For me only this one worked

git checkout -p filename

enter image description here

Iniquitous answered 19/8, 2017 at 14:28 Comment(0)
A
4

git checkout is the old way of doing this. After the 2020 update the preferred way is:

git restore file.txt

See this duplicate answer (be sure to scroll down to the 2020 update): https://mcmap.net/q/12501/-how-to-undo-local-changes-to-a-specific-file-duplicate

Antagonistic answered 18/7, 2022 at 19:52 Comment(0)
E
1

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
Eserine answered 30/4, 2014 at 19:45 Comment(0)
W
0

If it is already committed, you can revert the change for the file and commit again, then squash new commit with last commit.

Winifredwinikka answered 26/4, 2017 at 19:17 Comment(1)
Adding specific commands to use would help the original poster and future visitors.Keesee
P
-4
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.

Parfait answered 31/12, 2018 at 15:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.