Re: [PATCH v6] Implement --first-parent for git rev-list --bisect

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

 



Tiago Botelho <tiagonbotelho@xxxxxxxxx> writes:

> diff --git a/bisect.c b/bisect.c
> index 4eafc8262..cb80f29c5 100644
> --- a/bisect.c
> +++ b/bisect.c
> @@ -82,15 +82,16 @@ static inline void weight_set(struct commit_list *elem, int weight)
>  	*((int*)(elem->item->util)) = weight;
>  }
>  
> -static int count_interesting_parents(struct commit *commit)
> +static int count_interesting_parents(struct commit *commit, unsigned bisect_flags)
>  {
>  	struct commit_list *p;
>  	int count;
>  
>  	for (count = 0, p = commit->parents; p; p = p->next) {
> -		if (p->item->object.flags & UNINTERESTING)
> -			continue;
> -		count++;
> +		if (!(p->item->object.flags & UNINTERESTING))
> +		    count++;
> +		if (bisect_flags & BISECT_FIRST_PARENT)
> +			break;
>  	}
>  	return count;
>  }

We either say 0 ("the first parent is uninteresting") or 1 ("it is")
under BISECT_FIRST_PARENT mode.  OK.

> @@ -117,10 +118,10 @@ static inline int halfway(struct commit_list *p, int nr)
>  }
>  
>  #if !DEBUG_BISECT
> -#define show_list(a,b,c,d) do { ; } while (0)
> +#define show_list(a,b,c,d,e) do { ; } while (0)
>  #else
>  static void show_list(const char *debug, int counted, int nr,
> -		      struct commit_list *list)
> +		      struct commit_list *list, unsigned bisect_flags)
>  {
>  	struct commit_list *p;
>  
> @@ -146,10 +147,14 @@ static void show_list(const char *debug, int counted, int nr,

An unrelated tangent, but I think I just spotted a bug in the
existing code on the line immediately before this hunk, which reads

		if (commit->util)
			fprintf(stderr, "%3d", weight(p));

I think this was a bug introduced at bb408ac9 ("bisect.c: use
commit-slab for commit weight instead of commit->util", 2018-05-19)
where the internal implementation of weight() was changed not to
touch commit->util but instead to use a separate commit-slab storage

Looking at the code before that conversion, it seems that we were
using ->util to store a pointer to an integer, so we had the ability
to differenciate non-negative weight (i.e. weight already computed
for the commit), negative weight (i.e. not computed yet, but will
be), and commits to which the concept of weight is not applicable.
When we went to the commit-slab with the change, we lost the ability
to represent the third case.  I am offhand not sure what the best
remedy would be.  Perhaps stuff a so-far unused value like -3 to the
weight() and use weight(p) == -3 instead of the old !commit->util or
something like that?

(Duy CC'ed to help checking my sanity on this point).

In any case, this is an existing bug in a debug helper, and the
focus of this patch is not about fixing that bug, so you can and
should leave it as-is, until this patch successfully adds the
"bisection following only the first parent" feature.

>  		else
>  			fprintf(stderr, "---");
>  		fprintf(stderr, " %.*s", 8, oid_to_hex(&commit->object.oid));
> -		for (pp = commit->parents; pp; pp = pp->next)
> +		for (pp = commit->parents; pp; pp = pp->next) {
>  			fprintf(stderr, " %.*s", 8,
>  				oid_to_hex(&pp->item->object.oid));
>  
> +			if (bisect_flags & BISECT_FIRST_PARENT)
> +				break;
> +		}
> +

I am not sure if we want to do this.  This is a debugging aid that
allows us to peek into the internal state of the commit history
graph being worked on; don't we rather want to make sure that tips
of merged side branches are not participating (e.g. commit->util
that records "weight" is used differently between the first and
other parent commits)?

>  		subject_len = find_commit_subject(buf, &subject_start);
>  		if (subject_len)
>  			fprintf(stderr, " %.*s", subject_len, subject_start);
> @@ -267,13 +272,13 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
>  		unsigned flags = commit->object.flags;
>  
>  		p->item->util = &weights[n++];
> -		switch (count_interesting_parents(commit)) {
> +		switch (count_interesting_parents(commit, bisect_flags)) {
>  		case 0:
>  			if (!(flags & TREESAME)) {
>  				weight_set(p, 1);
>  				counted++;
>  				show_list("bisection 2 count one",
> -					  counted, nr, list);
> +					  counted, nr, list, bisect_flags);
>  			}
>  			/*
>  			 * otherwise, it is known not to reach any

Because count_interesting_parents() returns either 0 or 1 under
BISECT_FIRST_PARENT mode, we will never set -2 in this switch()
statement.  We either paint the bottom boundary with the correct
weight, or -1 (i.e. "its weight is one plus its first parent's
weight" marker).  OK.

> @@ -289,7 +294,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
>  		}
>  	}
>  
> -	show_list("bisection 2 initialize", counted, nr, list);
> +	show_list("bisection 2 initialize", counted, nr, list, bisect_flags);
>  
>  	/*
>  	 * If you have only one parent in the resulting set
> @@ -319,7 +324,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
>  		counted++;
>  	}
>  
> -	show_list("bisection 2 count_distance", counted, nr, list);
> +	show_list("bisection 2 count_distance", counted, nr, list, bisect_flags);

The loop before this part (not shown) is about counting weight for
merges the hard way, which does not apply to us under the new
BISECT_FIRST_PARENT mode.  IOW, "initialize" and "count_distance"
should show exactly the same output from show_list().

>  	while (counted < nr) {
>  		for (p = list; p; p = p->next) {
> @@ -329,6 +334,11 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
>  			if (0 <= weight(p))
>  				continue;

If we know the weight of 'p' already, then we are already done with
it.  In the normal code, that means we are done with all the merges,
so the loop immediately below deals only with a single strand of
pearls.  However, under BISECT_FIRST_PARENT mode, that is
different.  Let's see.

>  			for (q = p->item->parents; q; q = q->next) {
> +				if ((bisect_flags & BISECT_FIRST_PARENT)) {
> +					if (weight(q) < 0)
> +						q = NULL;
> +					break;
> +				}

Under first-parent mode, we uncondtionally break out of the loop
after inspecting the first parent, even if it is a merge.  The code
after this loop (outside the context) says

			if (!q)
				continue;

which is to say "we are not ready to set the weight of p based on
the weight of q, because the latter is unknown".  So that is done by
setting q to NULL, which makes sort of sense.

>  				if (q->item->object.flags & UNINTERESTING)
>  					continue;
> ...
>  				if (0 <= weight(q))

Post context of this hunk is "break;", meaning that if we find an
interesting parent 

What the above original tells us is that when we are doing a full
bisection, we do not look at weight of uninteresting parent and
continue.  In that case we know p is not a merge so we will exit
this for() loop with q set to NULL.

Shouldn't we keep that property even under BISECT_FIRST_PARENT mode?
What I am wondering is the block added to the top of this for() loop.

Shouldn't it be more like this?

                                if ((bisect_flags & BISECT_FIRST_PARENT)) {
					if ((q->item->object.flags & UNINTERESTING) ||
					    (weight(q) < 0))
						q = NULL;
					break;
				}

I do not even recall if weight(q) is defined for an uninteresting q
offhand; your patch requires weight(q) is defined and is negative
for such a 'q' to be correct.  Code would be more trivially correct
with an explicit check for UNINTERESTING, I would think.

In any case, after finding a parent (or not finding, signalled by
being NULL) whose weight is either the same or one less than our
weight, we leave the above for() loop and then ...

> @@ -346,7 +356,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
>  				weight_set(p, weight(q)+1);
>  				counted++;
>  				show_list("bisection 2 count one",
> -					  counted, nr, list);
> +					  counted, nr, list, bisect_flags);
>  			}
>  			else
>  				weight_set(p, weight(q));

... we set our weight based on its weight.  OK.

The remainder of the change looked OK (I didn't look at the the test).

Thanks.



[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