Skip to content

Commit e8861ff

Browse files
alipman88gitster
authored andcommitted
bisect: introduce first-parent flag
Upon seeing a merge commit when bisecting, this option may be used to follow only the first parent. In detecting regressions introduced through the merging of a branch, the merge commit will be identified as introduction of the bug and its ancestors will be ignored. This option is particularly useful in avoiding false positives when a merged branch contained broken or non-buildable commits, but the merge itself was OK. Signed-off-by: Aaron Lipman <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent be5fe20 commit e8861ff

File tree

4 files changed

+42
-3
lines changed

4 files changed

+42
-3
lines changed

Documentation/git-bisect.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The command takes various subcommands, and different options depending
1717
on the subcommand:
1818

1919
git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
20-
[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
20+
[--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
2121
git bisect (bad|new|<term-new>) [<rev>]
2222
git bisect (good|old|<term-old>) [<rev>...]
2323
git bisect terms [--term-good | --term-bad]
@@ -365,6 +365,17 @@ does not require a checked out tree.
365365
+
366366
If the repository is bare, `--no-checkout` is assumed.
367367

368+
--first-parent::
369+
+
370+
Follow only the first parent commit upon seeing a merge commit.
371+
+
372+
In detecting regressions introduced through the merging of a branch, the merge
373+
commit will be identified as introduction of the bug and its ancestors will be
374+
ignored.
375+
+
376+
This option is particularly useful in avoiding false positives when a merged
377+
branch contained broken or non-buildable commits, but the merge itself was OK.
378+
368379
EXAMPLES
369380
--------
370381

bisect.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "commit-slab.h"
1616
#include "commit-reach.h"
1717
#include "object-store.h"
18+
#include "dir.h"
1819

1920
static struct oid_array good_revs;
2021
static struct oid_array skipped_revs;
@@ -460,6 +461,7 @@ static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
460461
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
461462
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
462463
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
464+
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
463465
static GIT_PATH_FUNC(git_path_head_name, "head-name")
464466

465467
static void read_bisect_paths(struct argv_array *array)
@@ -998,7 +1000,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
9981000
struct object_id *bisect_rev;
9991001
char *steps_msg;
10001002
int no_checkout = ref_exists("BISECT_HEAD");
1001-
int first_parent_only = 0; /* TODO: pass --first-parent flag from git bisect start */
1003+
int first_parent_only = file_exists(git_path_bisect_first_parent());
10021004

10031005
read_bisect_terms(&term_bad, &term_good);
10041006
if (read_bisect_refs())
@@ -1142,6 +1144,7 @@ int bisect_clean_state(void)
11421144
unlink_or_warn(git_path_bisect_names());
11431145
unlink_or_warn(git_path_bisect_run());
11441146
unlink_or_warn(git_path_bisect_terms());
1147+
unlink_or_warn(git_path_bisect_first_parent());
11451148
/* Cleanup head-name if it got left by an old version of git-bisect */
11461149
unlink_or_warn(git_path_head_name());
11471150
/*

builtin/bisect--helper.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ static GIT_PATH_FUNC(git_path_bisect_head, "BISECT_HEAD")
1717
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
1818
static GIT_PATH_FUNC(git_path_head_name, "head-name")
1919
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
20+
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
2021

2122
static const char * const git_bisect_helper_usage[] = {
2223
N_("git bisect--helper --next-all"),
@@ -28,7 +29,7 @@ static const char * const git_bisect_helper_usage[] = {
2829
N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
2930
N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
3031
N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
31-
"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]"),
32+
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
3233
NULL
3334
};
3435

@@ -424,6 +425,7 @@ static int bisect_append_log_quoted(const char **argv)
424425
static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
425426
{
426427
int no_checkout = 0;
428+
int first_parent_only = 0;
427429
int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
428430
int flags, pathspec_pos, res = 0;
429431
struct string_list revs = STRING_LIST_INIT_DUP;
@@ -453,6 +455,8 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
453455
break;
454456
} else if (!strcmp(arg, "--no-checkout")) {
455457
no_checkout = 1;
458+
} else if (!strcmp(arg, "--first-parent")) {
459+
first_parent_only = 1;
456460
} else if (!strcmp(arg, "--term-good") ||
457461
!strcmp(arg, "--term-old")) {
458462
i++;
@@ -577,6 +581,9 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
577581
*/
578582
write_file(git_path_bisect_start(), "%s\n", start_head.buf);
579583

584+
if (first_parent_only)
585+
write_file(git_path_bisect_first_parent(), "\n");
586+
580587
if (no_checkout) {
581588
if (get_oid(start_head.buf, &oid) < 0) {
582589
res = error(_("invalid ref: '%s'"), start_head.buf);

t/t6030-bisect-porcelain.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,24 @@ test_expect_success 'many merge bases creation' '
448448
grep "$SIDE_HASH5" merge_bases.txt
449449
'
450450

451+
# We want to automatically find the merge that
452+
# added "line" into hello.
453+
test_expect_success '"git bisect run --first-parent" simple case' '
454+
git rev-list --first-parent $B_HASH ^$HASH4 >first_parent_chain.txt &&
455+
write_script test_script.sh <<-\EOF &&
456+
grep $(git rev-parse HEAD) first_parent_chain.txt || exit -1
457+
! grep line hello >/dev/null
458+
EOF
459+
git bisect start --first-parent &&
460+
test_path_is_file ".git/BISECT_FIRST_PARENT" &&
461+
git bisect good $HASH4 &&
462+
git bisect bad $B_HASH &&
463+
git bisect run ./test_script.sh >my_bisect_log.txt &&
464+
grep "$B_HASH is the first bad commit" my_bisect_log.txt &&
465+
git bisect reset &&
466+
test_path_is_missing .git/BISECT_FIRST_PARENT
467+
'
468+
451469
test_expect_success 'good merge bases when good and bad are siblings' '
452470
git bisect start "$B_HASH" "$A_HASH" > my_bisect_log.txt &&
453471
test_i18ngrep "merge base must be tested" my_bisect_log.txt &&

0 commit comments

Comments
 (0)