Domanda

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.

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top