Git development
 help / color / mirror / Atom feed
* [RFC] Making pathspec limited log play nicer with --first-parent
@ 2012-01-19 19:58 Junio C Hamano
  2012-01-19 20:15 ` Linus Torvalds
  0 siblings, 1 reply; 4+ messages in thread
From: Junio C Hamano @ 2012-01-19 19:58 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds

I often find myself frustrated when I receive an update to a part of the
project and want to find the latest commit that merges the topic branch
that touched the same area.

For example, I wanted to find the latest merge of any git-p4 related topic
so that I can fork a new topic branch to keep Luke's updates posted today.

Without pathspec, "git log --first-parent" traverses the first-parent
chain just fine, and "-m --stat" shows the list of paths touched by the
merge, so we _could_ ask the question this way:

    $ git log --first-parent --oneline -m --stat master |
      sed -e '/^ contrib\/fast-import\/git-p4 /q' | tail
      
The above finds that 8cbfc11 (Merge branch 'pw/p4-view-updates',
2012-01-06) was such a commit.

But a more natural way to spell it does not work as expected:

    $ git log --first-parent --oneline -m --stat -1 master -- \
      contrib/fast-import/git-p4

This finds ecb7cf9 (git-p4: rewrite view handling, 2012-01-02), which is a
part of the merged topic branch and is _not_ on the first-parent path from
the 'master':

    $ git show-branch 8cbfc11 ecb7cf9
    ! [8cbfc11] Merge branch 'pw/p4-view-updates'
     ! [ecb7cf9] git-p4: rewrite view handling
    --
    -  [8cbfc11] Merge branch 'pw/p4-view-updates'
    +  [8cbfc11^2] git-p4: view spec documentation
    ++ [ecb7cf9] git-p4: rewrite view handling

The problem happens when the merge simplification logic kicks in when the
traversal inspects the merge 8cbfc11. In this case, the history leading to
the tip of 'master' did not touch git-p4 since 'pw/p4-view-updates' topic
forked from it, and the result of the merge is simply a copy from the tip
of the topic branch in the view limited by the given pathspec.  The merge
simplification logic discards the first-parent of the merge and pretends
as if the sole parent of the merge is its second parent, i.e. the tip of
the topic. The history traversal veers off to the side branch, possibly
skipping a large swath of the mainline history if the topic forked from it
long in the past, but that only happens when the mainline did not touch
the paths in the limited view since the side topic forked, so it is not
losing information---but it still is wrong to show the commits on the side
topic when we are explicitly asked to show the first-parent chain.

Here is an attempt to fix this issue, by not allowing us to compare the
merge result with anything but the first parent when --first-parent is in
effect, to avoid the history traversal veering off to the side branch.

As this touches deep innards of a scary hairball that is the revision
traversal machinery, I am obviously not considering it as a 1.7.9
material, but I think we would want to fix it at some point, hopefully
soon.

With this patch, the "more natural way" finds the merge commit I am
looking for.

Comments?

---
 revision.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/revision.c b/revision.c
index 064e351..9e4596d 100644
--- a/revision.c
+++ b/revision.c
@@ -416,7 +416,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 {
 	struct commit_list **pp, *parent;
-	int tree_changed = 0, tree_same = 0;
+	int tree_changed = 0, tree_same = 0, nth_parent = 0;
 
 	/*
 	 * If we don't do pruning, everything is interesting
@@ -444,6 +444,8 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 	while ((parent = *pp) != NULL) {
 		struct commit *p = parent->item;
 
+		if (revs->first_parent_only && nth_parent++)
+			break;
 		if (parse_commit(p) < 0)
 			die("cannot simplify commit %s (because of %s)",
 			    sha1_to_hex(commit->object.sha1),

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC] Making pathspec limited log play nicer with --first-parent
  2012-01-19 19:58 [RFC] Making pathspec limited log play nicer with --first-parent Junio C Hamano
@ 2012-01-19 20:15 ` Linus Torvalds
  2012-01-19 20:43   ` Junio C Hamano
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Torvalds @ 2012-01-19 20:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 661 bytes --]

On Thu, Jan 19, 2012 at 11:58 AM, Junio C Hamano <gitster@pobox.com> wrote:
>
> Comments?

Looks conceptually right, but I do have to admit to hating that new variable.

I don't see a better way to do it, though. Sure, you could do it with just

   if (revs->first_parent_only && pp != &commit->parents)
             break;

and avoid the new variable that way, but that replaces the annoying
variable with a pretty subtle thing.

Or we could re-write that while() loop and move the 'parent' variable
into it. Like the appended untested thing.

But maybe your patch is better, and my dislike for that parent counter
is just irrational.

                  Linus

[-- Attachment #2: patch.diff --]
[-- Type: text/x-patch, Size: 1606 bytes --]

 revision.c |   16 ++++++++++------
 1 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/revision.c b/revision.c
index 064e35108478..5e8eb379c369 100644
--- a/revision.c
+++ b/revision.c
@@ -415,7 +415,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 
 static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 {
-	struct commit_list **pp, *parent;
+	struct commit_list **pp;
 	int tree_changed = 0, tree_same = 0;
 
 	/*
@@ -441,8 +441,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 		return;
 
 	pp = &commit->parents;
-	while ((parent = *pp) != NULL) {
-		struct commit *p = parent->item;
+	do {
+		struct commit_list *parent = *pp;
+		struct commit *p;
+
+		if (!parent)
+			break;
+		pp = &parent->next;
+		p = parent->item;
 
 		if (parse_commit(p) < 0)
 			die("cannot simplify commit %s (because of %s)",
@@ -458,7 +464,6 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 				 * to lose the other branches of this
 				 * merge, so we just keep going.
 				 */
-				pp = &parent->next;
 				continue;
 			}
 			parent->next = NULL;
@@ -487,11 +492,10 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 		case REV_TREE_OLD:
 		case REV_TREE_DIFFERENT:
 			tree_changed = 1;
-			pp = &parent->next;
 			continue;
 		}
 		die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
-	}
+	} while (!revs->first_parent_only);
 	if (tree_changed && !tree_same)
 		return;
 	commit->object.flags |= TREESAME;

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC] Making pathspec limited log play nicer with --first-parent
  2012-01-19 20:15 ` Linus Torvalds
