Re: unmerging feature branches

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Tue, 23 Oct 2007, martin f krafft wrote:
> 
> Are there any other methods? Is it conceivable to let git-revert
> revert a merging commit if you tell it somehow which of the two (or
> more) parents are the ones you want undone, meaning that you'd like
> to keep the others?

So let me get this straight.. You have a merge "M" that is the result of 
merging (possibly multiple) topic branches, and you now want to undo the 
part that *one* of them brought in?

First off, let me say that to some degree, what you ask for is not 
possible. Why?

Since you have pushed out the stuff, and don't want to rewrite history 
(which would result in trouble for down-streams - and I heartily approve), 
whatever you do will always have that merge in the commit history.

And that means that while you can certainly undo the *data* that the merge 
brought in, git will always know that you already merged up that branch. 
Which means that if you later decide that you *do* want to do the merge 
after all, you now really cannot - trying to merge the branch later on 
will just be a fast-forward, and you'll never get the actual changes from 
that merge (since git knows you already have them!).

So you can revert the data, but then if you want to get it back, you'll 
need to revert the revert - you cannot just merge the branch again. 

So the first thing you need to realize is that "revert" does not revert 
history, it *only* reverts data. The fact that you did the merge will 
always remain, although you could try to hack around even that by using 
the 'grafts' file and trying to hide it (I really don't think it's a good 
idea, but sure, everything is "possible" in that sense).

Now, that said, reverting the data is not that hard. There is not any 
single-command "revert this arm of a merge", but on the other hand, git 
can certainly help you.

The way to do it is:

	# go back to just before the merge, create a "fixup" branch
	#
	git branch -b fixup M^

	# merge all of it again, *except* the branch you didn't want to 
	# merge (this example assumes that you had a four-way octopus 
	# merge, and you now want to turn it into a three-way with the
	# next-to-last parent skipped):
	#
	git merge -m "fixed merge" M^2 M^4

	# You now have "fixup" containing what you *wanted* it to be
	# after the original merge. Create a temporary branch that is 
	# based on the merge and contains that state instead, and
	# apply the difference. 
	#
	git branch -b temporary M
	git diff ..fixup | git-apply
	git commit -m "fixup commit"

	# You now have the "temporary" branch that contains just the
	# diff that effectively undoes that one merge. Go back to the
	# tip of your development, and cherry-pick it to get git to
	# help you do a good job merging it with all the subsequent
	# development
	# 
	git checkout master	# or whatever branch you used
	git cherry-pick temporary
	.. do whatever you need to do to resolve it
	.. if it didn't go cleanly 

	# Now, edit the commit message to talk about what you did
	#
	git commit --amend

or something to that effect.

Complicated? Yes. The above is strictly speaking more complex than you may 
need, but if you do it like the above, you get maximum help from git (ie 
you *could* have tried to just apply the patch with "git-apply" directly 
on the top of master, but if you do it like the above, then it's 
guaranteed that the patch that undoes the commit will apply cleanly, and 
you then use "git cherry-pick" which uses the merge logic that can do a 
proper three-way merge with renames etc, so if there are conflicts or 
other things, the above will likely be the best way to do it)

So for simple cases, you can do the above more simply, but the above is 
fairly brainless and scriptable except for the *one* place where you 
actually move the changes forward (the single cherry-pick).

There are certainly other ways too. You could just "git revert -n" all the 
commits that came in through the branch you didn't want to merge. That 
doesn't work well if there were merges in that area, though, or of there 
were changes that were common to all the branches (some of which also came 
in through *other* merges).

So the above (UNTESTED! Caveat emptor!) sequence is *one* way of doing it, 
and probably in the end the one that most closely represents what you want 
to do.

			Linus
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux