* Merge seems to get confused by (reverted) cherry-picks @ 2008-09-03 7:20 Björn Steinbrink 2008-09-03 7:25 ` Björn Steinbrink 2008-09-03 7:50 ` Junio C Hamano 0 siblings, 2 replies; 9+ messages in thread From: Björn Steinbrink @ 2008-09-03 7:20 UTC (permalink / raw) To: Junio C Hamano, Linus Torvalds; +Cc: git Hi, "git merge" produces a (IMHO) wrong result, when a commit from the branch that is to be merged in was cherry-picked into the current branch and later reverted on the original branch. Basically ignoring the revert. Example: mkdir gmt cd gmt git init /bin/echo -e "1\n2\n3\n4\n5\n6\n" > file git add file git commit -m init /bin/echo -e "1\n2\n3\na\n4\n5\n6\n" > file git add file git commit -m add git revert --no-edit HEAD git checkout -b test HEAD~2 sleep 1 # Avoid race git cherry-pick master^ git merge master That last "git merge" call happily tells: Already uptodate! Merge made by recursive. And "file" still contains the "a" that was added in the second commit. Seems broken to me, of course I want that revert to "show up" in the merge result, probably as a conflict for me to resolve. Björn ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 7:20 Merge seems to get confused by (reverted) cherry-picks Björn Steinbrink @ 2008-09-03 7:25 ` Björn Steinbrink 2008-09-03 7:50 ` Junio C Hamano 1 sibling, 0 replies; 9+ messages in thread From: Björn Steinbrink @ 2008-09-03 7:25 UTC (permalink / raw) To: Junio C Hamano, Linus Torvalds; +Cc: git On 2008.09.03 09:20:11 +0200, Björn Steinbrink wrote: > Hi, > > "git merge" produces a (IMHO) wrong result, when a commit from the > branch that is to be merged in was cherry-picked into the current branch > and later reverted on the original branch. Basically ignoring the > revert. > > Example: > mkdir gmt > cd gmt > git init > > /bin/echo -e "1\n2\n3\n4\n5\n6\n" > file > git add file > git commit -m init > > /bin/echo -e "1\n2\n3\na\n4\n5\n6\n" > file > git add file > git commit -m add > > git revert --no-edit HEAD > > git checkout -b test HEAD~2 > sleep 1 # Avoid race > git cherry-pick master^ > git merge master > > > That last "git merge" call happily tells: > Already uptodate! > Merge made by recursive. > > And "file" still contains the "a" that was added in the second commit. > > Seems broken to me, of course I want that revert to "show up" in the > merge result, probably as a conflict for me to resolve. I knew I would forget something... That's with: $ git --version git version 1.6.0.1.196.g01914 Björn ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 7:20 Merge seems to get confused by (reverted) cherry-picks Björn Steinbrink 2008-09-03 7:25 ` Björn Steinbrink @ 2008-09-03 7:50 ` Junio C Hamano 2008-09-03 8:37 ` Björn Steinbrink 2008-09-03 9:19 ` Ittay Dror 1 sibling, 2 replies; 9+ messages in thread From: Junio C Hamano @ 2008-09-03 7:50 UTC (permalink / raw) To: Björn Steinbrink; +Cc: Linus Torvalds, git Björn Steinbrink <B.Steinbrink@gmx.de> writes: > "git merge" produces a (IMHO) wrong result, when a commit from the > branch that is to be merged in was cherry-picked into the current branch > and later reverted on the original branch. Basically ignoring the > revert. There are a few issues around 3-way merge. One thing is, what happened in between the common ancestor and the final results on histories before you initiate the merges does not matter. When doing a 3-way merge, you look only at three endpoints: your final state, their final state and the common ancestor between the two. Your history looks like this: 123a456 3-----------? / / / / 0-----1-----2 123456 123456 During the development between 0..2, your undecision might have caused the contents of the file fluctuate back and forth many number of times, but in the end result, you (the one who went 0..1..2) decided that for your development, you do not have to change the contents of that path. The path might have been a xyzzy.h file, and you once added an extern decl of a function because you thought a function in xyzzy.c might be needed by another file frotz.c, but it turned out that the function can stay private and you removed that extern decl from xyzzy.h and ended up in the same state. But the other person who built the history 0..3 decided that having the change is better than not having it. Perhaps his code does use the function from some other place and needs an extern. You are merging the two histories, which means by definition you trust your decision and the other guys decision with equal weight. And here is another thing. When you compare the path in question at 0 and 2, you see they are identical. And you are interpreting that "I say they MUST STAY THE SAME, while they say they want to change it some way, that is a conflict". But in 3-way merge context, you do not interpret the fact that something is identical between 0..2 as "they MUST STAY THE SAME". Instead, you read it as "My history does not care what happens to that path -- if the other guy wants to change it, I'll happily take it." Note. I am not claiming that the above interpretation will always match what you would expect. I am just explaining how the underlying concept of 3-way merge works in general. If you think about it in a realistic context, such as the "extern in xyzzy.h you did not need to add but the other guy needed to have", you'll realize that more often than not, "I do not care and let the other guy decide" interpretation results in a more useful result. That essentially boils down to three rules: (0) If both of you did not change anything, the final result won't have any change (obvious); (1) If you decided you do not have a need to change a path, but the other one saw a need, you take the change; (2) If you and the other one both wanted to change a path but in a different way, you need to merge at the contents level. And you are seeing rule (1) in action. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 7:50 ` Junio C Hamano @ 2008-09-03 8:37 ` Björn Steinbrink 2008-09-03 15:26 ` Linus Torvalds 2008-09-03 9:19 ` Ittay Dror 1 sibling, 1 reply; 9+ messages in thread From: Björn Steinbrink @ 2008-09-03 8:37 UTC (permalink / raw) To: Junio C Hamano; +Cc: Linus Torvalds, git On 2008.09.03 00:50:43 -0700, Junio C Hamano wrote: > But in 3-way merge context, you do not interpret the fact that something > is identical between 0..2 as "they MUST STAY THE SAME". Instead, you read > it as "My history does not care what happens to that path -- if the other > guy wants to change it, I'll happily take it." > > Note. I am not claiming that the above interpretation will always > match what you would expect. I am just explaining how the underlying > concept of 3-way merge works in general. If you think about it in a > realistic context, such as the "extern in xyzzy.h you did not need to > add but the other guy needed to have", you'll realize that more often > than not, "I do not care and let the other guy decide" interpretation > results in a more useful result. > > That essentially boils down to three rules: > > (0) If both of you did not change anything, the final result won't have > any change (obvious); > > (1) If you decided you do not have a need to change a path, but the other > one saw a need, you take the change; > > (2) If you and the other one both wanted to change a path but in a > different way, you need to merge at the contents level. > > And you are seeing rule (1) in action. OK, so that basically means "if you cherry-pick, you better make sure that you don't have to revert or just get your fine-toothed comb ready when you merge later", right? Any advice on how to deal with such a situation? The actual use case I had was somewhat like this: Some new code got added in commit A on the master branch as it was intended for the next major release. Then it became obvious that it needs to go into a minor release, so it got cherry-picked into the maintainance branch. For some reason that new code then got moved into a different file. That move happened on the maintainance branch (ie. immediate bugfix). And then came the regular merge of the maintainance branch into the master branch, which ended up with the code being duplicated. (Well, actually, it's a two-level maintainance branch setup, but you get the idea...) Of course, in a perfect world the first commit would never have been cherry-picked and would've been originally made on the maintainance branch, and the problem would have never shown up. But that's not the case and I'm not omniscient, so I would have surely missed the problem, if it wasn't for that two-level setup, which for this merge meant that the merge result should have been equal to the branch being merged, so it was easy to spot. Björn ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 8:37 ` Björn Steinbrink @ 2008-09-03 15:26 ` Linus Torvalds 0 siblings, 0 replies; 9+ messages in thread From: Linus Torvalds @ 2008-09-03 15:26 UTC (permalink / raw) To: Björn Steinbrink; +Cc: Junio C Hamano, git On Wed, 3 Sep 2008, Björn Steinbrink wrote: > > OK, so that basically means "if you cherry-pick, you better make sure > that you don't have to revert or just get your fine-toothed comb ready > when you merge later", right? Any advice on how to deal with such a > situation? Well, it's not actually even really related to cherry-picks in particular, although yes, cherry-picks and reverts are perhaps the simplest case to explain. At a more fundamental level, it's about git _not_ caring about any individual commit in the history, and only caring about the "big picture". In this, git is fairly consistent - the same way that git never cares about any individual _file_, but always merges the whole tree, it also never really cares about any individual _commit_, but always the whole history. So it really doesn't matter if one commit undid another - the only thing that matters as far as git merging is concerned is what the final set of changes were from the common base point. Now, there's nothing to say that git _couldn't_ try to look at individual commits when deciding how to merge, but I actually think it's fundamentally wrong to do so, for pretty much the same reason I think it's fundamentally wrong to try to encode rename information. The fact is, should it really matter whether something was "reverted", or whether multiple gradual changes made ot go back to what it used to be? Git says no, an considers the two to be totally equivalent in the end. exactly the same way that git doesn't matter whether you first created a new file and later deleted a similar old file, or whether you renamed it. The only thing that matters is the end result. So if you have one branch that first does "A", and then does "revert A", as far as git is concerned, that branch didn't do anything at all when it comes to data. So when you merge it with another branch that does "A" too, the end result is that the merged contents will have A. That's fairly easy to understand if you just think of git as caring about the whole end result and just doing a three-way merge at the end points (which is what it does), but I would also like to explain why I think it's fundamentally the _right_ thing to do, not just an "implementation detail because it's simpler". When one branch does the "revert A" does that really mean that A was bad? No. It could mean that A was "unnecessary" or "not quite ready". The revert, after all, was literally done in the context of _that_ branch, and the reasons may well have been totally private to that branch. Git doesn't know, and git shouldn't care - the only thing that should matter is the end result. To really hammer this point in, let's say that "A" was really doing two different things - A1 and A2 - to two different files. And let's further say that it had been cherry-picked because the one branch needed just a part of it - A1. And then later, in a fit of cleanup madness, that branch undid A2, because it really didn't need it. When you merge the two branches, what do you expect? You could argue that you would expect A2 to be undone in the original branch too. It was, after all, a partial revert. But I think you'll agree that it's not at all "obvious" any more. In fact, I will argue that it would be horribly _wrong_, because the branch that undid part of A could have done it two different ways: - it could do the "cherry-pick A" as one commit and the "undo A2" as another (as I implied above) - but it could equally well have done a "cherry-pick just part of A", and done it as just one commit (perhaps because it noticed that A2 didn't even _compile_ within the context of that branch, and did an '--amend' to fix it up rather than create a new commit. See? Shouldn't both really act the same? Should it really make a difference to what git does if there was a cherry-pick and a partial revert, or a partial cherry-pick? Should _how_ you do something matter more than the end result? HELL NO! And is the "partial revert" really any different from the "total revert"? Now, if you're a math person, think of the "limit behavior" as A2 approaches all of A. The final end result is that you were to revert _all_ of A. Should that limit case be fundamentally different from the case of A2 being just a _part_ of A? What should the logic be? What if all of A was reverted except for the whitespace cleanups that it did (almost by mistake?) So in the end, the answer is that git doesn't care about individual commits, because caring about individual commits is totally crazy. Git _remembers_ them, of course, and it can _show_ you them when you merge, but the actual end result depends purely on the *state* of the merge (and the "big picture" of the history, ie where the branches join etc), not of the small details of how you got to that state. And that is fundamentally the only sane thing to do. Here's another final thought to leave you with: - what if the other branch had decided that instead of reverting it, it could just do a "git rebase -i" _without_ it, because that other branch had never been exposed to anybody else? See? The "how you got to some state" really must be immaterial in a stable merge strategy. I realize that I'm at odds with some SCM people on this, but I'm ok with that, because I also realize that all those other SCM people are just _stupid_. Linus ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 7:50 ` Junio C Hamano 2008-09-03 8:37 ` Björn Steinbrink @ 2008-09-03 9:19 ` Ittay Dror 2008-09-03 11:04 ` Andreas Ericsson 2008-09-03 11:16 ` Johan Herland 1 sibling, 2 replies; 9+ messages in thread From: Ittay Dror @ 2008-09-03 9:19 UTC (permalink / raw) To: Junio C Hamano; +Cc: Björn Steinbrink, Linus Torvalds, git Note: codeville tried to implement a merge algorithm that considers the history to decide what the user wants to do: http://revctrl.org/PreciseCodevilleMerge. Maybe worth while exploring? Ittay Junio C Hamano wrote: > Björn Steinbrink <B.Steinbrink@gmx.de> writes: > > >> "git merge" produces a (IMHO) wrong result, when a commit from the >> branch that is to be merged in was cherry-picked into the current branch >> and later reverted on the original branch. Basically ignoring the >> revert. >> > > There are a few issues around 3-way merge. > > One thing is, what happened in between the common ancestor and the final > results on histories before you initiate the merges does not matter. When > doing a 3-way merge, you look only at three endpoints: your final state, > their final state and the common ancestor between the two. > > Your history looks like this: > > 123a456 > 3-----------? > / / > / / > 0-----1-----2 > 123456 123456 > > During the development between 0..2, your undecision might have caused the > contents of the file fluctuate back and forth many number of times, but in > the end result, you (the one who went 0..1..2) decided that for your > development, you do not have to change the contents of that path. The > path might have been a xyzzy.h file, and you once added an extern decl of > a function because you thought a function in xyzzy.c might be needed by > another file frotz.c, but it turned out that the function can stay private > and you removed that extern decl from xyzzy.h and ended up in the same > state. > > But the other person who built the history 0..3 decided that having the > change is better than not having it. Perhaps his code does use the > function from some other place and needs an extern. > > You are merging the two histories, which means by definition you trust > your decision and the other guys decision with equal weight. And here is > another thing. > > When you compare the path in question at 0 and 2, you see they are > identical. And you are interpreting that "I say they MUST STAY THE SAME, > while they say they want to change it some way, that is a conflict". > > But in 3-way merge context, you do not interpret the fact that something > is identical between 0..2 as "they MUST STAY THE SAME". Instead, you read > it as "My history does not care what happens to that path -- if the other > guy wants to change it, I'll happily take it." > > Note. I am not claiming that the above interpretation will always > match what you would expect. I am just explaining how the underlying > concept of 3-way merge works in general. If you think about it in a > realistic context, such as the "extern in xyzzy.h you did not need to > add but the other guy needed to have", you'll realize that more often > than not, "I do not care and let the other guy decide" interpretation > results in a more useful result. > > That essentially boils down to three rules: > > (0) If both of you did not change anything, the final result won't have > any change (obvious); > > (1) If you decided you do not have a need to change a path, but the other > one saw a need, you take the change; > > (2) If you and the other one both wanted to change a path but in a > different way, you need to merge at the contents level. > > And you are seeing rule (1) in action. > -- > To unsubscribe from this list: send the line "unsubscribe git" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > > -- Ittay Dror <ittayd@tikalk.com> Tikal <http://www.tikalk.com> Tikal Project <http://tikal.sourceforge.net> -- -- Ittay Dror <ittay.dror@gmail.com> ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 9:19 ` Ittay Dror @ 2008-09-03 11:04 ` Andreas Ericsson 2008-09-03 11:16 ` Johan Herland 1 sibling, 0 replies; 9+ messages in thread From: Andreas Ericsson @ 2008-09-03 11:04 UTC (permalink / raw) To: Ittay Dror; +Cc: Junio C Hamano, Björn Steinbrink, Linus Torvalds, git Ittay Dror wrote: > Note: codeville tried to implement a merge algorithm that considers the > history to decide what the user wants to do: > http://revctrl.org/PreciseCodevilleMerge. Maybe worth while exploring? > I believe that one would still fail for this case, as "ImplicitUndo" isn't included. Besides that, I'd rather have something simple that does something predictable than something complex that pushes the "gets it right" figure from 98% to 99.2%, while failing in completely annoying and surprising ways sometimes. Someone or something still has to verify that the merge produced something sane. -- Andreas Ericsson andreas.ericsson@op5.se OP5 AB www.op5.se Tel: +46 8-230225 Fax: +46 8-230231 ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 9:19 ` Ittay Dror 2008-09-03 11:04 ` Andreas Ericsson @ 2008-09-03 11:16 ` Johan Herland 2008-09-03 17:10 ` Mike Hommey 1 sibling, 1 reply; 9+ messages in thread From: Johan Herland @ 2008-09-03 11:16 UTC (permalink / raw) To: Ittay Dror; +Cc: git, Junio C Hamano, Björn Steinbrink, Linus Torvalds On Wednesday 03 September 2008, Ittay Dror wrote: > Note: codeville tried to implement a merge algorithm that considers > the history to decide what the user wants to do: > http://revctrl.org/PreciseCodevilleMerge. Maybe worth while > exploring? You haven't been here long, have you? ;) There was an infamous mailing list discussion between Bram Cohen (who created PreciseCodevilleMerge), and Linus Torvalds back in 2005, discussing merge strategies. It is well recounted here: http://wincent.com/a/about/wincent/weblog/archives/2007/07/a_look_back_bra.php Also, nowadays, even Bram himself seems to have conceded PreciseCodevilleMerge in favour of traditional 3-way merge, at least if you look at item #3 in the following posting from his blog: http://bramcohen.livejournal.com/52148.html ...Johan -- Johan Herland, <johan@herland.net> www.herland.net ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Merge seems to get confused by (reverted) cherry-picks 2008-09-03 11:16 ` Johan Herland @ 2008-09-03 17:10 ` Mike Hommey 0 siblings, 0 replies; 9+ messages in thread From: Mike Hommey @ 2008-09-03 17:10 UTC (permalink / raw) To: Johan Herland Cc: Ittay Dror, git, Junio C Hamano, Björn Steinbrink, Linus Torvalds On Wed, Sep 03, 2008 at 01:16:05PM +0200, Johan Herland wrote: > On Wednesday 03 September 2008, Ittay Dror wrote: > > Note: codeville tried to implement a merge algorithm that considers > > the history to decide what the user wants to do: > > http://revctrl.org/PreciseCodevilleMerge. Maybe worth while > > exploring? > > You haven't been here long, have you? ;) > > There was an infamous mailing list discussion between Bram Cohen (who > created PreciseCodevilleMerge), and Linus Torvalds back in 2005, > discussing merge strategies. It is well recounted here: > > http://wincent.com/a/about/wincent/weblog/archives/2007/07/a_look_back_bra.php I quite agree with the footnote statement, except on one thing: it would make it easier to have additional tools to help with such merge resolutions automatically. While resolving a rename/delete merge conflict is not a big deal, resolving function moves from one file to another (possibly new) file is another story. Mike ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-09-03 17:11 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-09-03 7:20 Merge seems to get confused by (reverted) cherry-picks Björn Steinbrink 2008-09-03 7:25 ` Björn Steinbrink 2008-09-03 7:50 ` Junio C Hamano 2008-09-03 8:37 ` Björn Steinbrink 2008-09-03 15:26 ` Linus Torvalds 2008-09-03 9:19 ` Ittay Dror 2008-09-03 11:04 ` Andreas Ericsson 2008-09-03 11:16 ` Johan Herland 2008-09-03 17:10 ` Mike Hommey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).