Skip to content

Commit 0fe305a

Browse files
alipman88gitster
authored andcommitted
rev-list: allow bisect and first-parent flags
Add first_parent_only parameter to find_bisection(), removing the barrier that prevented combining the --bisect and --first-parent flags when using git rev-list Based-on-patch-by: Tiago Botelho <tiagonbotelho@hotmail.com> Signed-off-by: Aaron Lipman <alipman88@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 15a4802 commit 0fe305a

File tree

7 files changed

+70
-21
lines changed

7 files changed

+70
-21
lines changed

Documentation/rev-list-options.txt

+3-4
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
128128
because merges into a topic branch tend to be only about
129129
adjusting to updated upstream from time to time, and
130130
this option allows you to ignore the individual commits
131-
brought in to your history by such a merge. Cannot be
132-
combined with --bisect.
131+
brought in to your history by such a merge.
133132

134133
--not::
135134
Reverses the meaning of the '{caret}' prefix (or lack thereof)
@@ -207,7 +206,7 @@ ifndef::git-rev-list[]
207206
Pretend as if the bad bisection ref `refs/bisect/bad`
208207
was listed and as if it was followed by `--not` and the good
209208
bisection refs `refs/bisect/good-*` on the command
210-
line. Cannot be combined with --first-parent.
209+
line.
211210
endif::git-rev-list[]
212211

213212
--stdin::
@@ -743,7 +742,7 @@ outputs 'midpoint', the output of the two commands
743742
would be of roughly the same length. Finding the change which
744743
introduces a regression is thus reduced to a binary search: repeatedly
745744
generate and test new 'midpoint's until the commit chain is of length
746-
one. Cannot be combined with --first-parent.
745+
one.
747746

748747
--bisect-vars::
749748
This calculates the same as `--bisect`, except that refs in

bisect.c

+18-10
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,16 @@ static inline void weight_set(struct commit_list *elem, int weight)
8888
**commit_weight_at(&commit_weight, elem->item) = weight;
8989
}
9090

