Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to revert a specific file in a old commit on git

Tags:

git

I think my question is close to this one, but I'm using git.

So, let's say I have

Commit1 changed file1.c and file2.c

Commit2 changed file2.c, file3.c, file4.c

Commit3 changed file1.c , file2.c and file3.c

and so on...

Then, I would like to revert only the changes that Commit2 made in file2.c, but, try to keep the changes that Commit3 made in this file...

What you think? There is some way to do it?

Thank you.

like image 607
Marcos Avatar asked Dec 25 '22 01:12

Marcos


2 Answers

In general, to back out an entire commit, you would use git revert (as you probably already know). Your issue here is that you want to back out only some of the changes in an older commit. But it turns out this is easy, because:

  • git revert has the same effect as applying a patch in reverse (git show or git diff with specific commit IDs as needed, and then git apply -R the resulting patch) and then committing; and
  • git diff allows you to choose which file(s) get diff-ed.

So, for a regular (single parent) commit, you can simply:

git show <commit-id> -- <path>

to get the "interesting" change from <commit-id>, and then pipe (or otherwise feed) the result to git apply -R:

git show HEAD~3 -- <path> | git apply -R

or in this case:

git show commit2 -- file2.c | git apply -R

For a merge commit, git show will produce a combined diff, which is not what you want, so you should use git diff (or git diff-tree) with two specific commit-IDs. Note that you can inspect the diff before (or after) reverse-applying, since git apply does not make the new commit itself (so you will have to do that on your own).

like image 169
torek Avatar answered Jan 05 '23 00:01

torek


You may try to revert Commit2 (that is, apply a new git commit, whose changes would be opposite to the changes made in Commit2) but without committing. There's a instant menu entry in gitk for example. In this new commit you leave only changes made to file2 and commit the result.

Alternatively, you could simply do something like

git diff Commit2..Commit1 -- file2.c > revert.patch
git apply revert.patch

it might be useful to take a look on the patch before applying it because commits after Commit2 may introduce some conflicts with the changes to file2.c from Commit2.

like image 36
user3159253 Avatar answered Jan 05 '23 00:01

user3159253