24

I want to do a revert of a commit, but only for some files. (Not a checkout; a revert. If you are unfamiliar with the difference, keep reading.)

I tried this

git revert --no-commit abcdef123456 -- my/path/to/revert 

And I got this error

fatal: ambiguous argument 'my/path/to/revert': unknown revision or path not in the working tree. Use '--' to separate paths from revisions 

But that is precisely what I did! (And yes, my/path/to/revert is in my working tree.)

My working theory is that it is not possible to revert only some files, and that the Git error message is misleading.

(Git 1.7.9.5)


This is not a duplicate of Reverting a single file to a previous version in git.

  • That question (despite the title) pertains to git-checkout. A checkout restores a file to a previous version, removing all commits after that point.
  • My question pertains to git-revert. A revert undoes changes made in a particular commit, without touching other commits that may have come later. It applies the reverse of (only) that commit.
6
  • 1
    Can you explain your need to revert instead of using checkout? As far as I know, a checkout of the appropriate files followed by a commit would be equivalent to a revert. Commented Apr 14, 2014 at 19:47
  • 2
    I don't think you can revert a single file, where did you read that, is it in the docs? You can however apply patches in reverse, together with git apply: git show <commit> -- <path> | git apply -R, found here: git.661346.n2.nabble.com/… Commented Apr 14, 2014 at 19:47
  • 1
    I think this might be a duplicate of this post: stackoverflow.com/questions/2733873/… Commented Apr 14, 2014 at 19:48
  • 1
    @ChrisMaes, see my explanation of the difference between checkout and revert. Commented Apr 14, 2014 at 19:55
  • 1
    @PaulDraper, interesting, apparently I've misunderstood revert for years. So if you have commits A (older), B, and C, you want to reverse the changes from A while keeping the changes from the newer commits B and C. Commented Apr 14, 2014 at 19:57

4 Answers 4

35

I don't think git lets you specify particular files to revert. The best I can think of is this:

git revert --no-commit <commit hash> # Revert, don't commit it yet git reset # Unstage everything git add yourFilesToRevert # Add the file to revert git commit -m "commit message" git reset --hard # Undo changes from the part of the revert that we didn't commit 
Sign up to request clarification or add additional context in comments.

2 Comments

FWIW, it should be pretty easy to wrap this up in a shell script make it easier if you find yourself doing this a lot.
Alternatively, if you want to keep most files in the revert and only undo a few, you can do the git-revert, use git reset --hard on the files you don't want reverted, then commit.
11

A shorter sequence for when you can make a short list of what you want:

git revert that_commit # do the whole revert git reset --hard HEAD^ # in what turns out to have been a throwaway commit git checkout HEAD@{1} -- one/folder # and just take what you want of the results 

Comments

9

vcsjones' answer is probably the best way since revert uses the three-way merge machinery. However, for many cases, you could git apply -R (reverse) the patch to the file (or files) in question, e.g.:

git show <rev> -- path/to/file | git apply -R 

(or git diff—any diff generator that allow you to limit the result to specific files, really—but git show is the obvious go-to for non-merge commits; for merges you'd need to specify the correct parent).

3 Comments

This certainly is the simplest way.
This is less robust than the other answers: error: patch failed: ...\n error: ...: patch does not apply
@jimbo1qaz: yes, that's why I said vcsjones' answer is probably best in general (though jthill's is just as good, and probably easier—it didn't exist at the time I wrote the above).
0

Git works by commits. You cannot git revert a file. Even if there's just one file in a commit, you are still reverting the commit. The solution is to emulate git revert to get back what you need for a new commit. I don't see the cleanest and safest way shown here - revert on another branch and checkout what you need. Unlike git apply, it won't break if there are merge conflicts and revert/reset really only lends itself to undoing one commit.

git checkout -b tmpbranch git revert commitref # complete commit, follow with more reverts as needed git checkout mainbranch git checkout tmpbranch -- file/i/need # while on mainbranch and to index by default git commit -m "this is a new commit message" git branch -d tmpbranch 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.