Revert changes to a file in a commit

91,846

Solution 1

The cleanest way I've seen of doing this is described here

git show some_commit_sha1 -- some_file.c | git apply -R

Similar to VonC's response but using git show and git apply.

Solution 2

Assuming it is ok to change the commit history, here's a workflow to revert changes in a single file in an earlier commit:

For example, you want to revert changes in 1 file (badfile.txt) in commit aaa222:

aaa333 Good commit
aaa222 Problem commit containing badfile.txt
aaa111 Base commit

Rebase on the base commit, amend the problem commit, & continue.

1) Start interactive rebase:

git rebase -i aaa111

2) Mark the problem commit for edit in the editor by changing pick to e (for edit):

e aaa222
pick aaa333

3) Revert changes to the bad file:

git show -- badfile.txt | git apply -R

4) Add the changes & amend the commit:

git add badfile.txt
git commit --amend

5) Finish the rebase:

git rebase --continue

Solution 3

git revert is for all file contents within a commits.

For a single file, you can script it:

#!/bin/bash

function output_help {
    echo "usage: git-revert-single-file <sha1> <file>"
}

sha1=$1
file=$2

if [[ $sha1 ]]; then
git diff $sha1..$sha1^ -- $file | patch -p1
else
output_help
fi

(From the git-shell-scripts utilities from smtlaissezfaire)


Note:

another way is described here if you have yet to commit your current modification.

git checkout -- filename

git checkout has some options for a file, modifying the file from HEAD, overwriting your change.


Dropped.on.Caprica mentions in the comments:

You can add an alias to git so you can do git revert-file <hash> <file-loc> and have that specific file be reverted.
See this gist.

[alias]
  revert-file = !sh /home/some-user/git-file-revert.sh

Solution 4

Much simpler:

git reset HEAD^ path/to/file/to/revert

then

git commit --amend   

and then

git push -f

the file is gone and commit hash, message, etc is the same.

Solution 5

I would simply use the --no-commit option to git-revert and then remove the files you don't want reverted from the index before finally committing it. Here's an example showing how to easily revert just the changes to foo.c in the second most recent commit:

$ git revert --no-commit HEAD~1
$ git reset HEAD
$ git add foo.c
$ git commit -m "Reverting recent change to foo.c"
$ git reset --hard HEAD

The first git-reset "unstages" all files, so that we can then add back just the one file we want reverted. The final git-reset --hard gets rid of the remaining file reverts that we don't want to keep.

Share:
91,846

Related videos on Youtube

lprsd
Author by

lprsd

I am a curious learner! You should follow me on twitter as @lprsd_

Updated on June 18, 2021

Comments

  • lprsd
    lprsd almost 3 years

    I want to revert changes made by a particular commit to a given file only.

    Can I use git revert command for that?

    Any other simple way to do it?

  • Mark Edington
    Mark Edington over 10 years
    Nicely done. The script solution is overkill for this. Why can't there just be git revert sha-1 filename ?
  • AlbertEngelB
    AlbertEngelB about 9 years
    Just to add to the discussion here, you can add an alias to git so you can do git revert-file <hash> <file-loc> and have that specific file be reverted. I lifted from this answer (though I had to make a couple edits to work correctly). You can find a copy of my .gitconfig and edited script here: gist.github.com/droppedoncaprica/5b67ec0021371a0ad438
  • VonC
    VonC about 9 years
    @Dropped.on.Caprica good point. I have included it in the answer for more visibility.
  • Kedar Mhaswade
    Kedar Mhaswade almost 9 years
    This works on my Mac, but on Windows (under Cygwin) it gives me: fatal: unrecognized input
  • Merhawi Fissehaye
    Merhawi Fissehaye almost 9 years
    It only puts back the file from the index. I needed to then run git checkout -- some_file.c to fully revert the file back.
  • ViFI
    ViFI over 7 years
    @MerhawiFissehaye : I think git checkout will only revert the changes again to fall back to the state what was in commit. I did 'git add filename ; git commit --amend' to remove the file from commit.
  • acidnbass
    acidnbass over 7 years
    This works wonderfully, but are there any caveats to this approach vs @VonC's that are worth knowing?
  • angularsen
    angularsen over 7 years
    Just want to point out that this assumes you can edit the git history. Some answers above create a new commit that reverses the particular change without editing the history, which is not always possible/allowed.
  • angularsen
    angularsen over 7 years
    Just a tip, I almost always have to add the -3 flag to git apply for three-way merge when the patch fails, since I am usually correcting a change a bit back in time.
  • Marcus Junius Brutus
    Marcus Junius Brutus over 6 years
    @KedarMhaswade same thing in Ubuntu. Turns out it was ANSI escape sequences for colors, once those were stripped, it worked
  • Warpling
    Warpling over 6 years
    Maybe obvious to most but ensure some_file.c includes the path to the file if there is one otherwise you'll silently patch nothing :)
  • manpatha
    manpatha over 6 years
    doesn't work for a binary file. Nevertheless, I copied original file back and did git add/git commit --amend.
  • Kevin
    Kevin over 6 years
    For completeness, do you need a git checkout -- path/to/file/to/revert step? Also, it is not true that the hash is the same afterwards, right? The last sentence might be better as something like: "The result is that the last commit is replaced by a new one that differs only in that it does not contain the changes to the reverted file."
  • mraxus
    mraxus about 5 years
    Fantastic. This was exactly what I was looking for. I had this idea already, but got confused when doing the interactive rebase that the files when doing the edit was not showing as changed. But the git show -- badfile.txt | git apply -R gave the answer I needed <3
  • Forrest
    Forrest over 4 years
    @Kevin you're probably right. I'll have to double check that last line, but looking back at this from a couple years ago I'd be surprised if the commit hash is unchanged.
  • DaImTo
    DaImTo about 4 years
    if i understand this git apply -R removes the commit on that file setting it back to the original changed state?
  • georgiecasey
    georgiecasey almost 4 years
    If you get an unrecognized input on Windows, maybe you're simply using forward slashes in your filenames instead of backslashes. Also, quote each file if it's a list of files. So my command looked like: git show 0fa42bec07005e47401ddba2e0e28f60cb034fa6 -- "app/js/controllers/file1.controller.js" "app/templates/views/file1.pug" "java/core/src/main/java/com/georgiecasey/file3.kt" | git apply -R
  • Adam Rosenfield
    Adam Rosenfield over 3 years
    To do this for the previous commit without looking up the exact commit hash, you can use git show HEAD^{commit} -- [...]; it doesn't seem to work with just HEAD without the ^{commit} unfortunately. (Windows users: the ^ also has to be escaped as ^^)
  • ScottyBlades
    ScottyBlades almost 3 years
    What if you don't know the commit sha/s that made the changes?
  • mgalgs
    mgalgs almost 3 years
  • Preston McCormick
    Preston McCormick almost 3 years
    This is the way to go if you aren't looking to rewrite history. I've been using this to cleanup files I didn't really need to touch prior to a squash merge. Then the churn gets paved over anyway.