Marcos
Marcos

Reputation: 47

How to revert a specific file in a old commit on 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.

Upvotes: 4

Views: 2418

Answers (3)

torek
torek

Reputation: 487725

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

Upvotes: 5

user3159253
user3159253

Reputation: 17455

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.

Upvotes: 4

shirakia
shirakia

Reputation: 2409

Do you want to do revert?

Or just want to modify it. If so, you can do it with

git rebase -i HEAD^^

Next, an editor will open. In the editor modify 'pick' to 'edit' on Commit2 like

pick abcdefg Commit3
pick jikdvuf Commit2

to

pick abcdefg Commit3
edit jikdvuf Commit2

Then, you can modify your commit. So now modify the file. You may want to do git checkout FILENAME. After that

git add FILENAME
git rebase --continue

Now you successfully modified the file on Commit2.

Upvotes: 1

Related Questions