91-
static int count_interesting_parents(struct commit *commit)
91+
static int count_interesting_parents(struct commit *commit, int first_parent_only)
9292
{
9393
struct commit_list *p;
9494
int count;
9595

9696
for (count = 0, p = commit->parents; p; p = p->next) {
97-
if (p->item->object.flags & UNINTERESTING)
98-
continue;
99-
count++;
97+
if (!(p->item->object.flags & UNINTERESTING))
98+
count++;
99+
if (first_parent_only)
100+
break;
100101
}
101102
return count;
102103
}
@@ -259,7 +260,7 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
259260
*/
260261
static struct commit_list *do_find_bisection(struct commit_list *list,
261262
int nr, int *weights,
262-
int find_all)
263+
int find_all, int first_parent_only)
263264
{
264265
int n, counted;
265266
struct commit_list *p;
@@ -271,7 +272,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
271272
unsigned flags = commit->object.flags;
272273

273274
*commit_weight_at(&commit_weight, p->item) = &weights[n++];
274-
switch (count_interesting_parents(commit)) {
275+
switch (count_interesting_parents(commit, first_parent_only)) {
275276
case 0:
276277
if (!(flags & TREESAME)) {
277278
weight_set(p, 1);
@@ -314,6 +315,8 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
314315
continue;
315316
if (weight(p) != -2)
316317
continue;
318+
if (first_parent_only)
319+
BUG("shouldn't be calling count-distance in fp mode");
317320
weight_set(p, count_distance(p));
318321
clear_distance(list);
319322

@@ -332,7 +335,10 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
332335

333336
if (0 <= weight(p))
334337
continue;
335-
for (q = p->item->parents; q; q = q->next) {
338+
339+
for (q = p->item->parents;
340+
q;
341+
q = first_parent_only ? NULL : q->next) {
336342
if (q->item->object.flags & UNINTERESTING)
337343
continue;
338344
if (0 <= weight(q))
@@ -370,7 +376,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
370376
}
371377

372378
void find_bisection(struct commit_list **commit_list, int *reaches,
373-
int *all, int find_all)
379+
int *all, int find_all, int first_parent_only)
374380
{
375381
int nr, on_list;
376382
struct commit_list *list, *p, *best, *next, *last;
@@ -406,7 +412,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
406412
weights = xcalloc(on_list, sizeof(*weights));
407413

408414
/* Do the real work of finding bisection commit. */
409-
best = do_find_bisection(list, nr, weights, find_all);
415+
best = do_find_bisection(list, nr, weights, find_all, first_parent_only);
410416
if (best) {
411417
if (!find_all) {
412418
list->item = best->item;
@@ -991,6 +997,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int
991997
enum bisect_error res = BISECT_OK;
992998
struct object_id *bisect_rev;
993999
char *steps_msg;
1000+
int first_parent_only = 0; /* TODO: pass --first-parent flag from git bisect start */
9941001

9951002
read_bisect_terms(&term_bad, &term_good);
9961003
if (read_bisect_refs())
@@ -1001,11 +1008,12 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int
10011008
return res;
10021009

10031010
bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
1011+
revs.first_parent_only = first_parent_only;
10041012
revs.limited = 1;
10051013

10061014
bisect_common(&revs);
10071015

1008-
find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr);
1016+
find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr, first_parent_only);
10091017
revs.commits = managed_skipped(revs.commits, &tried);
10101018

10111019
if (!revs.commits) {

bisect.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct repository;
1212
* best commit, as chosen by `find_all`.
1313
*/
1414
void find_bisection(struct commit_list **list, int *reaches, int *all,
15-
int find_all);
15+
int find_all, int first_parent_only);
1616

1717
struct commit_list *filter_skipped(struct commit_list *list,
1818
struct commit_list **tried,

builtin/rev-list.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
638638
if (bisect_list) {
639639
int reaches, all;
640640

641-
find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
641+
find_bisection(&revs.commits, &reaches, &all, bisect_find_all, revs.first_parent_only);
642642

643643
if (bisect_show_vars)
644644
return show_bisect_vars(&info, reaches, all);

revision.c

-3
Original file line numberDiff line numberDiff line change
@@ -2869,9 +2869,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
28692869
if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
28702870
die("cannot use --grep-reflog without --walk-reflogs");
28712871

2872-
if (revs->first_parent_only && revs->bisect)
2873-
die(_("--first-parent is incompatible with --bisect"));
2874-
28752872
if (revs->line_level_traverse &&
28762873
(revs->diffopt.output_format & ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT)))
28772874
die(_("-L does not yet support diff formats besides -p and -s"));

t/t6000-rev-list-misc.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ test_expect_success 'rev-list can negate index objects' '
125125
test_cmp expect actual
126126
'
127127

128-
test_expect_success '--bisect and --first-parent can not be combined' '
129-
test_must_fail git rev-list --bisect --first-parent HEAD
128+
test_expect_success '--bisect and --first-parent can be combined' '
129+
git rev-list --bisect --first-parent HEAD
130130
'
131131

132132
test_expect_success '--header shows a NUL after each commit' '

t/t6002-rev-list-bisect.sh

+45
Original file line numberDiff line numberDiff line change
@@ -263,4 +263,49 @@ test_expect_success 'rev-parse --bisect can default to good/bad refs' '
263263
test_cmp expect.sorted actual.sorted
264264
'
265265

266+
test_output_expect_success '--bisect --first-parent' 'git rev-list --bisect --first-parent E ^F' <<EOF
267+
e4
268+
EOF
269+
270+
test_output_expect_success '--first-parent' 'git rev-list --first-parent E ^F' <<EOF
271+
E
272+
e1
273+
e2
274+
e3
275+
e4
276+
e5
277+
e6
278+
e7
279+
e8
280+
EOF
281+
282+
test_output_expect_success '--bisect-vars --first-parent' 'git rev-list --bisect-vars --first-parent E ^F' <<EOF
283+
bisect_rev='e5'
284+
bisect_nr=4
285+
bisect_good=4
286+
bisect_bad=3
287+
bisect_all=9
288+
bisect_steps=2
289+
EOF
290+
291+
test_expect_success '--bisect-all --first-parent' '
292+
cat >expect.unsorted <<-EOF &&
293+
$(git rev-parse E) (tag: E, dist=0)
294+
$(git rev-parse e1) (tag: e1, dist=1)
295+
$(git rev-parse e2) (tag: e2, dist=2)
296+
$(git rev-parse e3) (tag: e3, dist=3)
297+
$(git rev-parse e4) (tag: e4, dist=4)
298+
$(git rev-parse e5) (tag: e5, dist=4)
299+
$(git rev-parse e6) (tag: e6, dist=3)
300+
$(git rev-parse e7) (tag: e7, dist=2)
301+
$(git rev-parse e8) (tag: e8, dist=1)
302+
EOF
303+
304+
# expect results to be ordered by distance (descending),
305+
# commit hash (ascending)
306+
sort -k4,4r -k1,1 expect.unsorted >expect &&
307+
git rev-list --bisect-all --first-parent E ^F >actual &&
308+
test_cmp expect actual
309+
'
310+
266311
test_done

0 commit comments

Comments
 (0)