bisect: allow setting any user-specified in 'git bisect start'

This allows a natural user-interface when looking for any change in the
code, not just regression. For example:

git bisect start --term-old fast --term-new slow
git bisect fast
git bisect slow
...

There were several proposed user-interfaces for this feature. This patch
implements it as options to 'git bisect start' for the following reasons:

* By construction, the terms will be valid for one and only one
  bisection.

* Unlike positional arguments, using named options avoid having to
  remember an order.

* We can combine user-defined terms and passing old/new commits as
  argument to "git bisect start".

* The implementation is relatively simple.

See previous discussions:

  http://mid.gmane.org/1435337896-20709-3-git-send-email-Matthieu.Moy@imag.fr

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Matthieu Moy 2015-06-29 17:40:35 +02:00 committed by Junio C Hamano
parent 21b55e3369
commit 06e6a74506
3 changed files with 132 additions and 3 deletions

View File

@ -16,7 +16,8 @@ DESCRIPTION
The command takes various subcommands, and different options depending
on the subcommand:
git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect (bad|new) [<rev>]
git bisect (good|old) [<rev>...]
git bisect terms [--term-good | --term-bad]
@ -41,7 +42,7 @@ In fact, `git bisect` can be used to find the commit that changed
*any* property of your project; e.g., the commit that fixed a bug, or
the commit that caused a benchmark's performance to improve. To
support this more general usage, the terms "old" and "new" can be used
in place of "good" and "bad". See
in place of "good" and "bad", or you can choose your own terms. See
section "Alternate terms" below for more information.
Basic bisect commands: start, bad, good
@ -167,6 +168,31 @@ git bisect terms
You can get just the old (respectively new) term with `git bisect term
--term-old` or `git bisect term --term-good`.
If you would like to use your own terms instead of "bad"/"good" or
"new"/"old", you can choose any names you like (except existing bisect
subcommands like `reset`, `start`, ...) by starting the
bisection using
------------------------------------------------
git bisect start --term-old <term-old> --term-new <term-new>
------------------------------------------------
For example, if you are looking for a commit that introduced a
performance regression, you might use
------------------------------------------------
git bisect start --term-old fast --term-new slow
------------------------------------------------
Or if you are looking for the commit that fixed a bug, you might use
------------------------------------------------
git bisect start --term-new fixed --term-old broken
------------------------------------------------
Then, use `git bisect <term-old>` and `git bisect <term-new>` instead
of `git bisect good` and `git bisect bad` to mark commits.
Bisect visualize
~~~~~~~~~~~~~~~~
@ -450,6 +476,13 @@ $ git bisect start
$ git bisect new HEAD # current commit is marked as new
$ git bisect old HEAD~10 # the tenth commit from now is marked as old
------------
+
or:
------------
$ git bisect start --term-old broken --term-new fixed
$ git bisect fixed
$ git bisect broken HEAD~10
------------
Getting help
~~~~~~~~~~~~

View File

@ -3,7 +3,8 @@
USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|replay|log|run]'
LONG_USAGE='git bisect help
print this long help message.
git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
[--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
reset bisect state and start bisection.
git bisect (bad|new) [<rev>]
mark <rev> a known-bad revision/
@ -99,6 +100,24 @@ bisect_start() {
--no-checkout)
mode=--no-checkout
shift ;;
--term-good|--term-old)
shift
must_write_terms=1
TERM_GOOD=$1
shift ;;
--term-good=*|--term-old=*)
must_write_terms=1
TERM_GOOD=${1#*=}
shift ;;
--term-bad|--term-new)
shift
must_write_terms=1
TERM_BAD=$1
shift ;;
--term-bad=*|--term-new=*)
must_write_terms=1
TERM_BAD=${1#*=}
shift ;;
--*)
die "$(eval_gettext "unrecognised option: '\$arg'")" ;;
*)

View File

@ -817,4 +817,81 @@ test_expect_success 'bisect terms shows good/bad after start' '
test_cmp expected actual
'
test_expect_success 'bisect start with one term1 and term2' '
git bisect reset &&
git bisect start --term-old term2 --term-new term1 &&
git bisect term2 $HASH1 &&
git bisect term1 $HASH4 &&
git bisect term1 &&
git bisect term1 >bisect_result &&
grep "$HASH2 is the first term1 commit" bisect_result &&
git bisect log >log_to_replay.txt &&
git bisect reset
'
test_expect_success 'bisect replay with term1 and term2' '
git bisect replay log_to_replay.txt >bisect_result &&
grep "$HASH2 is the first term1 commit" bisect_result &&
git bisect reset
'
test_expect_success 'bisect start term1 term2' '
git bisect reset &&
git bisect start --term-new term1 --term-old term2 $HASH4 $HASH1 &&
git bisect term1 &&
git bisect term1 >bisect_result &&
grep "$HASH2 is the first term1 commit" bisect_result &&
git bisect log >log_to_replay.txt &&
git bisect reset
'
test_expect_success 'bisect cannot mix terms' '
git bisect reset &&
git bisect start --term-good term1 --term-bad term2 $HASH4 $HASH1 &&
test_must_fail git bisect a &&
test_must_fail git bisect b &&
test_must_fail git bisect bad &&
test_must_fail git bisect good &&
test_must_fail git bisect new &&
test_must_fail git bisect old
'
test_expect_success 'bisect terms rejects invalid terms' '
git bisect reset &&
test_must_fail git bisect start --term-good invalid..term &&
test_must_fail git bisect terms --term-bad invalid..term &&
test_must_fail git bisect terms --term-good bad &&
test_must_fail git bisect terms --term-good old &&
test_must_fail git bisect terms --term-good skip &&
test_must_fail git bisect terms --term-good reset &&
test_path_is_missing .git/BISECT_TERMS
'
test_expect_success 'bisect start --term-* does store terms' '
git bisect reset &&
git bisect start --term-bad=one --term-good=two &&
git bisect terms >actual &&
cat <<-EOF >expected &&
Your current terms are two for the old state
and one for the new state.
EOF
test_cmp expected actual &&
git bisect terms --term-bad >actual &&
echo one >expected &&
test_cmp expected actual &&
git bisect terms --term-good >actual &&
echo two >expected &&
test_cmp expected actual
'
test_expect_success 'bisect start takes options and revs in any order' '
git bisect reset &&
git bisect start --term-good one $HASH4 \
--term-good two --term-bad bad-term \
$HASH1 --term-good three -- &&
(git bisect terms --term-bad && git bisect terms --term-good) >actual &&
printf "%s\n%s\n" bad-term three >expected &&
test_cmp expected actual
'
test_done