threads / discuss / 17377

Common ancestor in merge diffs?

Subject: Common ancestor in merge diffs?

## tl;dr

7 messages between Jan 26, 2009 and Jan 26, 2009.

replies: 6people: 4as markdown or json

Daniel Barkalow· Jan 26, 2009, 18:41 UTC · lore

I was just doing an annoying merge (I'd reorganized code while other people made changes to it), and I kept having the problem that it was hard to figure out what each side had done. Is there some way to ask git for the diffs between the common ancestor (which is unique in my case, so it's actually useful) and each of the sides of the merge? Ideally, it would give essentially the converse of the --cc diff: first column is -stage 1 +stage 2; second column is -stage 1 +stage 3.

I think this would generally be more useful than the current diff output for the unresolved portions (-stage 3 +working tree, -stage 2 +working tree) because you're generally quite familiar with the working tree (since you're trying to resolve there), and stage 1 is not obvious.

	-Daniel
*This .sig left intentionally blank*
Johannes Schindelin· Jan 26, 2009, 18:59 UTC · re: Daniel Barkalow · lore

Re: Common ancestor in merge diffs?

Hi,
On Mon, 26 Jan 2009, Daniel Barkalow wrote:
Show 5 quoted lines
> I was just doing an annoying merge (I'd reorganized code while other 
> people made changes to it), and I kept having the problem that it was hard 
> to figure out what each side had done. Is there some way to ask git for 
> the diffs between the common ancestor (which is unique in my case, so it's 
> actually useful) and each of the sides of the merge?
How about
	git diff HEAD...MERGE_HEAD
and
	git diff MERGE_HEAD...HEAD
?  I might have misunderstood, though.

Ciao, Dscho

Daniel Barkalow· Jan 26, 2009, 19:06 UTC · re: Johannes Schindelin · lore

Re: Common ancestor in merge diffs?

On Mon, 26 Jan 2009, Johannes Schindelin wrote:
Show 19 quoted lines
> Hi,
> 
> On Mon, 26 Jan 2009, Daniel Barkalow wrote:
> 
> > I was just doing an annoying merge (I'd reorganized code while other 
> > people made changes to it), and I kept having the problem that it was hard 
> > to figure out what each side had done. Is there some way to ask git for 
> > the diffs between the common ancestor (which is unique in my case, so it's 
> > actually useful) and each of the sides of the merge?
> 
> How about
> 
> 	git diff HEAD...MERGE_HEAD
> 
> and
> 
> 	git diff MERGE_HEAD...HEAD
> 
> ?  I might have misunderstood, though.

That's definitely helpful information (and I'd forgotten about it; I was only thinking of the index). It would be helpful to get it in --cc form, though, rather than as two independant diffs. And it seems somewhat wasteful or something to not use the information in the index, although it's hard to get worked up about with git being blindingly fast anyway.

	-Daniel
*This .sig left intentionally blank*
Linus Torvalds· Jan 26, 2009, 19:05 UTC · re: Daniel Barkalow · lore

Re: Common ancestor in merge diffs?

On Mon, 26 Jan 2009, Daniel Barkalow wrote:
Show 8 quoted lines
>
> I was just doing an annoying merge (I'd reorganized code while other 
> people made changes to it), and I kept having the problem that it was hard 
> to figure out what each side had done. Is there some way to ask git for 
> the diffs between the common ancestor (which is unique in my case, so it's 
> actually useful) and each of the sides of the merge? Ideally, it would 
> give essentially the converse of the --cc diff: first column is -stage 1 
> +stage 2; second column is -stage 1 +stage 3.
Have you tried "gitk --merge [filename]"?

That's usually even more useful - because it doesn't just give a diff, it gives the actual commits that caused the conflict. That way you see what both sides of a merge tried to do.. It's what I do when encountering conflicts on the kernel (where I'm usually not the author of _either_ side of the code that causes a conflict), and it really is very powerful.

That said, finding the diffs from the common case is pretty trivial too. Just do

	git diff MERGE_HEAD...HEAD [filename]

