24
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
25
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
26
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
27
+static GIT_PATH_FUNC(git_path_bisect_reset_when_found, "BISECT_RESET_WHEN_FOUND")
28
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
29
30
#define BUILTIN_GIT_BISECT_START_USAGE \
31
N_("git bisect start [--term-(bad|new)=<term-new> --term-(good|old)=<term-old>]\n" \
31
- " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]")
32
+ " [--no-checkout] [--first-parent] [--reset-when-found[=<where>]] [<bad> [<good>...]] [--] [<pathspec>...]")
33
#define BUILTIN_GIT_BISECT_BAD_USAGE \
34
N_("git bisect (bad|new|<term-new>) [<rev>]")
35
#define BUILTIN_GIT_BISECT_GOOD_USAGE \
49
#define BUILTIN_GIT_BISECT_LOG_USAGE \
50
"git bisect log"
51
#define BUILTIN_GIT_BISECT_RUN_USAGE \
51
- N_("git bisect run <cmd> [<arg>...]")
52
+ N_("git bisect run [--reset-when-found[=<where>]] <cmd> [<arg>...]")
53
#define BUILTIN_GIT_BISECT_HELP_USAGE \
54
"git bisect help"
55
69
NULL
70
};
71
72
+enum reset_when_found_mode {
73
+ RESET_WHEN_FOUND_NONE,
74
+ RESET_WHEN_FOUND_TO_ORIGINAL,
75
+ RESET_WHEN_FOUND_TO_FOUND,
76
+};
77
+
78
struct add_bisect_ref_data {
79
struct rev_info *revs;
80
unsigned int object_flags;
279
return bisect_clean_state();
280
}
281
282
+static int parse_reset_when_found(const char *value,
283
+ enum reset_when_found_mode *mode)
284
+{
285
+ if (!strcmp(value, "original"))
286
+ *mode = RESET_WHEN_FOUND_TO_ORIGINAL;
287
+ else if (!strcmp(value, "found"))
288
+ *mode = RESET_WHEN_FOUND_TO_FOUND;
289
+ else
290
+ return error(_("invalid value for '--reset-when-found': '%s'"),
291
+ value);
292
+
293
+ return 0;
294
+}
295
+
296
+static const char *reset_when_found_mode_name(enum reset_when_found_mode mode)
297
+{
298
+ switch (mode) {
299
+ case RESET_WHEN_FOUND_TO_ORIGINAL:
300
+ return "original";
301
+ case RESET_WHEN_FOUND_TO_FOUND:
302
+ return "found";
303
+ case RESET_WHEN_FOUND_NONE:
304
+ BUG("no name for unset reset-when-found mode");
305
+ }
306
+ BUG("unknown reset-when-found mode %d", mode);
307
+}
308
+
309
+static int bisect_reset_when_found(struct bisect_terms *terms)
310
+{
311
+ struct strbuf value = STRBUF_INIT;
312
+ enum reset_when_found_mode mode;
313
+ char *commit = NULL;
314
+ int res;
315
+
316
+ if (strbuf_read_file(&value, git_path_bisect_reset_when_found(), 0) < 0) {
317
+ res = error_errno(_("could not read '%s'"),
318
+ git_path_bisect_reset_when_found());
319
+ goto cleanup;
320
+ }
321
+ strbuf_trim(&value);
322
+ if (parse_reset_when_found(value.buf, &mode)) {
323
+ res = -1;
324
+ goto cleanup;
325
+ }
326
+
327
+ if (mode == RESET_WHEN_FOUND_TO_FOUND)
328
+ commit = xstrfmt("refs/bisect/%s", terms->term_bad);
329
+ res = bisect_reset(commit, 1);
330
+
331
+cleanup:
332
+ free(commit);
333
+ strbuf_release(&value);
334
+ return res;
335
+}
336
+
337
static void log_commit(FILE *fp,
338
const char *fmt, const char *state,
339
struct commit *commit)
739
return res;
740
}
741
680
-static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
742
+static enum bisect_error bisect_next(struct bisect_terms *terms,
743
+ const char *prefix, bool defer_reset)
744
{
745
enum bisect_error res;
746
755
756
if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
757
res = bisect_successful(terms);
758
+ if (!res && !defer_reset &&
759
+ !is_empty_or_missing_file(git_path_bisect_reset_when_found()))
760
+ res = bisect_reset_when_found(terms);
761
return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
762
} else if (res == BISECT_ONLY_SKIPPED_LEFT) {
763
res = bisect_skipped_commits(terms);
766
return res;
767
}
768
703
-static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
769
+static enum bisect_error bisect_auto_next(struct bisect_terms *terms,
770
+ const char *prefix, bool defer_reset)
771
{
772
if (bisect_next_check(terms, NULL)) {
773
bisect_print_status(terms);
774
return BISECT_OK;
775
}
776
710
- return bisect_next(terms, prefix);
777
+ return bisect_next(terms, prefix, defer_reset);
778
}
779
780
static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
782
{
783
int no_checkout = 0;
784
int first_parent_only = 0;
785
+ enum reset_when_found_mode reset_when_found = RESET_WHEN_FOUND_NONE;
786
int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
787
int flags, pathspec_pos;
788
enum bisect_error res = BISECT_OK;
815
no_checkout = 1;
816
} else if (!strcmp(arg, "--first-parent")) {
817
first_parent_only = 1;
818
+ } else if (!strcmp(arg, "--reset-when-found")) {
819
+ reset_when_found = RESET_WHEN_FOUND_TO_ORIGINAL;
820
+ } else if (skip_prefix(arg, "--reset-when-found=", &arg)) {
821
+ if (parse_reset_when_found(arg, &reset_when_found)) {
822
+ res = BISECT_FAILED;
823
+ goto finish;
824
+ }
825
} else if (!strcmp(arg, "--term-good") ||
826
!strcmp(arg, "--term-old")) {
827
i++;
859
break;
860
}
861
}
862
+ if (reset_when_found != RESET_WHEN_FOUND_NONE && no_checkout) {
863
+ res = error(_("'--reset-when-found' cannot be used with '--no-checkout'"));
864
+ goto finish;
865
+ }
866
pathspec_pos = i;
867
868
/*
940
if (first_parent_only)
941
write_file(git_path_bisect_first_parent(), "\n");
942
943
+ if (reset_when_found != RESET_WHEN_FOUND_NONE)
944
+ write_file(git_path_bisect_reset_when_found(), "%s\n",
945
+ reset_when_found_mode_name(reset_when_found));
946
+
947
if (no_checkout) {
948
if (repo_get_oid(the_repository, start_head.buf, &oid) < 0) {
949
res = error(_("invalid ref: '%s'"), start_head.buf);
985
if (res)
986
return res;
987
905
- res = bisect_auto_next(terms, NULL);
988
+ res = bisect_auto_next(terms, NULL, false);
989
if (!is_bisect_success(res))
990
bisect_clean_state();
991
return res;
1024
}
1025
1026
static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
944
- const char **argv)
1027
+ const char **argv, bool defer_reset)
1028
{
1029
const char *state;
1030
int i, verify_expected = 1;
1101
}
1102
1103
oid_array_clear(&revs);
1021
- return bisect_auto_next(terms, NULL);
1104
+ return bisect_auto_next(terms, NULL, defer_reset);
1105
}
1106
1107
static enum bisect_error bisect_log(void)
1190
if (res)
1191
return BISECT_FAILED;
1192
1110
- return bisect_auto_next(terms, NULL);
1193
+ return bisect_auto_next(terms, NULL, false);
1194
}
1195
1196
static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
1224
strvec_push(&argv_state, argv[i]);
1225
}
1226
}
1144
- res = bisect_state(terms, argv_state.nr, argv_state.v);
1227
+ res = bisect_state(terms, argv_state.nr, argv_state.v, false);
1228
1229
strvec_clear(&argv_state);
1230
return res;
1322
{
1323
int res = BISECT_OK;
1324
struct strbuf command = STRBUF_INIT;
1325
+ enum reset_when_found_mode reset_when_found = RESET_WHEN_FOUND_NONE;
1326
+ const char *reset_when_found_arg;
1327
const char *new_state;
1328
int temporary_stdout_fd, saved_stdout;
1329
int is_first_run = 1;
1331
if (bisect_next_check(terms, NULL))
1332
return BISECT_FAILED;
1333
1334
+ if (argc && !strcmp(argv[0], "--reset-when-found"))
1335
+ reset_when_found = RESET_WHEN_FOUND_TO_ORIGINAL;
1336
+ else if (argc && skip_prefix(argv[0], "--reset-when-found=",
1337
+ &reset_when_found_arg)) {
1338
+ if (parse_reset_when_found(reset_when_found_arg, &reset_when_found))
1339
+ return BISECT_FAILED;
1340
+ }
1341
+
1342
+ if (reset_when_found != RESET_WHEN_FOUND_NONE) {
1343
+ if (refs_ref_exists(get_main_ref_store(the_repository), "BISECT_HEAD"))
1344
+ return error(_("'--reset-when-found' cannot be used with '--no-checkout'"));
1345
+ write_file(git_path_bisect_reset_when_found(), "%s\n",
1346
+ reset_when_found_mode_name(reset_when_found));
1347
+ argc--;
1348
+ argv++;
1349
+ }
1350
+
1351
if (!argc) {
1352
error(_("bisect run failed: no command provided."));
1353
return BISECT_FAILED;
1406
saved_stdout = dup(1);
1407
dup2(temporary_stdout_fd, 1);
1408
1307
- res = bisect_state(terms, 1, &new_state);
1409
+ res = bisect_state(terms, 1, &new_state, true);
1410
1411
fflush(stdout);
1412
dup2(saved_stdout, 1);
1422
res = BISECT_OK;
1423
} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
1424
printf(_("bisect found first '%s' commit\n"), terms->term_bad);
1323
- res = BISECT_OK;
1425
+ if (!is_empty_or_missing_file(git_path_bisect_reset_when_found()) &&
1426
+ bisect_reset_when_found(terms))
1427
+ res = BISECT_FAILED;
1428
+ else
1429
+ res = BISECT_OK;
1430
} else if (res) {
1431
error(_("bisect run failed: 'git bisect %s'"
1432
" exited with error code %d"), new_state, res);
1485
return error(_("'%s' requires 0 arguments"),
1486
"git bisect next");
1487
get_terms(&terms);
1382
- res = bisect_next(&terms, prefix);
1488
+ res = bisect_next(&terms, prefix, false);
1489
free_terms(&terms);
1490
return res;
1491
}
1588
!one_of(argv[0], terms.term_good, terms.term_bad, NULL))
1589
usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
1590
options, argv[0]);
1485
- res = bisect_state(&terms, argc, argv);
1591
+ res = bisect_state(&terms, argc, argv, false);
1592
free_terms(&terms);
1593
} else {
1594
argc--;