threads / discuss / 13473

"git log --first-parent" shows parents that are not first

Subject: "git log --first-parent" shows parents that are not first

## tl;dr

10 messages between May 11, 2008 and May 14, 2008.

replies: 9people: 4as markdown or json

しらいしななこ· May 11, 2008, 07:03 UTC · lore
Quoting �������  <nanako3@bluebottle.com>:
Show 25 quoted lines
> The result given by "git log --first-parent" ('next' version) is
> unexpected to me.
>
>   % git rev-parse origin/next
>   4eddac518225621c3e4f7285beb879d2b4bad38a
>   % git log --abbrev-commit --pretty=oneline --first-parent origin/next^..origin/next
>   4eddac5... Merge branch 'master' into next
>   1f8115b... Merge branch 'maint'
>   ca1c991... Merge branch 'sg/merge-options' (early part)
>   31a3c6b... Merge branch 'db/learn-HEAD'
>   a064ac1... Merge branch 'jn/webfeed'
>   d576c45... Merge branch 'cc/help'
>   ca1a5ee... Merge branch 'dm/cherry-pick-s'
>   4c4d3ac... Merge branch 'lt/dirmatch-optim'
>   c5445fe... compat-util: avoid macro redefinition warning
>   eb120e6... compat/fopen.c: avoid clobbering the system defined fopen macro
>   bac59f1... Documentation: bisect: add a few "git bisect run" examples
>   d84ae0d... Documentation/config.txt: Add git-gui options
>   921177f... Documentation: improve "add", "pull" and "format-patch" examples
>   c904bf3... Be more careful with objects directory permissions on clone
>
> I asked for the log between one commit before the tip of "origin/next" and the tip of the branch, following only the first-parent links.  v1.5.5 is not broken and shows the expected result:
>
>   % ~/git-v1.5.5/bin/git log --abbrev-commit --pretty=oneline --first-parent origin/next^..origin/next
>   4eddac5... Merge branch 'master' into next

Could you please revert d9c292e8bbd51c84cb9ecd86cb89b8a1b35a2a82? With that patch reverted from 'next', the problem disappears.

-- 
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/

----------------------------------------------------------------------
Free pop3 email with a spam filter.
http://www.bluebottle.com/tag/5
Junio C Hamano· May 11, 2008, 18:44 UTC · re: しらいしななこ · lore

Re: "git log --first-parent" shows parents that are not first

しらいしななこ  <nanako3@bluebottle.com> writes:
Show 21 quoted lines
>> The result given by "git log --first-parent" ('next' version) is
>> unexpected to me.
>>
>>   % git rev-parse origin/next
>>   4eddac518225621c3e4f7285beb879d2b4bad38a
>>   % git log --abbrev-commit --pretty=oneline --first-parent origin/next^..origin/next
>>   4eddac5... Merge branch 'master' into next
>>   1f8115b... Merge branch 'maint'
>> ...
>>   921177f... Documentation: improve "add", "pull" and "format-patch" examples
>>   c904bf3... Be more careful with objects directory permissions on clone
>>
>> I asked for the log between one commit before the tip of "origin/next"
>> and the tip of the branch, following only the first-parent links.
>> v1.5.5 is not broken and shows the expected result:
>>
>>   % ~/git-v1.5.5/bin/git log --abbrev-commit --pretty=oneline --first-parent origin/next^..origin/next
>>   4eddac5... Merge branch 'master' into next
>
> Could you please revert d9c292e8bbd51c84cb9ecd86cb89b8a1b35a2a82?  With
> that patch reverted from 'next', the problem disappears.

That's d9c292e (Simplify and fix --first-parent implementation, 2008-04-27) by Stephen.

I know that the alleged "fix" works around a corner-case, a fast-forward situation that was artificually recorded as a merge, but if the "cure" breaks a normal case like this, it is worse than the disease.

Stephen, do you have a fix?
Lars Hjemli· May 11, 2008, 23:14 UTC · re: Junio C Hamano · lore

[PATCH] revision.c: really honor --first-parent