and you'll get the diff from the common case to the HEAD, and if you switch them around, you'll get the diff from the common commit to the MERGE_HEAD. Note the _three_ dots.

			Linus
Daniel Barkalow· Jan 26, 2009, 19:52 UTC · re: Linus Torvalds · lore

Re: Common ancestor in merge diffs?

On Mon, 26 Jan 2009, Linus Torvalds wrote:
Show 17 quoted lines
> On Mon, 26 Jan 2009, Daniel Barkalow wrote:
> >
> > I was just doing an annoying merge (I'd reorganized code while other 
> > people made changes to it), and I kept having the problem that it was hard 
> > to figure out what each side had done. Is there some way to ask git for 
> > the diffs between the common ancestor (which is unique in my case, so it's 
> > actually useful) and each of the sides of the merge? Ideally, it would 
> > give essentially the converse of the --cc diff: first column is -stage 1 
> > +stage 2; second column is -stage 1 +stage 3.
> 
> Have you tried "gitk --merge [filename]"?
> 
> That's usually even more useful - because it doesn't just give a diff, it 
> gives the actual commits that caused the conflict. That way you see what 
> both sides of a merge tried to do.. It's what I do when encountering 
> conflicts on the kernel (where I'm usually not the author of _either_ side 
> of the code that causes a conflict), and it really is very powerful.

That is really nice, and quite handy. I ended up getting approximately that effect with blame and show, but gitk is much easier. For some reason, I never think of the graphical tools. Is there an easy way of focusing on the changes that end up in a particular conflict? Half of the work was finding the right commit and finding the right part of the diff.

	-Daniel
*This .sig left intentionally blank*
Linus Torvalds· Jan 26, 2009, 20:54 UTC · re: Daniel Barkalow · lore

Re: Common ancestor in merge diffs?

On Mon, 26 Jan 2009, Daniel Barkalow wrote:
> 
> That is really nice, and quite handy. I ended up getting approximately 
> that effect with blame and show, but gitk is much easier. For some reason, 
> I never think of the graphical tools.
You can do the same thing on the command-line with just doing
	git log --merge [filename]

but when doing conflict resolution you often do care (deeply) about the way the commits hang together, so the graphical tools really do end up giving you fundamentally interesting information that is hard to show in any readable way with just plain text.

[ Yeah, there's "--graph", but it really loses out on the whole 
  readability thing ]
> Is there an easy way of focusing on the changes that end up in a 
> particular conflict? Half of the work was finding the right commit and 
> finding the right part of the diff.

This is where the command line tools really help. What I do is to just fire up that "gitk" and 90% of the time the thing is clear from that. But _if_ it then is complex, and has a ton of changes to the same file that really aren't that interesting, doing a

	git log --merge -S'interesting-part-goes-here' [filename]

in another window tends to be a good idea. That way you get the commits that just touch that string, and you can do the whole 'goto-SHA1' in the gitk window to see them there.

Sometimes, "git blame -C " is also a good tool to have around. You seem to have found it already. One usage case is

	git blame -C $(git merge-base HEAD MERGE_HEAD).. filename

which then high-lights the lines changed from the merge-base to the HEAD (change it to "..MERGE_HEAD" to see what changed to MERGE_HEAD), but quite frankly, I tend to use "git blame" more as a tool _after_ the merge, when I noticed that I merged things wrong and go back and try to figure out what caused the problem.

		Linus
Junio C Hamano· Jan 26, 2009, 19:55 UTC · re: Daniel Barkalow · lore

Re: Common ancestor in merge diffs?

Daniel Barkalow <barkalow@iabervon.org> writes:
Show 5 quoted lines
> I was just doing an annoying merge (I'd reorganized code while other 
> people made changes to it), and I kept having the problem that it was hard 
> to figure out what each side had done. Is there some way to ask git for 
> the diffs between the common ancestor (which is unique in my case, so it's 
> actually useful) and each of the sides of the merge?
Have you tried "git checkout --conflict=diff3 $that_conflicted_path"?

← back to recent threads