bisect: simplify the addition of new bisect terms

We create a file BISECT_TERMS in the repository .git to be read during a bisection. There's no user-interface yet, but "git bisect" works if terms other than old/new or bad/good are set in .git/BISECT_TERMS. The fonctions to be changed if we add new terms are quite few. In git-bisect.sh: check_and_set_terms bisect_voc Co-authored-by: Louis Stuber <stuberl@ensimag.grenoble-inp.fr> Tweaked-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Antoine Delaite <antoine.delaite@ensimag.grenoble-inp.fr> Signed-off-by: Louis Stuber <stuberl@ensimag.grenoble-inp.fr> Signed-off-by: Valentin Duperray <Valentin.Duperray@ensimag.imag.fr> Signed-off-by: Franck Jonas <Franck.Jonas@ensimag.imag.fr> Signed-off-by: Lucien Kong <Lucien.Kong@ensimag.imag.fr> Signed-off-by: Thomas Nguy <Thomas.Nguy@ensimag.imag.fr> Signed-off-by: Huynh Khoi Nguyen Nguyen <Huynh-Khoi-Nguyen.Nguyen@ensimag.imag.fr> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Antoine Delaite committed Jun 29, 2015 at 17:40 UTC cb46d630baf780412f8ca0592531880b592f0922
4 files changed +120 -12
bisect.c
+31 -2
@@ -904,6 +904,36 @@ static void show_diff_tree(const char *prefix, struct commit *commit)
904 log_tree_commit(&opt, commit);
905 }
906
907 +/*
908 + * The terms used for this bisect session are stored in BISECT_TERMS.
909 + * We read them and store them to adapt the messages accordingly.
910 + * Default is bad/good.
911 + */
912 +void read_bisect_terms(const char **read_bad, const char **read_good)
913 +{
914 + struct strbuf str = STRBUF_INIT;
915 + const char *filename = git_path("BISECT_TERMS");
916 + FILE *fp = fopen(filename, "r");
917 +
918 + if (!fp) {
919 + if (errno == ENOENT) {
920 + *read_bad = "bad";
921 + *read_good = "good";
922 + return;
923 + } else {
924 + die("could not read file '%s': %s", filename,
925 + strerror(errno));
926 + }
927 + } else {
928 + strbuf_getline(&str, fp, '\n');
929 + *read_bad = strbuf_detach(&str, NULL);
930 + strbuf_getline(&str, fp, '\n');
931 + *read_good = strbuf_detach(&str, NULL);
932 + }
933 + strbuf_release(&str);
934 + fclose(fp);
935 +}
936 +
937 /*
938 * We use the convention that exiting with an exit code 10 means that
939 * the bisection process finished successfully.
@@ -920,8 +950,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
950 const unsigned char *bisect_rev;
951 char bisect_rev_hex[GIT_SHA1_HEXSZ + 1];
952
923 - term_bad = "bad";
924 - term_good = "good";
953 + read_bisect_terms(&term_bad, &term_good);
954 if (read_bisect_refs())
955 die("reading bisect refs failed");
956
bisect.h
+2
@@ -26,4 +26,6 @@ extern int bisect_next_all(const char *prefix, int no_checkout);
26
27 extern int estimate_bisect_steps(int all);
28
29 +extern void read_bisect_terms(const char **bad, const char **good);
30 +
31 #endif
git-bisect.sh
+71 -8
@@ -77,6 +77,7 @@ bisect_start() {
77 orig_args=$(git rev-parse --sq-quote "$@")
78 bad_seen=0
79 eval=''
80 + must_write_terms=0
81 if test "z$(git rev-parse --is-bare-repository)" != zfalse
82 then
83 mode=--no-checkout
@@ -101,6 +102,14 @@ bisect_start() {
102 die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
103 break
104 }
105 +
106 + # The user ran "git bisect start <sha1>
107 + # <sha1>", hence did not explicitly specify
108 + # the terms, but we are already starting to
109 + # set references named with the default terms,
110 + # and won't be able to change afterwards.
111 + must_write_terms=1
112 +
113 case $bad_seen in
114 0) state=$TERM_BAD ; bad_seen=1 ;;
115 *) state=$TERM_GOOD ;;
@@ -172,6 +181,10 @@ bisect_start() {
181 } &&
182 git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
183 eval "$eval true" &&
184 + if test $must_write_terms -eq 1
185 + then
186 + write_terms "$TERM_BAD" "$TERM_GOOD"
187 + fi &&
188 echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
189 #
190 # Check if we can proceed to the next bisect state.
@@ -232,6 +245,7 @@ bisect_skip() {
245 bisect_state() {
246 bisect_autostart
247 state=$1
248 + check_and_set_terms $state
249 case "$#,$state" in
250 0,*)
251 die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;
@@ -291,15 +305,17 @@ bisect_next_check() {
305 : bisect without $TERM_GOOD...
306 ;;
307 *)
294 -
308 + bad_syn=$(bisect_voc bad)
309 + good_syn=$(bisect_voc good)
310 if test -s "$GIT_DIR/BISECT_START"
311 then
297 - gettextln "You need to give me at least one good and one bad revision.
298 -(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
312 +
313 + eval_gettextln "You need to give me at least one \$bad_syn and one \$good_syn revision.
314 +(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
315 else
300 - gettextln "You need to start by \"git bisect start\".
301 -You then need to give me at least one good and one bad revision.
302 -(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
316 + eval_gettextln "You need to start by \"git bisect start\".
317 +You then need to give me at least one \$good_syn and one \$bad_syn revision.
318 +(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
319 fi
320 exit 1 ;;
321 esac
@@ -402,6 +418,7 @@ bisect_clean_state() {
418 rm -f "$GIT_DIR/BISECT_LOG" &&
419 rm -f "$GIT_DIR/BISECT_NAMES" &&
420 rm -f "$GIT_DIR/BISECT_RUN" &&
421 + rm -f "$GIT_DIR/BISECT_TERMS" &&
422 # Cleanup head-name if it got left by an old version of git-bisect
423 rm -f "$GIT_DIR/head-name" &&
424 git update-ref -d --no-deref BISECT_HEAD &&
@@ -422,11 +439,13 @@ bisect_replay () {
439 rev="$command"
440 command="$bisect"
441 fi
442 + get_terms
443 + check_and_set_terms "$command"
444 case "$command" in
445 start)
446 cmd="bisect_start $rev"
447 eval "$cmd" ;;
429 - $TERM_GOOD|$TERM_BAD|skip)
448 + "$TERM_GOOD"|"$TERM_BAD"|skip)
449 bisect_write "$command" "$rev" ;;
450 *)
451 die "$(gettext "?? what are you talking about?")" ;;
@@ -499,18 +518,62 @@ bisect_log () {
518 cat "$GIT_DIR/BISECT_LOG"
519 }
520
521 +get_terms () {
522 + if test -s "$GIT_DIR/BISECT_TERMS"
523 + then
524 + {
525 + read TERM_BAD
526 + read TERM_GOOD
527 + } <"$GIT_DIR/BISECT_TERMS"
528 + fi
529 +}
530 +
531 +write_terms () {
532 + TERM_BAD=$1
533 + TERM_GOOD=$2
534 + printf '%s\n%s\n' "$TERM_BAD" "$TERM_GOOD" >"$GIT_DIR/BISECT_TERMS"
535 +}
536 +
537 +check_and_set_terms () {
538 + cmd="$1"
539 + case "$cmd" in
540 + skip|start|terms) ;;
541 + *)
542 + if test -s "$GIT_DIR/BISECT_TERMS" && test "$cmd" != "$TERM_BAD" && test "$cmd" != "$TERM_GOOD"
543 + then
544 + die "$(eval_gettext "Invalid command: you're currently in a \$TERM_BAD/\$TERM_GOOD bisect.")"
545 + fi
546 + case "$cmd" in
547 + bad|good)
548 + if ! test -s "$GIT_DIR/BISECT_TERMS"
549 + then
550 + write_terms bad good
551 + fi
552 + ;;
553 + esac ;;
554 + esac
555 +}
556 +
557 +bisect_voc () {
558 + case "$1" in
559 + bad) echo "bad" ;;
560 + good) echo "good" ;;
561 + esac
562 +}
563 +
564 case "$#" in
565 0)
566 usage ;;
567 *)
568 cmd="$1"
569 + get_terms
570 shift
571 case "$cmd" in
572 help)
573 git bisect -h ;;
574 start)
575 bisect_start "$@" ;;
513 - bad|good)
576 + bad|good|"$TERM_BAD"|"$TERM_GOOD")
577 bisect_state "$cmd" "$@" ;;
578 skip)
579 bisect_skip "$@" ;;
revision.c
+16 -2
@@ -18,9 +18,13 @@
18 #include "commit-slab.h"
19 #include "dir.h"
20 #include "cache-tree.h"
21 +#include "bisect.h"
22
23 volatile show_early_output_fn_t show_early_output;
24
25 +static const char *term_bad;
26 +static const char *term_good;
27 +
28 char *path_name(const struct name_path *path, const char *name)
29 {
30 const struct name_path *p;
@@ -2076,14 +2080,23 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
2080 ctx->argc -= n;
2081 }
2082
2083 +static int for_each_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data, const char *term) {
2084 + struct strbuf bisect_refs = STRBUF_INIT;
2085 + int status;
2086 + strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
2087 + status = for_each_ref_in_submodule(submodule, bisect_refs.buf, fn, cb_data);
2088 + strbuf_release(&bisect_refs);
2089 + return status;
2090 +}
2091 +
2092 static int for_each_bad_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
2093 {
2081 - return for_each_ref_in_submodule(submodule, "refs/bisect/bad", fn, cb_data);
2094 + return for_each_bisect_ref(submodule, fn, cb_data, term_bad);
2095 }
2096
2097 static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
2098 {
2086 - return for_each_ref_in_submodule(submodule, "refs/bisect/good", fn, cb_data);
2099 + return for_each_bisect_ref(submodule, fn, cb_data, term_good);
2100 }
2101
2102 static int handle_revision_pseudo_opt(const char *submodule,
@@ -2112,6 +2125,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
2125 handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
2126 clear_ref_exclusion(&revs->ref_excludes);
2127 } else if (!strcmp(arg, "--bisect")) {
2128 + read_bisect_terms(&term_bad, &term_good);
2129 handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
2130 handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
2131 revs->bisect = 1;