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>

Matthieu Moy committed Jun 29, 2015 at 17:40 UTC 06e6a745064c4f2f827177f6d92f4b9adb018200
3 files changed +132 -3
Documentation/git-bisect.txt
+35 -2
@@ -16,7 +16,8 @@ DESCRIPTION
16 The command takes various subcommands, and different options depending
17 on the subcommand:
18
19 - git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
19 + git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
20 + [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
21 git bisect (bad|new) [<rev>]
22 git bisect (good|old) [<rev>...]
23 git bisect terms [--term-good | --term-bad]
@@ -41,7 +42,7 @@ In fact, `git bisect` can be used to find the commit that changed
42 *any* property of your project; e.g., the commit that fixed a bug, or
43 the commit that caused a benchmark's performance to improve. To
44 support this more general usage, the terms "old" and "new" can be used
44 -in place of "good" and "bad". See
45 +in place of "good" and "bad", or you can choose your own terms. See
46 section "Alternate terms" below for more information.
47
48 Basic bisect commands: start, bad, good
@@ -167,6 +168,31 @@ git bisect terms
168 You can get just the old (respectively new) term with `git bisect term
169 --term-old` or `git bisect term --term-good`.
170
171 +If you would like to use your own terms instead of "bad"/"good" or
172 +"new"/"old", you can choose any names you like (except existing bisect
173 +subcommands like `reset`, `start`, ...) by starting the
174 +bisection using
175 +
176 +------------------------------------------------
177 +git bisect start --term-old <term-old> --term-new <term-new>
178 +------------------------------------------------
179 +
180 +For example, if you are looking for a commit that introduced a
181 +performance regression, you might use
182 +
183 +------------------------------------------------
184 +git bisect start --term-old fast --term-new slow
185 +------------------------------------------------
186 +
187 +Or if you are looking for the commit that fixed a bug, you might use
188 +
189 +------------------------------------------------
190 +git bisect start --term-new fixed --term-old broken
191 +------------------------------------------------
192 +
193 +Then, use `git bisect <term-old>` and `git bisect <term-new>` instead
194 +of `git bisect good` and `git bisect bad` to mark commits.
195 +
196 Bisect visualize
197 ~~~~~~~~~~~~~~~~
198
@@ -450,6 +476,13 @@ $ git bisect start
476 $ git bisect new HEAD # current commit is marked as new
477 $ git bisect old HEAD~10 # the tenth commit from now is marked as old
478 ------------
479 ++
480 +or:
481 +------------
482 +$ git bisect start --term-old broken --term-new fixed
483 +$ git bisect fixed
484 +$ git bisect broken HEAD~10
485 +------------
486
487 Getting help
488 ~~~~~~~~~~~~
git-bisect.sh
+20 -1
@@ -3,7 +3,8 @@
3 USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|replay|log|run]'
4 LONG_USAGE='git bisect help
5 print this long help message.
6 -git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
6 +git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
7 + [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
8 reset bisect state and start bisection.
9 git bisect (bad|new) [<rev>]
10 mark <rev> a known-bad revision/
@@ -99,6 +100,24 @@ bisect_start() {
100 --no-checkout)
101 mode=--no-checkout
102 shift ;;
103 + --term-good|--term-old)
104 + shift
105 + must_write_terms=1
106 + TERM_GOOD=$1
107 + shift ;;
108 + --term-good=*|--term-old=*)
109 + must_write_terms=1
110 + TERM_GOOD=${1#*=}
111 + shift ;;
112 + --term-bad|--term-new)
113 + shift
114 + must_write_terms=1
115 + TERM_BAD=$1
116 + shift ;;
117 + --term-bad=*|--term-new=*)
118 + must_write_terms=1
119 + TERM_BAD=${1#*=}
120 + shift ;;
121 --*)
122 die "$(eval_gettext "unrecognised option: '\$arg'")" ;;
123 *)
t/t6030-bisect-porcelain.sh
+77
@@ -817,4 +817,81 @@ test_expect_success 'bisect terms shows good/bad after start' '
817 test_cmp expected actual
818 '
819
820 +test_expect_success 'bisect start with one term1 and term2' '
821 + git bisect reset &&
822 + git bisect start --term-old term2 --term-new term1 &&
823 + git bisect term2 $HASH1 &&
824 + git bisect term1 $HASH4 &&
825 + git bisect term1 &&
826 + git bisect term1 >bisect_result &&
827 + grep "$HASH2 is the first term1 commit" bisect_result &&
828 + git bisect log >log_to_replay.txt &&
829 + git bisect reset
830 +'
831 +
832 +test_expect_success 'bisect replay with term1 and term2' '
833 + git bisect replay log_to_replay.txt >bisect_result &&
834 + grep "$HASH2 is the first term1 commit" bisect_result &&
835 + git bisect reset
836 +'
837 +
838 +test_expect_success 'bisect start term1 term2' '
839 + git bisect reset &&
840 + git bisect start --term-new term1 --term-old term2 $HASH4 $HASH1 &&
841 + git bisect term1 &&
842 + git bisect term1 >bisect_result &&
843 + grep "$HASH2 is the first term1 commit" bisect_result &&
844 + git bisect log >log_to_replay.txt &&
845 + git bisect reset
846 +'
847 +
848 +test_expect_success 'bisect cannot mix terms' '
849 + git bisect reset &&
850 + git bisect start --term-good term1 --term-bad term2 $HASH4 $HASH1 &&
851 + test_must_fail git bisect a &&
852 + test_must_fail git bisect b &&
853 + test_must_fail git bisect bad &&
854 + test_must_fail git bisect good &&
855 + test_must_fail git bisect new &&
856 + test_must_fail git bisect old
857 +'
858 +
859 +test_expect_success 'bisect terms rejects invalid terms' '
860 + git bisect reset &&
861 + test_must_fail git bisect start --term-good invalid..term &&
862 + test_must_fail git bisect terms --term-bad invalid..term &&
863 + test_must_fail git bisect terms --term-good bad &&
864 + test_must_fail git bisect terms --term-good old &&
865 + test_must_fail git bisect terms --term-good skip &&
866 + test_must_fail git bisect terms --term-good reset &&
867 + test_path_is_missing .git/BISECT_TERMS
868 +'
869 +
870 +test_expect_success 'bisect start --term-* does store terms' '
871 + git bisect reset &&
872 + git bisect start --term-bad=one --term-good=two &&
873 + git bisect terms >actual &&
874 + cat <<-EOF >expected &&
875 + Your current terms are two for the old state
876 + and one for the new state.
877 + EOF
878 + test_cmp expected actual &&
879 + git bisect terms --term-bad >actual &&
880 + echo one >expected &&
881 + test_cmp expected actual &&
882 + git bisect terms --term-good >actual &&
883 + echo two >expected &&
884 + test_cmp expected actual
885 +'
886 +
887 +test_expect_success 'bisect start takes options and revs in any order' '
888 + git bisect reset &&
889 + git bisect start --term-good one $HASH4 \
890 + --term-good two --term-bad bad-term \
891 + $HASH1 --term-good three -- &&
892 + (git bisect terms --term-bad && git bisect terms --term-good) >actual &&
893 + printf "%s\n%s\n" bad-term three >expected &&
894 + test_cmp expected actual
895 +'
896 +
897 test_done