In add_parents_to_list, if any parent of a revision had already been SEEN, the current code would continue with the next parent. But if the first parent has been SEEN and --first-parent has been specified we need to break, not continue.

Signed-off-by: Lars Hjemli <hjemli@gmail.com>
---
 revision.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/revision.c b/revision.c
index 44d780b..974ad10 100644
--- a/revision.c
+++ b/revision.c
@@ -468,8 +468,11 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
 		if (parse_commit(p) < 0)
 			return -1;
 		p->object.flags |= left_flag;
-		if (p->object.flags & SEEN)
+		if (p->object.flags & SEEN) {
+			if (revs->first_parent_only)
+				break;
 			continue;
+		}
 		p->object.flags |= SEEN;
 		insert_by_date(p, list);
 		if(revs->first_parent_only)
-- 
1.5.5.1.148.g8ee22.dirty
Lars Hjemli· May 12, 2008, 15:12 UTC · re: Lars Hjemli · lore

[PATCH v2] revision.c: really honor --first-parent

In add_parents_to_list, if any parent of a revision had already been SEEN, the current code would continue with the next parent, skipping the test for --first-parent. This patch inverts the test for SEEN so that the test for --first-parent is always performed.

Signed-off-by: Lars Hjemli <hjemli@gmail.com>
---
This is a slightly different approach which I think is less ugly.
 revision.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/revision.c b/revision.c
index 44d780b..2fc26b8 100644
--- a/revision.c
+++ b/revision.c
@@ -468,10 +468,10 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
 		if (parse_commit(p) < 0)
 			return -1;
 		p->object.flags |= left_flag;
-		if (p->object.flags & SEEN)
-			continue;
-		p->object.flags |= SEEN;
-		insert_by_date(p, list);
+		if (!(p->object.flags & SEEN)) {
+			p->object.flags |= SEEN;
+			insert_by_date(p, list);
+		}
 		if(revs->first_parent_only)
 			break;
 	}
-- 
1.5.5.1.148.g8ee22.dirty
Stephen R. van den Berg· May 13, 2008, 20:15 UTC · re: Lars Hjemli · lore

Re: [PATCH v2] revision.c: really honor --first-parent

Lars Hjemli wrote:
>In add_parents_to_list, if any parent of a revision had already been
>SEEN, the current code would continue with the next parent, skipping
>the test for --first-parent. This patch inverts the test for SEEN so
>that the test for --first-parent is always performed.
Let's put it this way:
- If there would have been only one path to any particular point in the
  tree, then the --first-parent flag makes no differences, because the
  tree wouldn't contain any merges to begin with.
- If a tree contains *any* merges (i.e. a commit with multiple parents),
  then there are always multiple paths to some common ancestor, and
  therefore depending on which path you travel up first, you sometimes get
  clashes with the SEEN flag (unpredictable by definition).
- It would seem logical and sufficient to avoid this unpredictability by
  utilising the --first-parent flag to present and walk a tree of commits
  AS IF there were no merges.
- My original patch did just that, it simplified the code to make sure
  that all other parents beside the first parent are ignored when
  walking the tree.
- Your code now doesn't simplify the (IMO) convoluted walk, and still
  marks things as seen, even though in the first-parent case, these
  commits are not really seen at all.  It implies that your code
  generates differing output, depending on the merges present.
- The question now is, do we want the output of --first-parent to be
  immutable with respect to merges being present (but hidden from sight
  during a --first-parent run), or do we want the output of
  --first-parent to actually change depending on variations in parents
  other than the first parent?

I'd say it's better to keep the code simpler, and to make sure the output does *not* depend on any parents other than the first (as implemented in my original patch).

>This is a slightly different approach which I think is less ugly.

Your patch is smaller, and therefore (perhaps) less ugly; the resulting code and logic of my original patch is simpler (IMHO), and therefore cleaner (but it all depends on (the lack of) consensus over the points above).

-- 
Sincerely,                                                          srb@cuci.nl
           Stephen R. van den Berg.

"If I had to live my life again, I'd make the same mistakes, only sooner."
Lars Hjemli· May 13, 2008, 20:43 UTC · re: Stephen R. van den Berg · lore