@ 2012-01-19 20:43   ` Junio C Hamano
  2012-01-19 20:48     ` Linus Torvalds
  0 siblings, 1 reply; 4+ messages in thread
From: Junio C Hamano @ 2012-01-19 20:43 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Thu, Jan 19, 2012 at 11:58 AM, Junio C Hamano <gitster@pobox.com> wrote:
>>
>> Comments?
>
> Looks conceptually right, but I do have to admit to hating that new variable.
>
> I don't see a better way to do it, though. Sure, you could do it with just
>
>    if (revs->first_parent_only && pp != &commit->parents)
>              break;
>
> and avoid the new variable that way, but that replaces the annoying
> variable with a pretty subtle thing.
>
> Or we could re-write that while() loop and move the 'parent' variable
> into it. Like the appended untested thing.
>
> But maybe your patch is better, and my dislike for that parent counter
> is just irrational.

I didn't like that parent counter that _only_ increments when we are
running under first-parent-only mode at the conceptual level. At the
implementation level, of course it is the right thing to do because
outside first-parent-only mode nobody cares about the parent counter,
so it is a valid but subtle optimization.

But I personally find your loop

	do {
        	...
	} while (!revs->first_parent_only);

is even more disgusting. It is misleading to have something that is not
supposed to change inside the loop as the terminating condition as if we
are saying "loop until somebody flips that bit" which is clearly not the
case.

So obviously I am saying that I do not think either patch is pretty
without offering a better alternative implementation, which is my usual
badness. As this is not an ultra urgent fix, I'll wait and see if somebody
else comes up with a more readable version.

Thanks for eyeballing the logic side of it, anyway. That was what I was
worried about the change the most.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC] Making pathspec limited log play nicer with --first-parent
  2012-01-19 20:43   ` Junio C Hamano
@ 2012-01-19 20:48     ` Linus Torvalds
  0 siblings, 0 replies; 4+ messages in thread
From: Linus Torvalds @ 2012-01-19 20:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Thu, Jan 19, 2012 at 12:43 PM, Junio C Hamano <gitster@pobox.com> wrote:
>
> But I personally find your loop is even more disgusting

Yeah, I can't really argue with that.

The thing I was playing with was to move the entire loop content into
a helper function (which would return the new pp), and then the
"first-parent only" case just wouldn't do a loop at all.

But I couldn't be bothered. Your patch certainly does have the
advantage of being minimally intrusive.

                  Linus

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-01-19 20:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-19 19:58 [RFC] Making pathspec limited log play nicer with --first-parent Junio C Hamano
2012-01-19 20:15 ` Linus Torvalds
2012-01-19 20:43   ` Junio C Hamano
2012-01-19 20:48     ` Linus Torvalds

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox