Reputation: 60674
I have a branch where I've made some changes to several files, in several commits. Once, a while back, I started doing some work on a subset of these files, and checked in some changes. After that, we decided that these files should be deleted as part of things being done in another branch. Thus, I want to "untouch" those files - they're not relevant to what I do in my branch anymore, and I don't want to cause any merge conflicts with the elsewhere deleted files because of this.
Is there any way I can update the commit that made those changes to leave those files untouched, and outside the history of my branch?
In more concrete terms:
Consider the following source tree, in the current state:
src/A.java
src/B.java
src/C.java
src/D.java
Some 10 commits back or so in the history, a commit was made that made changes in the following manner:
M src/B.java
M src/C.java
A src/D.java
Is there a way I can remove the changes to C.java
from the history, so that when you look at the commit above it instead looks like
M src/B.java
A src/D.java
As you see, it will appear so that C.java
has never been touched by my branch.
I've looked at git revert
, but haven't been able to figure out a way to do it that without creating a new commit, which resets the changes made by the old one. I know I could also avoid merge conflicts by simply deleting the files in my branch as well, but that feels like an "ugly" solution that works this time but maybe not the next (what if the change in the other branch is not deletion, but modification?), so if there's a cleaner way I'd like to learn it.
Upvotes: 3
Views: 372
Reputation: 60674
Although the now deleted answer by RyPeck RyPeck linked to a good way of doing this using git filter-branch
in the comments, I solved it differently, so I thought I'd share how I did it - if for no other purposes, then as a reference for future me (who will inevitably have to ask the Internet this question again, probably soon...):
First, I did an interactive rebase using git rebase -i master
. That opened up my text editor (I happen to have git configured to open Notepad++) with a file similar to this:
pick First commit message
pick Second commit message
pick This is where I touched the files I didn't want to touch
pick Another commit
pick This goes on for a while
pick I think you get the point
pick I'll stop now
followed by some comments about how to edit the file. What I did, was to change the line with the commit I wanted to alter to
...
edit This is where I touched the files I didn't want to touch
...
and then save and close the editor. What happens then is that git applies the three first commits, then stops and says
Stopped at <hash>... This is where I touched the files I didn't want to touch
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Then, I reset the files to the state they were prior to this commit, using something similar to
git reset HEAD^ src/C.java # undoes the changes to the file
git add src/C.java # stages the undoing of the changes
git commit --amend # amends the undoing to the last commit
After that, the commit has changed the file twice - first the change I made, and then back again - and git has squashed these two sets of changes into one, in which they cancel out and do nothing. I now run
git rebase --continue
to finish the job. If I now look at the history of src/C.java
, there's nothing about this set of commits.
This technique is extremely flexible - using the edit
mode of a commit, you can do any change you want to it.
Upvotes: 1