Re: [PATCH v2] revision.c: really honor --first-parent

On Tue, May 13, 2008 at 10:15 PM, Stephen R. van den Berg <srb@cuci.nl> wrote:
Show 10 quoted lines
> Lars Hjemli wrote:
>  >In add_parents_to_list, if any parent of a revision had already been
>  >SEEN, the current code would continue with the next parent, skipping
>  >the test for --first-parent. This patch inverts the test for SEEN so
>  >that the test for --first-parent is always performed.
>
>  Let's put it this way:
>  - If there would have been only one path to any particular point in the
>   tree, then the --first-parent flag makes no differences, because the
>   tree wouldn't contain any merges to begin with.
True
>  - If a tree contains *any* merges (i.e. a commit with multiple parents),
>   then there are always multiple paths to some common ancestor, and
>   therefore depending on which path you travel up first, you sometimes get
>   clashes with the SEEN flag (unpredictable by definition).
True
>  - It would seem logical and sufficient to avoid this unpredictability by
>   utilising the --first-parent flag to present and walk a tree of commits
>   AS IF there were no merges.
True
>  - My original patch did just that, it simplified the code to make sure
>   that all other parents beside the first parent are ignored when
>   walking the tree.

Except for the case where the first parent had been already SEEN; then it would continue to test the next parents until one was found which was not already SEEN and _that_ parent would be treated as if it was first. And as Nanako showed, a simple `git rev-list HEAD^..HEAD` marks both HEAD and HEAD^ as seen. When combined with --first-parent, the result (with your patch) is that HEAD^2 is treated as the first parent. With my patch on top of yours, the walk stops as HEAD^, which is what we probably both want.

>  - Your code now doesn't simplify the (IMO) convoluted walk, and still
>   marks things as seen, even though in the first-parent case, these
>   commits are not really seen at all.  It implies that your code
>   generates differing output, depending on the merges present.

I don't think so. My code should neither follow nor mark as SEEN any parent but the first (but I could obviously be wrong).

Show 9 quoted lines
>  - The question now is, do we want the output of --first-parent to be
>   immutable with respect to merges being present (but hidden from sight
>   during a --first-parent run), or do we want the output of
>   --first-parent to actually change depending on variations in parents
>   other than the first parent?
>
>  I'd say it's better to keep the code simpler, and to make sure the
>  output does *not* depend on any parents other than the first (as
>  implemented in my original patch).

I agree with your reasoning, and your patch with mine on top seems to achieve that goal.

-- larsh

Junio C Hamano· May 13, 2008, 22:38 UTC · re: Lars Hjemli · lore

Re: [PATCH v2] revision.c: really honor --first-parent

"Lars Hjemli" <hjemli@gmail.com> writes:
Show 20 quoted lines
>>  - My original patch did just that, it simplified the code to make sure
>>   that all other parents beside the first parent are ignored when
>>   walking the tree.
>
> Except for the case where the first parent had been already SEEN; then
> it would continue to test the next parents until one was found which
> was not already SEEN and _that_ parent would be treated as if it was
> first. And as Nanako showed, a simple `git rev-list HEAD^..HEAD` marks
> both HEAD and HEAD^ as seen. When combined with --first-parent, the
> result (with your patch) is that HEAD^2 is treated as the first
> parent. With my patch on top of yours, the walk stops as HEAD^, which
> is what we probably both want.
>
>>  - Your code now doesn't simplify the (IMO) convoluted walk, and still
>>   marks things as seen, even though in the first-parent case, these
>>   commits are not really seen at all.  It implies that your code
>>   generates differing output, depending on the merges present.
>
> I don't think so. My code should neither follow nor mark as SEEN any
> parent but the first (but I could obviously be wrong).

A major part of the "convoluted walk" is the (il-)logic that skipped earlier SEEN parents and treated the first unseen one as if it was the first parent, which is not exactly Stephen's fault. It was placed by yours truly in the very original code but it was done without much thought.

I think your patch is the correct fix for that convolution, regardless of the traversal order stability issue Stephen mentions.

Stephen R. van den Berg· May 14, 2008, 10:34 UTC · re: Junio C Hamano · lore

Re: [PATCH v2] revision.c: really honor --first-parent

Junio C Hamano wrote:
Show 5 quoted lines
>"Lars Hjemli" <hjemli@gmail.com> writes:
>>>  - Your code now doesn't simplify the (IMO) convoluted walk, and still
>>>   marks things as seen, even though in the first-parent case, these
>>>   commits are not really seen at all.  It implies that your code
>>>   generates differing output, depending on the merges present.
>> I don't think so. My code should neither follow nor mark as SEEN any
>> parent but the first (but I could obviously be wrong).
Show 5 quoted lines
>A major part of the "convoluted walk" is the (il-)logic that skipped
>earlier SEEN parents and treated the first unseen one as if it was the
>first parent, which is not exactly Stephen's fault.  It was placed by
>yours truly in the very original code but it was done without much
>thought.
>I think your patch is the correct fix for that convolution, regardless of
>the traversal order stability issue Stephen mentions.

I agree that Lars' patch prevents parts of the tree to go "dark" (so did my patch). However, without either patch, that implies that the current --first-parent code has a high probability of obscuring parts of the tree depending on traversing order (in any tree which contains at least one merge).

So, I'd say, since the current code does not and cannot work reliably for anyone specifically using --first-parent (with every merge encountered, the probability of correctness is multiplied by 0.5 at most/least), you are going to do them a favour anyway by fixing the code, then why not simplify the convolution and make the code rock-steady (and implement my patch)?

Anyone using --first-parent in production now has an embarrassingly high probability of missing commits in his generated lists (I know that I noticed the problem within 5 minutes from actually trying to use the flag to get meaningful output). So fixing and simplifying the code now is rather unlikely to create any more surprises than the current code already presents to existing users (if any).

-- 
Sincerely,                                                          srb@cuci.nl
           Stephen R. van den Berg.

What if there were no hypothetical questions?
Lars Hjemli· May 14, 2008, 10:54 UTC · re: Stephen R. van den Berg · lore

Re: [PATCH v2] revision.c: really honor --first-parent

On Wed, May 14, 2008 at 12:34 PM, Stephen R. van den Berg <srb@cuci.nl> wrote:
Show 6 quoted lines
>  So, I'd say, since the current code does not and cannot work reliably
>  for anyone specifically using --first-parent (with every merge
>  encountered, the probability of correctness is multiplied by 0.5 at
>  most/least), you are going to do them a favour anyway by fixing the code,
>  then why not simplify the convolution and make the code rock-steady (and
>  implement my patch)?

The current 'next' branch in git.git contains your patch with my fixup on top and I believe this fixes _both_ the original issue with first-parent (thanks to your patch) and the issue Nanako discovered (thanks to my patch). Am I missing something?

-- 
larsh
Stephen R. van den Berg· May 14, 2008, 11:10 UTC · re: Lars Hjemli · lore

Re: [PATCH v2] revision.c: really honor --first-parent

Lars Hjemli wrote:
Show 7 quoted lines
>On Wed, May 14, 2008 at 12:34 PM, Stephen R. van den Berg <srb@cuci.nl> wrote:
>>  So, I'd say, since the current code does not and cannot work reliably
>>  for anyone specifically using --first-parent (with every merge
>>  encountered, the probability of correctness is multiplied by 0.5 at
>>  most/least), you are going to do them a favour anyway by fixing the code,
>>  then why not simplify the convolution and make the code rock-steady (and
>>  implement my patch)?
>The current 'next' branch in git.git contains your patch with my fixup
>on top and I believe this fixes _both_ the original issue with
>first-parent (thanks to your patch) and the issue Nanako discovered
>(thanks to my patch). Am I missing something?

Probably not. I didn't check 'next' yet, since neither mine nor your patch had been Acked on the list (I guess it shows that I don't know the procedures here all too well yet).

-- 
Sincerely,                                                          srb@cuci.nl
           Stephen R. van den Berg.

What if there were no hypothetical questions?

← back to recent threads