2009-03-26 04:55:54 +00:00
|
|
|
#include "builtin.h"
|
|
|
|
#include "cache.h"
|
2023-02-24 00:09:27 +00:00
|
|
|
#include "hex.h"
|
2009-03-26 04:55:54 +00:00
|
|
|
#include "parse-options.h"
|
|
|
|
#include "bisect.h"
|
2017-09-29 06:49:39 +00:00
|
|
|
#include "refs.h"
|
2019-01-02 15:38:31 +00:00
|
|
|
#include "dir.h"
|
2020-07-28 20:23:39 +00:00
|
|
|
#include "strvec.h"
|
2019-01-02 15:38:31 +00:00
|
|
|
#include "run-command.h"
|
2019-01-02 15:38:34 +00:00
|
|
|
#include "prompt.h"
|
2019-01-02 15:38:36 +00:00
|
|
|
#include "quote.h"
|
2020-09-24 12:33:40 +00:00
|
|
|
#include "revision.h"
|
2009-03-26 04:55:54 +00:00
|
|
|
|
2017-09-29 06:49:39 +00:00
|
|
|
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
|
2017-09-29 06:49:40 +00:00
|
|
|
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
|
|
|
|
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
|
2019-01-02 15:38:31 +00:00
|
|
|
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
|
2019-01-02 15:38:32 +00:00
|
|
|
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
|
2019-01-02 15:38:36 +00:00
|
|
|
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
|
2020-08-07 21:58:37 +00:00
|
|
|
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
|
2021-09-13 17:39:03 +00:00
|
|
|
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
|
2017-09-29 06:49:39 +00:00
|
|
|
|
2022-11-10 16:36:43 +00:00
|
|
|
#define BUILTIN_GIT_BISECT_START_USAGE \
|
|
|
|
N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
|
|
|
|
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
|
|
|
|
" [<pathspec>...]")
|
|
|
|
#define BUILTIN_GIT_BISECT_STATE_USAGE \
|
|
|
|
N_("git bisect (good|bad) [<rev>...]")
|
|
|
|
#define BUILTIN_GIT_BISECT_TERMS_USAGE \
|
|
|
|
"git bisect terms [--term-good | --term-bad]"
|
|
|
|
#define BUILTIN_GIT_BISECT_SKIP_USAGE \
|
|
|
|
N_("git bisect skip [(<rev>|<range>)...]")
|
|
|
|
#define BUILTIN_GIT_BISECT_NEXT_USAGE \
|
|
|
|
"git bisect next"
|
|
|
|
#define BUILTIN_GIT_BISECT_RESET_USAGE \
|
|
|
|
N_("git bisect reset [<commit>]")
|
|
|
|
#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
|
|
|
|
"git bisect visualize"
|
|
|
|
#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
|
|
|
|
N_("git bisect replay <logfile>")
|
|
|
|
#define BUILTIN_GIT_BISECT_LOG_USAGE \
|
|
|
|
"git bisect log"
|
|
|
|
#define BUILTIN_GIT_BISECT_RUN_USAGE \
|
|
|
|
N_("git bisect run <cmd>...")
|
|
|
|
|
|
|
|
static const char * const git_bisect_usage[] = {
|
|
|
|
BUILTIN_GIT_BISECT_START_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_STATE_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_TERMS_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_SKIP_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_NEXT_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_RESET_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_REPLAY_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_LOG_USAGE,
|
|
|
|
BUILTIN_GIT_BISECT_RUN_USAGE,
|
2009-03-26 04:55:54 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2020-09-24 12:33:40 +00:00
|
|
|
struct add_bisect_ref_data {
|
|
|
|
struct rev_info *revs;
|
|
|
|
unsigned int object_flags;
|
|
|
|
};
|
|
|
|
|
2019-01-02 15:38:32 +00:00
|
|
|
struct bisect_terms {
|
|
|
|
char *term_good;
|
|
|
|
char *term_bad;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void free_terms(struct bisect_terms *terms)
|
|
|
|
{
|
|
|
|
FREE_AND_NULL(terms->term_good);
|
|
|
|
FREE_AND_NULL(terms->term_bad);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_terms(struct bisect_terms *terms, const char *bad,
|
|
|
|
const char *good)
|
|
|
|
{
|
|
|
|
free((void *)terms->term_good);
|
|
|
|
terms->term_good = xstrdup(good);
|
|
|
|
free((void *)terms->term_bad);
|
|
|
|
terms->term_bad = xstrdup(bad);
|
|
|
|
}
|
|
|
|
|
2020-02-17 08:40:28 +00:00
|
|
|
static const char vocab_bad[] = "bad|new";
|
|
|
|
static const char vocab_good[] = "good|old";
|
2019-01-02 15:38:34 +00:00
|
|
|
|
2020-09-24 12:33:40 +00:00
|
|
|
static int bisect_autostart(struct bisect_terms *terms);
|
|
|
|
|
2017-09-29 06:49:39 +00:00
|
|
|
/*
|
|
|
|
* Check whether the string `term` belongs to the set of strings
|
|
|
|
* included in the variable arguments.
|
|
|
|
*/
|
|
|
|
LAST_ARG_MUST_BE_NULL
|
|
|
|
static int one_of(const char *term, ...)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
va_list matches;
|
|
|
|
const char *match;
|
|
|
|
|
|
|
|
va_start(matches, term);
|
|
|
|
while (!res && (match = va_arg(matches, const char *)))
|
|
|
|
res = !strcmp(term, match);
|
|
|
|
va_end(matches);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-10-15 13:38:32 +00:00
|
|
|
/*
|
|
|
|
* return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
|
|
|
|
* and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
|
|
|
|
* that indicate special success.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int is_bisect_success(enum bisect_error res)
|
|
|
|
{
|
|
|
|
return !res ||
|
|
|
|
res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
|
|
|
|
res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
|
|
|
|
}
|
|
|
|
|
2020-08-28 12:46:07 +00:00
|
|
|
static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
|
|
|
|
{
|
|
|
|
FILE *fp = NULL;
|
|
|
|
int res = 0;
|
|
|
|
|
2020-09-24 12:33:40 +00:00
|
|
|
if (strcmp(mode, "w") && strcmp(mode, "a"))
|
2020-08-28 12:46:07 +00:00
|
|
|
BUG("write-in-file does not support '%s' mode", mode);
|
|
|
|
fp = fopen(path, mode);
|
|
|
|
if (!fp)
|
|
|
|
return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
|
|
|
|
res = vfprintf(fp, format, args);
|
|
|
|
|
|
|
|
if (res < 0) {
|
|
|
|
int saved_errno = errno;
|
|
|
|
fclose(fp);
|
|
|
|
errno = saved_errno;
|
|
|
|
return error_errno(_("could not write to file '%s'"), path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fclose(fp);
|
|
|
|
}
|
|
|
|
|
2021-07-13 08:05:18 +00:00
|
|
|
__attribute__((format (printf, 2, 3)))
|
2020-08-28 12:46:07 +00:00
|
|
|
static int write_to_file(const char *path, const char *format, ...)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
res = write_in_file(path, "w", format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-07-13 08:05:18 +00:00
|
|
|
__attribute__((format (printf, 2, 3)))
|
2020-09-24 12:33:40 +00:00
|
|
|
static int append_to_file(const char *path, const char *format, ...)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
res = write_in_file(path, "a", format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-09-13 17:39:03 +00:00
|
|
|
static int print_file_to_stdout(const char *path)
|
|
|
|
{
|
|
|
|
int fd = open(path, O_RDONLY);
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
return error_errno(_("cannot open file '%s' for reading"), path);
|
|
|
|
if (copy_fd(fd, 1) < 0)
|
|
|
|
ret = error_errno(_("failed to read '%s'"), path);
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-09-29 06:49:39 +00:00
|
|
|
static int check_term_format(const char *term, const char *orig_term)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
char *new_term = xstrfmt("refs/bisect/%s", term);
|
|
|
|
|
|
|
|
res = check_refname_format(new_term, 0);
|
|
|
|
free(new_term);
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
return error(_("'%s' is not a valid term"), term);
|
|
|
|
|
|
|
|
if (one_of(term, "help", "start", "skip", "next", "reset",
|
2017-11-12 09:30:38 +00:00
|
|
|
"visualize", "view", "replay", "log", "run", "terms", NULL))
|
2017-09-29 06:49:39 +00:00
|
|
|
return error(_("can't use the builtin command '%s' as a term"), term);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In theory, nothing prevents swapping completely good and bad,
|
|
|
|
* but this situation could be confusing and hasn't been tested
|
|
|
|
* enough. Forbid it for now.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
|
|
|
|
(strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
|
|
|
|
return error(_("can't change the meaning of the term '%s'"), term);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-29 06:49:39 +00:00
|
|
|
static int write_terms(const char *bad, const char *good)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
if (!strcmp(bad, good))
|
|
|
|
return error(_("please use two different terms"));
|
|
|
|
|
|
|
|
if (check_term_format(bad, "bad") || check_term_format(good, "good"))
|
|
|
|
return -1;
|
|
|
|
|
2020-08-28 12:46:07 +00:00
|
|
|
res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
|
2017-09-29 06:49:39 +00:00
|
|
|
|
2020-08-28 12:46:07 +00:00
|
|
|
return res;
|
2017-09-29 06:49:39 +00:00
|
|
|
}
|
|
|
|
|
2019-01-02 15:38:31 +00:00
|
|
|
static int bisect_reset(const char *commit)
|
|
|
|
{
|
|
|
|
struct strbuf branch = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (!commit) {
|
|
|
|
if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
|
|
|
|
printf(_("We are not bisecting.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strbuf_rtrim(&branch);
|
|
|
|
} else {
|
|
|
|
struct object_id oid;
|
|
|
|
|
|
|
|
if (get_oid_commit(commit, &oid))
|
|
|
|
return error(_("'%s' is not a valid commit"), commit);
|
|
|
|
strbuf_addstr(&branch, commit);
|
|
|
|
}
|
|
|
|
|
2020-07-10 17:19:52 +00:00
|
|
|
if (!ref_exists("BISECT_HEAD")) {
|
2022-10-30 11:51:14 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2019-01-02 15:38:31 +00:00
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
cmd.git_cmd = 1;
|
2023-01-22 01:38:10 +00:00
|
|
|
strvec_pushl(&cmd.args, "checkout", "--ignore-other-worktrees",
|
|
|
|
branch.buf, "--", NULL);
|
2022-10-30 11:51:14 +00:00
|
|
|
if (run_command(&cmd)) {
|
2019-12-09 10:56:47 +00:00
|
|
|
error(_("could not check out original"
|
|
|
|
" HEAD '%s'. Try 'git bisect"
|
|
|
|
" reset <commit>'."), branch.buf);
|
2019-01-02 15:38:31 +00:00
|
|
|
strbuf_release(&branch);
|
2019-12-09 10:56:47 +00:00
|
|
|
return -1;
|
2019-01-02 15:38:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_release(&branch);
|
|
|
|
return bisect_clean_state();
|
|
|
|
}
|
|
|
|
|
2019-01-02 15:38:32 +00:00
|
|
|
static void log_commit(FILE *fp, char *fmt, const char *state,
|
|
|
|
struct commit *commit)
|
|
|
|
{
|
|
|
|
struct pretty_print_context pp = {0};
|
|
|
|
struct strbuf commit_msg = STRBUF_INIT;
|
|
|
|
char *label = xstrfmt(fmt, state);
|
|
|
|
|
|
|
|
format_commit_message(commit, "%s", &commit_msg, &pp);
|
|
|
|
|
|
|
|
fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
|
|
|
|
commit_msg.buf);
|
|
|
|
|
|
|
|
strbuf_release(&commit_msg);
|
|
|
|
free(label);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bisect_write(const char *state, const char *rev,
|
|
|
|
const struct bisect_terms *terms, int nolog)
|
|
|
|
{
|
|
|
|
struct strbuf tag = STRBUF_INIT;
|
|
|
|
struct object_id oid;
|
|
|
|
struct commit *commit;
|
|
|
|
FILE *fp = NULL;
|
2020-02-17 08:40:29 +00:00
|
|
|
int res = 0;
|
2019-01-02 15:38:32 +00:00
|
|
|
|
|
|
|
if (!strcmp(state, terms->term_bad)) {
|
|
|
|
strbuf_addf(&tag, "refs/bisect/%s", state);
|
|
|
|
} else if (one_of(state, terms->term_good, "skip", NULL)) {
|
|
|
|
strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
|
|
|
|
} else {
|
2020-02-17 08:40:29 +00:00
|
|
|
res = error(_("Bad bisect_write argument: %s"), state);
|
2019-01-02 15:38:32 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_oid(rev, &oid)) {
|
2020-02-17 08:40:29 +00:00
|
|
|
res = error(_("couldn't get the oid of the rev '%s'"), rev);
|
2019-01-02 15:38:32 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (update_ref(NULL, tag.buf, &oid, NULL, 0,
|
|
|
|
UPDATE_REFS_MSG_ON_ERR)) {
|
2020-02-17 08:40:29 +00:00
|
|
|
res = -1;
|
2019-01-02 15:38:32 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp = fopen(git_path_bisect_log(), "a");
|
|
|
|
if (!fp) {
|
2020-02-17 08:40:29 +00:00
|
|
|
res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
|
2019-01-02 15:38:32 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
commit = lookup_commit_reference(the_repository, &oid);
|
|
|
|
log_commit(fp, "%s", state, commit);
|
|
|
|
|
|
|
|
if (!nolog)
|
|
|
|
fprintf(fp, "git bisect %s %s\n", state, rev);
|
|
|
|
|
|
|
|
finish:
|
|
|
|
if (fp)
|
|
|
|
fclose(fp);
|
|
|
|
strbuf_release(&tag);
|
2020-02-17 08:40:29 +00:00
|
|
|
return res;
|
2019-01-02 15:38:32 +00:00
|
|
|
}
|
|
|
|
|
2019-01-02 15:38:33 +00:00
|
|
|
static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
|
|
|
|
{
|
|
|
|
int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
|
|
|
|
|
|
|
|
if (one_of(cmd, "skip", "start", "terms", NULL))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (has_term_file && strcmp(cmd, terms->term_bad) &&
|
|
|
|
strcmp(cmd, terms->term_good))
|
|
|
|
return error(_("Invalid command: you're currently in a "
|
|
|
|
"%s/%s bisect"), terms->term_bad,
|
|
|
|
terms->term_good);
|
|
|
|
|
|
|
|
if (!has_term_file) {
|
|
|
|
if (one_of(cmd, "bad", "good", NULL)) {
|
|
|
|
set_terms(terms, "bad", "good");
|
|
|
|
return write_terms(terms->term_bad, terms->term_good);
|
|
|
|
}
|
|
|
|
if (one_of(cmd, "new", "old", NULL)) {
|
|
|
|
set_terms(terms, "new", "old");
|
|
|
|
return write_terms(terms->term_bad, terms->term_good);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-25 17:09:48 +00:00
|
|
|
static int inc_nr(const char *refname UNUSED,
|
|
|
|
const struct object_id *oid UNUSED,
|
|
|
|
int flag UNUSED, void *cb_data)
|
2019-01-02 15:38:34 +00:00
|
|
|
{
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
unsigned int *nr = (unsigned int *)cb_data;
|
|
|
|
(*nr)++;
|
|
|
|
return 0;
|
2019-01-02 15:38:34 +00:00
|
|
|
}
|
|
|
|
|
2019-12-14 08:11:24 +00:00
|
|
|
static const char need_bad_and_good_revision_warning[] =
|
2019-01-02 15:38:34 +00:00
|
|
|
N_("You need to give me at least one %s and %s revision.\n"
|
|
|
|
"You can use \"git bisect %s\" and \"git bisect %s\" for that.");
|
|
|
|
|
2019-12-14 08:11:24 +00:00
|
|
|
static const char need_bisect_start_warning[] =
|
2019-01-02 15:38:34 +00:00
|
|
|
N_("You need to start by \"git bisect start\".\n"
|
|
|
|
"You then need to give me at least one %s and %s revision.\n"
|
|
|
|
"You can use \"git bisect %s\" and \"git bisect %s\" for that.");
|
|
|
|
|
2020-02-17 08:40:31 +00:00
|
|
|
static int decide_next(const struct bisect_terms *terms,
|
|
|
|
const char *current_term, int missing_good,
|
|
|
|
int missing_bad)
|
2019-01-02 15:38:34 +00:00
|
|
|
{
|
|
|
|
if (!missing_good && !missing_bad)
|
2020-02-17 08:40:31 +00:00
|
|
|
return 0;
|
|
|
|
if (!current_term)
|
|
|
|
return -1;
|
2019-01-02 15:38:34 +00:00
|
|
|
|
|
|
|
if (missing_good && !missing_bad &&
|
|
|
|
!strcmp(current_term, terms->term_good)) {
|
|
|
|
char *yesno;
|
|
|
|
/*
|
|
|
|
* have bad (or new) but not good (or old). We could bisect
|
|
|
|
* although this is less optimum.
|
|
|
|
*/
|
|
|
|
warning(_("bisecting only with a %s commit"), terms->term_bad);
|
|
|
|
if (!isatty(0))
|
2020-02-17 08:40:31 +00:00
|
|
|
return 0;
|
2019-01-02 15:38:34 +00:00
|
|
|
/*
|
|
|
|
* TRANSLATORS: Make sure to include [Y] and [n] in your
|
|
|
|
* translation. The program will only accept English input
|
|
|
|
* at this point.
|
|
|
|
*/
|
|
|
|
yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
|
|
|
|
if (starts_with(yesno, "N") || starts_with(yesno, "n"))
|
2020-02-17 08:40:31 +00:00
|
|
|
return -1;
|
|
|
|
return 0;
|
2019-01-02 15:38:34 +00:00
|
|
|
}
|
|
|
|
|
2020-02-17 08:40:31 +00:00
|
|
|
if (!is_empty_or_missing_file(git_path_bisect_start()))
|
|
|
|
return error(_(need_bad_and_good_revision_warning),
|
|
|
|
vocab_bad, vocab_good, vocab_bad, vocab_good);
|
|
|
|
else
|
|
|
|
return error(_(need_bisect_start_warning),
|
|
|
|
vocab_good, vocab_bad, vocab_good, vocab_bad);
|
|
|
|
}
|
|
|
|
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
static void bisect_status(struct bisect_state *state,
|
|
|
|
const struct bisect_terms *terms)
|
2020-02-17 08:40:31 +00:00
|
|
|
{
|
|
|
|
char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
|
|
|
|
char *good_glob = xstrfmt("%s-*", terms->term_good);
|
|
|
|
|
|
|
|
if (ref_exists(bad_ref))
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
state->nr_bad = 1;
|
2020-02-17 08:40:31 +00:00
|
|
|
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
for_each_glob_ref_in(inc_nr, good_glob, "refs/bisect/",
|
|
|
|
(void *) &state->nr_good);
|
2020-02-17 08:40:31 +00:00
|
|
|
|
|
|
|
free(good_glob);
|
|
|
|
free(bad_ref);
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
}
|
|
|
|
|
2022-05-11 18:00:14 +00:00
|
|
|
__attribute__((format (printf, 1, 2)))
|
|
|
|
static void bisect_log_printf(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
strbuf_vaddf(&buf, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
printf("%s", buf.buf);
|
|
|
|
append_to_file(git_path_bisect_log(), "# %s", buf.buf);
|
|
|
|
|
|
|
|
strbuf_release(&buf);
|
|
|
|
}
|
|
|
|
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
static void bisect_print_status(const struct bisect_terms *terms)
|
|
|
|
{
|
|
|
|
struct bisect_state state = { 0 };
|
|
|
|
|
|
|
|
bisect_status(&state, terms);
|
|
|
|
|
|
|
|
/* If we had both, we'd already be started, and shouldn't get here. */
|
|
|
|
if (state.nr_good && state.nr_bad)
|
|
|
|
return;
|
2020-02-17 08:40:31 +00:00
|
|
|
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
if (!state.nr_good && !state.nr_bad)
|
2022-05-11 18:00:14 +00:00
|
|
|
bisect_log_printf(_("status: waiting for both good and bad commits\n"));
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
else if (state.nr_good)
|
2022-05-11 18:00:14 +00:00
|
|
|
bisect_log_printf(Q_("status: waiting for bad commit, %d good commit known\n",
|
|
|
|
"status: waiting for bad commit, %d good commits known\n",
|
|
|
|
state.nr_good), state.nr_good);
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
else
|
2022-05-11 18:00:14 +00:00
|
|
|
bisect_log_printf(_("status: waiting for good commit(s), bad commit known\n"));
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bisect_next_check(const struct bisect_terms *terms,
|
|
|
|
const char *current_term)
|
|
|
|
{
|
|
|
|
struct bisect_state state = { 0 };
|
|
|
|
bisect_status(&state, terms);
|
|
|
|
return decide_next(terms, current_term, !state.nr_good, !state.nr_bad);
|
2019-01-02 15:38:34 +00:00
|
|
|
}
|
|
|
|
|
2019-01-02 15:38:35 +00:00
|
|
|
static int get_terms(struct bisect_terms *terms)
|
|
|
|
{
|
|
|
|
struct strbuf str = STRBUF_INIT;
|
|
|
|
FILE *fp = NULL;
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
fp = fopen(git_path_bisect_terms(), "r");
|
|
|
|
if (!fp) {
|
|
|
|
res = -1;
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
free_terms(terms);
|
|
|
|
strbuf_getline_lf(&str, fp);
|
|
|
|
terms->term_bad = strbuf_detach(&str, NULL);
|
|
|
|
strbuf_getline_lf(&str, fp);
|
|
|
|
terms->term_good = strbuf_detach(&str, NULL);
|
|
|
|
|
|
|
|
finish:
|
|
|
|
if (fp)
|
|
|
|
fclose(fp);
|
|
|
|
strbuf_release(&str);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bisect_terms(struct bisect_terms *terms, const char *option)
|
|
|
|
{
|
|
|
|
if (get_terms(terms))
|
|
|
|
return error(_("no terms defined"));
|
|
|
|
|
2022-05-02 16:50:37 +00:00
|
|
|
if (!option) {
|
2019-01-02 15:38:35 +00:00
|
|
|
printf(_("Your current terms are %s for the old state\n"
|
|
|
|
"and %s for the new state.\n"),
|
|
|
|
terms->term_good, terms->term_bad);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (one_of(option, "--term-good", "--term-old", NULL))
|
|
|
|
printf("%s\n", terms->term_good);
|
|
|
|
else if (one_of(option, "--term-bad", "--term-new", NULL))
|
|
|
|
printf("%s\n", terms->term_bad);
|
|
|
|
else
|
|
|
|
return error(_("invalid argument %s for 'git bisect terms'.\n"
|
|
|
|
"Supported options are: "
|
|
|
|
"--term-good|--term-old and "
|
|
|
|
"--term-bad|--term-new."), option);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-02 15:38:36 +00:00
|
|
|
static int bisect_append_log_quoted(const char **argv)
|
|
|
|
{
|
2020-02-17 08:40:29 +00:00
|
|
|
int res = 0;
|
2019-01-02 15:38:36 +00:00
|
|
|
FILE *fp = fopen(git_path_bisect_log(), "a");
|
|
|
|
struct strbuf orig_args = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (!fp)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (fprintf(fp, "git bisect start") < 1) {
|
2020-02-17 08:40:29 +00:00
|
|
|
res = -1;
|
2019-01-02 15:38:36 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
sq_quote_argv(&orig_args, argv);
|
|
|
|
if (fprintf(fp, "%s\n", orig_args.buf) < 1)
|
2020-02-17 08:40:29 +00:00
|
|
|
res = -1;
|
2019-01-02 15:38:36 +00:00
|
|
|
|
|
|
|
finish:
|
|
|
|
fclose(fp);
|
|
|
|
strbuf_release(&orig_args);
|
2020-02-17 08:40:29 +00:00
|
|
|
return res;
|
2019-01-02 15:38:36 +00:00
|
|
|
}
|
|
|
|
|
2020-09-24 12:33:40 +00:00
|
|
|
static int add_bisect_ref(const char *refname, const struct object_id *oid,
|
2022-08-25 17:09:48 +00:00
|
|
|
int flags UNUSED, void *cb)
|
2020-09-24 12:33:40 +00:00
|
|
|
{
|
|
|
|
struct add_bisect_ref_data *data = cb;
|
|
|
|
|
|
|
|
add_pending_oid(data->revs, refname, oid, data->object_flags);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
struct add_bisect_ref_data cb = { revs };
|
|
|
|
char *good = xstrfmt("%s-*", terms->term_good);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We cannot use terms->term_bad directly in
|
|
|
|
* for_each_glob_ref_in() and we have to append a '*' to it,
|
|
|
|
* otherwise for_each_glob_ref_in() will append '/' and '*'.
|
|
|
|
*/
|
|
|
|
char *bad = xstrfmt("%s*", terms->term_bad);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It is important to reset the flags used by revision walks
|
|
|
|
* as the previous call to bisect_next_all() in turn
|
|
|
|
* sets up a revision walk.
|
|
|
|
*/
|
|
|
|
reset_revision_walk();
|
|
|
|
init_revisions(revs, NULL);
|
|
|
|
setup_revisions(0, NULL, revs, NULL);
|
|
|
|
for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
|
|
|
|
cb.object_flags = UNINTERESTING;
|
|
|
|
for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
|
|
|
|
if (prepare_revision_walk(revs))
|
|
|
|
res = error(_("revision walk setup failed\n"));
|
|
|
|
|
|
|
|
free(good);
|
|
|
|
free(bad);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bisect_skipped_commits(struct bisect_terms *terms)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
FILE *fp = NULL;
|
|
|
|
struct rev_info revs;
|
|
|
|
struct commit *commit;
|
|
|
|
struct pretty_print_context pp = {0};
|
|
|
|
struct strbuf commit_name = STRBUF_INIT;
|
|
|
|
|
|
|
|
res = prepare_revs(terms, &revs);
|
|
|
|
if (res)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
fp = fopen(git_path_bisect_log(), "a");
|
|
|
|
if (!fp)
|
|
|
|
return error_errno(_("could not open '%s' for appending"),
|
|
|
|
git_path_bisect_log());
|
|
|
|
|
|
|
|
if (fprintf(fp, "# only skipped commits left to test\n") < 0)
|
|
|
|
return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
|
|
|
|
|
|
|
|
while ((commit = get_revision(&revs)) != NULL) {
|
|
|
|
strbuf_reset(&commit_name);
|
|
|
|
format_commit_message(commit, "%s",
|
|
|
|
&commit_name, &pp);
|
|
|
|
fprintf(fp, "# possible first %s commit: [%s] %s\n",
|
|
|
|
terms->term_bad, oid_to_hex(&commit->object.oid),
|
|
|
|
commit_name.buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset the flags used by revision walks in case
|
|
|
|
* there is another revision walk after this one.
|
|
|
|
*/
|
|
|
|
reset_revision_walk();
|
|
|
|
|
|
|
|
strbuf_release(&commit_name);
|
2022-04-13 20:01:36 +00:00
|
|
|
release_revisions(&revs);
|
2020-09-24 12:33:40 +00:00
|
|
|
fclose(fp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bisect_successful(struct bisect_terms *terms)
|
|
|
|
{
|
|
|
|
struct object_id oid;
|
|
|
|
struct commit *commit;
|
|
|
|
struct pretty_print_context pp = {0};
|
|
|
|
struct strbuf commit_name = STRBUF_INIT;
|
|
|
|
char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
|
|
|
|
int res;
|
|
|
|
|
|
|
|
read_ref(bad_ref, &oid);
|
|
|
|
commit = lookup_commit_reference_by_name(bad_ref);
|
|
|
|
format_commit_message(commit, "%s", &commit_name, &pp);
|
|
|
|
|
|
|
|
res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
|
|
|
|
terms->term_bad, oid_to_hex(&commit->object.oid),
|
|
|
|
commit_name.buf);
|
|
|
|
|
|
|
|
strbuf_release(&commit_name);
|
|
|
|
free(bad_ref);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
|
|
|
|
{
|
|
|
|
enum bisect_error res;
|
|
|
|
|
|
|
|
if (bisect_autostart(terms))
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
if (bisect_next_check(terms, terms->term_good))
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
/* Perform all bisection computation */
|
|
|
|
res = bisect_next_all(the_repository, prefix);
|
|
|
|
|
|
|
|
if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
|
|
|
|
res = bisect_successful(terms);
|
|
|
|
return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
|
|
|
|
} else if (res == BISECT_ONLY_SKIPPED_LEFT) {
|
|
|
|
res = bisect_skipped_commits(terms);
|
|
|
|
return res ? res : BISECT_ONLY_SKIPPED_LEFT;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
|
|
|
|
{
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
if (bisect_next_check(terms, NULL)) {
|
|
|
|
bisect_print_status(terms);
|
2020-09-24 12:33:40 +00:00
|
|
|
return BISECT_OK;
|
bisect: output state before we are ready to compute bisection
Commit 73c6de06aff8 ("bisect: don't use invalid oid as rev when
starting") changes the behaviour of `git bisect` to consider invalid
oids as pathspecs again, as in the old shell implementation.
While that behaviour may be desirable, it can also cause confusion. For
example, while bisecting in a particular repo I encountered this:
$ git bisect start d93ff48803f0 v6.3
$
...which led to me sitting for a few moments, wondering why there's no
printout stating the first rev to check.
It turns out that the tag was actually "6.3", not "v6.3", and thus the
bisect was still silently started with only a bad rev, because
d93ff48803f0 was a valid oid and "v6.3" was silently considered to be a
pathspec.
While this behaviour may be desirable, it can be confusing, especially
with different repo conventions either using or not using "v" before
release names, or when a branch name or tag is simply misspelled on the
command line.
In order to avoid situations like this, make it more clear what we're
waiting for:
$ git bisect start d93ff48803f0 v6.3
status: waiting for good commit(s), bad commit known
We already have good output once the bisect process has begun in
earnest, so we don't need to do anything more there.
Signed-off-by: Chris Down <chris@chrisdown.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-11 18:00:09 +00:00
|
|
|
}
|
2020-09-24 12:33:40 +00:00
|
|
|
|
|
|
|
return bisect_next(terms, prefix);
|
|
|
|
}
|
|
|
|
|
2023-01-12 15:19:10 +00:00
|
|
|
static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
|
|
|
|
const char **argv)
|
2019-01-02 15:38:36 +00:00
|
|
|
{
|
2020-08-07 21:58:36 +00:00
|
|
|
int no_checkout = 0;
|
2020-08-07 21:58:37 +00:00
|
|
|
int first_parent_only = 0;
|
2019-01-02 15:38:36 +00:00
|
|
|
int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
|
2020-10-15 13:38:32 +00:00
|
|
|
int flags, pathspec_pos;
|
|
|
|
enum bisect_error res = BISECT_OK;
|
2019-01-02 15:38:36 +00:00
|
|
|
struct string_list revs = STRING_LIST_INIT_DUP;
|
|
|
|
struct string_list states = STRING_LIST_INIT_DUP;
|
|
|
|
struct strbuf start_head = STRBUF_INIT;
|
|
|
|
struct strbuf bisect_names = STRBUF_INIT;
|
|
|
|
struct object_id head_oid;
|
|
|
|
struct object_id oid;
|
|
|
|
const char *head;
|
|
|
|
|
|
|
|
if (is_bare_repository())
|
|
|
|
no_checkout = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for one bad and then some good revisions
|
|
|
|
*/
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
if (!strcmp(argv[i], "--")) {
|
|
|
|
has_double_dash = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
const char *arg = argv[i];
|
|
|
|
if (!strcmp(argv[i], "--")) {
|
|
|
|
break;
|
|
|
|
} else if (!strcmp(arg, "--no-checkout")) {
|
|
|
|
no_checkout = 1;
|
2020-08-07 21:58:37 +00:00
|
|
|
} else if (!strcmp(arg, "--first-parent")) {
|
|
|
|
first_parent_only = 1;
|
2019-01-02 15:38:36 +00:00
|
|
|
} else if (!strcmp(arg, "--term-good") ||
|
|
|
|
!strcmp(arg, "--term-old")) {
|
2020-05-20 23:26:27 +00:00
|
|
|
i++;
|
|
|
|
if (argc <= i)
|
|
|
|
return error(_("'' is not a valid term"));
|
2019-01-02 15:38:36 +00:00
|
|
|
must_write_terms = 1;
|
|
|
|
free((void *) terms->term_good);
|
2020-05-20 23:26:27 +00:00
|
|
|
terms->term_good = xstrdup(argv[i]);
|
2019-01-02 15:38:36 +00:00
|
|
|
} else if (skip_prefix(arg, "--term-good=", &arg) ||
|
|
|
|
skip_prefix(arg, "--term-old=", &arg)) {
|
|
|
|
must_write_terms = 1;
|
|
|
|
free((void *) terms->term_good);
|
|
|
|
terms->term_good = xstrdup(arg);
|
|
|
|
} else if (!strcmp(arg, "--term-bad") ||
|
|
|
|
!strcmp(arg, "--term-new")) {
|
2020-05-20 23:26:27 +00:00
|
|
|
i++;
|
|
|
|
if (argc <= i)
|
|
|
|
return error(_("'' is not a valid term"));
|
2019-01-02 15:38:36 +00:00
|
|
|
must_write_terms = 1;
|
|
|
|
free((void *) terms->term_bad);
|
2020-05-20 23:26:27 +00:00
|
|
|
terms->term_bad = xstrdup(argv[i]);
|
2019-01-02 15:38:36 +00:00
|
|
|
} else if (skip_prefix(arg, "--term-bad=", &arg) ||
|
|
|
|
skip_prefix(arg, "--term-new=", &arg)) {
|
|
|
|
must_write_terms = 1;
|
|
|
|
free((void *) terms->term_bad);
|
|
|
|
terms->term_bad = xstrdup(arg);
|
2020-05-20 23:26:27 +00:00
|
|
|
} else if (starts_with(arg, "--")) {
|
2019-01-02 15:38:36 +00:00
|
|
|
return error(_("unrecognized option: '%s'"), arg);
|
2020-09-25 13:01:28 +00:00
|
|
|
} else if (!get_oidf(&oid, "%s^{commit}", arg)) {
|
2019-01-02 15:38:36 +00:00
|
|
|
string_list_append(&revs, oid_to_hex(&oid));
|
2020-09-25 13:01:28 +00:00
|
|
|
} else if (has_double_dash) {
|
|
|
|
die(_("'%s' does not appear to be a valid "
|
|
|
|
"revision"), arg);
|
|
|
|
} else {
|
|
|
|
break;
|
2019-01-02 15:38:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pathspec_pos = i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The user ran "git bisect start <sha1> <sha1>", hence did not
|
|
|
|
* explicitly specify the terms, but we are already starting to
|
|
|
|
* set references named with the default terms, and won't be able
|
|
|
|
* to change afterwards.
|
|
|
|
*/
|
|
|
|
if (revs.nr)
|
|
|
|
must_write_terms = 1;
|
|
|
|
for (i = 0; i < revs.nr; i++) {
|
|
|
|
if (bad_seen) {
|
|
|
|
string_list_append(&states, terms->term_good);
|
|
|
|
} else {
|
|
|
|
bad_seen = 1;
|
|
|
|
string_list_append(&states, terms->term_bad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify HEAD
|
|
|
|
*/
|
|
|
|
head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
|
|
|
|
if (!head)
|
|
|
|
if (get_oid("HEAD", &head_oid))
|
|
|
|
return error(_("bad HEAD - I need a HEAD"));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if we are bisecting
|
|
|
|
*/
|
|
|
|
if (!is_empty_or_missing_file(git_path_bisect_start())) {
|
|
|
|
/* Reset to the rev from where we started */
|
|
|
|
strbuf_read_file(&start_head, git_path_bisect_start(), 0);
|
|
|
|
strbuf_trim(&start_head);
|
|
|
|
if (!no_checkout) {
|
2022-10-30 11:55:06 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2019-01-02 15:38:36 +00:00
|
|
|
|
2022-10-30 11:55:06 +00:00
|
|
|
cmd.git_cmd = 1;
|
|
|
|
strvec_pushl(&cmd.args, "checkout", start_head.buf,
|
|
|
|
"--", NULL);
|
|
|
|
if (run_command(&cmd)) {
|
2020-02-17 08:40:29 +00:00
|
|
|
res = error(_("checking out '%s' failed."
|
2019-01-02 15:38:36 +00:00
|
|
|
" Try 'git bisect start "
|
|
|
|
"<valid-branch>'."),
|
|
|
|
start_head.buf);
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Get the rev from where we start. */
|
|
|
|
if (!get_oid(head, &head_oid) &&
|
|
|
|
!starts_with(head, "refs/heads/")) {
|
|
|
|
strbuf_reset(&start_head);
|
|
|
|
strbuf_addstr(&start_head, oid_to_hex(&head_oid));
|
|
|
|
} else if (!get_oid(head, &head_oid) &&
|
|
|
|
skip_prefix(head, "refs/heads/", &head)) {
|
|
|
|
strbuf_addstr(&start_head, head);
|
|
|
|
} else {
|
|
|
|
return error(_("bad HEAD - strange symbolic ref"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get rid of any old bisect state.
|
|
|
|
*/
|
|
|
|
if (bisect_clean_state())
|
2020-10-15 13:38:32 +00:00
|
|
|
return BISECT_FAILED;
|
2019-01-02 15:38:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Write new start state
|
|
|
|
*/
|
|
|
|
write_file(git_path_bisect_start(), "%s\n", start_head.buf);
|
|
|
|
|
2020-08-07 21:58:37 +00:00
|
|
|
if (first_parent_only)
|
|
|
|
write_file(git_path_bisect_first_parent(), "\n");
|
|
|
|
|
2019-01-02 15:38:36 +00:00
|
|
|
if (no_checkout) {
|
2019-05-21 17:50:21 +00:00
|
|
|
if (get_oid(start_head.buf, &oid) < 0) {
|
2020-02-17 08:40:29 +00:00
|
|
|
res = error(_("invalid ref: '%s'"), start_head.buf);
|
2019-05-21 17:50:21 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
2019-01-02 15:38:36 +00:00
|
|
|
if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
|
|
|
|
UPDATE_REFS_MSG_ON_ERR)) {
|
2020-10-15 13:38:32 +00:00
|
|
|
res = BISECT_FAILED;
|
2019-01-02 15:38:36 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pathspec_pos < argc - 1)
|
|
|
|
sq_quote_argv(&bisect_names, argv + pathspec_pos);
|
|
|
|
write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
|
|
|
|
|
|
|
|
for (i = 0; i < states.nr; i++)
|
|
|
|
if (bisect_write(states.items[i].string,
|
|
|
|
revs.items[i].string, terms, 1)) {
|
2020-10-15 13:38:32 +00:00
|
|
|
res = BISECT_FAILED;
|
2019-01-02 15:38:36 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (must_write_terms && write_terms(terms->term_bad,
|
|
|
|
terms->term_good)) {
|
2020-10-15 13:38:32 +00:00
|
|
|
res = BISECT_FAILED;
|
2019-01-02 15:38:36 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2020-02-17 08:40:29 +00:00
|
|
|
res = bisect_append_log_quoted(argv);
|
|
|
|
if (res)
|
2020-10-15 13:38:32 +00:00
|
|
|
res = BISECT_FAILED;
|
2019-01-02 15:38:36 +00:00
|
|
|
|
|
|
|
finish:
|
|
|
|
string_list_clear(&revs, 0);
|
|
|
|
string_list_clear(&states, 0);
|
|
|
|
strbuf_release(&start_head);
|
|
|
|
strbuf_release(&bisect_names);
|
2020-10-15 13:38:32 +00:00
|
|
|
if (res)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
res = bisect_auto_next(terms, NULL);
|
|
|
|
if (!is_bisect_success(res))
|
|
|
|
bisect_clean_state();
|
2020-02-17 08:40:29 +00:00
|
|
|
return res;
|
2019-01-02 15:38:36 +00:00
|
|
|
}
|
|
|
|
|
2020-09-24 12:33:38 +00:00
|
|
|
static inline int file_is_not_empty(const char *path)
|
|
|
|
{
|
|
|
|
return !is_empty_or_missing_file(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bisect_autostart(struct bisect_terms *terms)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
const char *yesno;
|
|
|
|
|
|
|
|
if (file_is_not_empty(git_path_bisect_start()))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fprintf_ln(stderr, _("You need to start by \"git bisect "
|
|
|
|
"start\"\n"));
|
|
|
|
|
|
|
|
if (!isatty(STDIN_FILENO))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TRANSLATORS: Make sure to include [Y] and [n] in your
|
|
|
|
* translation. The program will only accept English input
|
|
|
|
* at this point.
|
|
|
|
*/
|
|
|
|
yesno = git_prompt(_("Do you want me to do it for you "
|
|
|
|
"[Y/n]? "), PROMPT_ECHO);
|
|
|
|
res = tolower(*yesno) == 'n' ?
|
2023-01-12 15:19:10 +00:00
|
|
|
-1 : bisect_start(terms, 0, empty_strvec);
|
2020-09-24 12:33:38 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-01-12 15:19:10 +00:00
|
|
|
static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
|
|
|
|
const char **argv)
|
2020-10-15 13:38:35 +00:00
|
|
|
{
|
|
|
|
const char *state;
|
|
|
|
int i, verify_expected = 1;
|
|
|
|
struct object_id oid, expected;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
struct oid_array revs = OID_ARRAY_INIT;
|
|
|
|
|
|
|
|
if (!argc)
|
|
|
|
return error(_("Please call `--bisect-state` with at least one argument"));
|
|
|
|
|
|
|
|
if (bisect_autostart(terms))
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
state = argv[0];
|
|
|
|
if (check_and_set_terms(terms, state) ||
|
|
|
|
!one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
argv++;
|
|
|
|
argc--;
|
|
|
|
if (argc > 1 && !strcmp(state, terms->term_bad))
|
|
|
|
return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
|
|
|
|
|
|
|
|
if (argc == 0) {
|
|
|
|
const char *head = "BISECT_HEAD";
|
|
|
|
enum get_oid_result res_head = get_oid(head, &oid);
|
|
|
|
|
|
|
|
if (res_head == MISSING_OBJECT) {
|
|
|
|
head = "HEAD";
|
|
|
|
res_head = get_oid(head, &oid);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res_head)
|
|
|
|
error(_("Bad rev input: %s"), head);
|
|
|
|
oid_array_append(&revs, &oid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All input revs must be checked before executing bisect_write()
|
|
|
|
* to discard junk revs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (; argc; argc--, argv++) {
|
2021-03-16 15:15:55 +00:00
|
|
|
struct commit *commit;
|
|
|
|
|
2020-10-15 13:38:35 +00:00
|
|
|
if (get_oid(*argv, &oid)){
|
|
|
|
error(_("Bad rev input: %s"), *argv);
|
|
|
|
oid_array_clear(&revs);
|
|
|
|
return BISECT_FAILED;
|
|
|
|
}
|
2021-03-16 15:15:55 +00:00
|
|
|
|
|
|
|
commit = lookup_commit_reference(the_repository, &oid);
|
|
|
|
if (!commit)
|
|
|
|
die(_("Bad rev input (not a commit): %s"), *argv);
|
|
|
|
|
|
|
|
oid_array_append(&revs, &commit->object.oid);
|
2020-10-15 13:38:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
|
|
|
|
get_oid_hex(buf.buf, &expected) < 0)
|
|
|
|
verify_expected = 0; /* Ignore invalid file contents */
|
|
|
|
strbuf_release(&buf);
|
|
|
|
|
|
|
|
for (i = 0; i < revs.nr; i++) {
|
|
|
|
if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
|
|
|
|
oid_array_clear(&revs);
|
|
|
|
return BISECT_FAILED;
|
|
|
|
}
|
|
|
|
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
|
|
|
|
unlink_or_warn(git_path_bisect_ancestors_ok());
|
|
|
|
unlink_or_warn(git_path_bisect_expected_rev());
|
|
|
|
verify_expected = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oid_array_clear(&revs);
|
|
|
|
return bisect_auto_next(terms, NULL);
|
|
|
|
}
|
|
|
|
|
2021-02-03 21:54:32 +00:00
|
|
|
static enum bisect_error bisect_log(void)
|
|
|
|
{
|
|
|
|
int fd, status;
|
|
|
|
const char* filename = git_path_bisect_log();
|
|
|
|
|
|
|
|
if (is_empty_or_missing_file(filename))
|
|
|
|
return error(_("We are not bisecting."));
|
|
|
|
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
|
|
if (fd < 0)
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
status = copy_fd(fd, STDOUT_FILENO);
|
|
|
|
close(fd);
|
|
|
|
return status ? BISECT_FAILED : BISECT_OK;
|
|
|
|
}
|
|
|
|
|
2021-02-03 21:54:33 +00:00
|
|
|
static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
|
|
|
|
{
|
|
|
|
const char *p = line->buf + strspn(line->buf, " \t");
|
|
|
|
char *word_end, *rev;
|
|
|
|
|
|
|
|
if ((!skip_prefix(p, "git bisect", &p) &&
|
|
|
|
!skip_prefix(p, "git-bisect", &p)) || !isspace(*p))
|
|
|
|
return 0;
|
|
|
|
p += strspn(p, " \t");
|
|
|
|
|
|
|
|
word_end = (char *)p + strcspn(p, " \t");
|
|
|
|
rev = word_end + strspn(word_end, " \t");
|
|
|
|
*word_end = '\0'; /* NUL-terminate the word */
|
|
|
|
|
|
|
|
get_terms(terms);
|
|
|
|
if (check_and_set_terms(terms, p))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!strcmp(p, "start")) {
|
|
|
|
struct strvec argv = STRVEC_INIT;
|
|
|
|
int res;
|
|
|
|
sq_dequote_to_strvec(rev, &argv);
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_start(terms, argv.nr, argv.v);
|
2021-02-03 21:54:33 +00:00
|
|
|
strvec_clear(&argv);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (one_of(p, terms->term_good,
|
|
|
|
terms->term_bad, "skip", NULL))
|
|
|
|
return bisect_write(p, rev, terms, 0);
|
|
|
|
|
|
|
|
if (!strcmp(p, "terms")) {
|
|
|
|
struct strvec argv = STRVEC_INIT;
|
|
|
|
int res;
|
|
|
|
sq_dequote_to_strvec(rev, &argv);
|
|
|
|
res = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);
|
|
|
|
strvec_clear(&argv);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
error(_("'%s'?? what are you talking about?"), p);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)
|
|
|
|
{
|
|
|
|
FILE *fp = NULL;
|
|
|
|
enum bisect_error res = BISECT_OK;
|
|
|
|
struct strbuf line = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (is_empty_or_missing_file(filename))
|
|
|
|
return error(_("cannot read file '%s' for replaying"), filename);
|
|
|
|
|
|
|
|
if (bisect_reset(NULL))
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
fp = fopen(filename, "r");
|
|
|
|
if (!fp)
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
while ((strbuf_getline(&line, fp) != EOF) && !res)
|
|
|
|
res = process_replay_line(terms, &line);
|
|
|
|
|
|
|
|
strbuf_release(&line);
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
|
|
|
return bisect_auto_next(terms, NULL);
|
|
|
|
}
|
|
|
|
|
2023-01-12 15:19:10 +00:00
|
|
|
static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
|
|
|
|
const char **argv)
|
2021-02-03 21:54:37 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
enum bisect_error res;
|
|
|
|
struct strvec argv_state = STRVEC_INIT;
|
|
|
|
|
|
|
|
strvec_push(&argv_state, "skip");
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
const char *dotdot = strstr(argv[i], "..");
|
|
|
|
|
|
|
|
if (dotdot) {
|
|
|
|
struct rev_info revs;
|
|
|
|
struct commit *commit;
|
|
|
|
|
|
|
|
init_revisions(&revs, NULL);
|
|
|
|
setup_revisions(2, argv + i - 1, &revs, NULL);
|
|
|
|
|
|
|
|
if (prepare_revision_walk(&revs))
|
|
|
|
die(_("revision walk setup failed\n"));
|
|
|
|
while ((commit = get_revision(&revs)) != NULL)
|
|
|
|
strvec_push(&argv_state,
|
|
|
|
oid_to_hex(&commit->object.oid));
|
|
|
|
|
|
|
|
reset_revision_walk();
|
2022-04-13 20:01:36 +00:00
|
|
|
release_revisions(&revs);
|
2021-02-03 21:54:37 +00:00
|
|
|
} else {
|
|
|
|
strvec_push(&argv_state, argv[i]);
|
|
|
|
}
|
|
|
|
}
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_state(terms, argv_state.nr, argv_state.v);
|
2021-02-03 21:54:37 +00:00
|
|
|
|
|
|
|
strvec_clear(&argv_state);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-01-12 15:19:10 +00:00
|
|
|
static int bisect_visualize(struct bisect_terms *terms, int argc,
|
|
|
|
const char **argv)
|
2021-09-13 17:39:02 +00:00
|
|
|
{
|
2022-10-30 11:51:14 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2021-09-13 17:39:02 +00:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (bisect_next_check(terms, NULL) != 0)
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
cmd.no_stdin = 1;
|
2021-09-13 17:39:02 +00:00
|
|
|
if (!argc) {
|
|
|
|
if ((getenv("DISPLAY") || getenv("SESSIONNAME") || getenv("MSYSTEM") ||
|
|
|
|
getenv("SECURITYSESSIONID")) && exists_in_PATH("gitk")) {
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, "gitk");
|
2021-09-13 17:39:02 +00:00
|
|
|
} else {
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, "log");
|
|
|
|
cmd.git_cmd = 1;
|
2021-09-13 17:39:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (argv[0][0] == '-') {
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, "log");
|
|
|
|
cmd.git_cmd = 1;
|
2021-09-13 17:39:02 +00:00
|
|
|
} else if (strcmp(argv[0], "tig") && !starts_with(argv[0], "git"))
|
2022-10-30 11:51:14 +00:00
|
|
|
cmd.git_cmd = 1;
|
2021-09-13 17:39:02 +00:00
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_pushv(&cmd.args, argv);
|
2021-09-13 17:39:02 +00:00
|
|
|
}
|
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_pushl(&cmd.args, "--bisect", "--", NULL);
|
2021-09-13 17:39:02 +00:00
|
|
|
|
|
|
|
strbuf_read_file(&sb, git_path_bisect_names(), 0);
|
2022-10-30 11:51:14 +00:00
|
|
|
sq_dequote_to_strvec(sb.buf, &cmd.args);
|
2021-09-13 17:39:02 +00:00
|
|
|
strbuf_release(&sb);
|
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
return run_command(&cmd);
|
2021-09-13 17:39:02 +00:00
|
|
|
}
|
|
|
|
|
2022-08-25 17:09:48 +00:00
|
|
|
static int get_first_good(const char *refname UNUSED,
|
2022-08-19 10:08:32 +00:00
|
|
|
const struct object_id *oid,
|
2022-08-25 17:09:48 +00:00
|
|
|
int flag UNUSED, void *cb_data)
|
bisect--helper: double-check run command on exit code 126 and 127
When a run command cannot be executed or found, shells return exit code
126 or 127, respectively. Valid run commands are allowed to return
these codes as well to indicate bad revisions, though, for historical
reasons. This means typos can cause bogus bisect runs that go over the
full distance and end up reporting invalid results.
The best solution would be to reserve exit codes 126 and 127, like
71b0251cdd (Bisect run: "skip" current commit if script exit code is
125., 2007-10-26) did for 125, and abort bisect run when we get them.
That might be inconvenient for those who relied on the documentation
stating that 126 and 127 can be used for bad revisions, though.
The workaround used by this patch is to run the command on a known-good
revision and abort if we still get the same error code. This adds one
step to runs with scripts that use exit codes 126 and 127, but keeps
them supported, with one exception: It won't work with commands that
cannot recognize the (manually marked) known-good revision as such.
Run commands that use low exit codes are unaffected. Typos are reported
after executing the missing command twice and three checkouts (the first
step, the known good revision and back to the revision of the first
step).
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-18 12:46:32 +00:00
|
|
|
{
|
|
|
|
oidcpy(cb_data, oid);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-11-10 16:36:39 +00:00
|
|
|
static int do_bisect_run(const char *command)
|
2022-10-30 11:48:16 +00:00
|
|
|
{
|
2022-10-30 11:55:06 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
|
|
|
|
2022-11-10 16:36:39 +00:00
|
|
|
printf(_("running %s\n"), command);
|
2022-10-30 11:55:06 +00:00
|
|
|
cmd.use_shell = 1;
|
|
|
|
strvec_push(&cmd.args, command);
|
|
|
|
return run_command(&cmd);
|
2022-10-30 11:48:16 +00:00
|
|
|
}
|
|
|
|
|
2022-11-10 16:36:39 +00:00
|
|
|
static int verify_good(const struct bisect_terms *terms, const char *command)
|
bisect--helper: double-check run command on exit code 126 and 127
When a run command cannot be executed or found, shells return exit code
126 or 127, respectively. Valid run commands are allowed to return
these codes as well to indicate bad revisions, though, for historical
reasons. This means typos can cause bogus bisect runs that go over the
full distance and end up reporting invalid results.
The best solution would be to reserve exit codes 126 and 127, like
71b0251cdd (Bisect run: "skip" current commit if script exit code is
125., 2007-10-26) did for 125, and abort bisect run when we get them.
That might be inconvenient for those who relied on the documentation
stating that 126 and 127 can be used for bad revisions, though.
The workaround used by this patch is to run the command on a known-good
revision and abort if we still get the same error code. This adds one
step to runs with scripts that use exit codes 126 and 127, but keeps
them supported, with one exception: It won't work with commands that
cannot recognize the (manually marked) known-good revision as such.
Run commands that use low exit codes are unaffected. Typos are reported
after executing the missing command twice and three checkouts (the first
step, the known good revision and back to the revision of the first
step).
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-18 12:46:32 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
enum bisect_error res;
|
|
|
|
struct object_id good_rev;
|
|
|
|
struct object_id current_rev;
|
|
|
|
char *good_glob = xstrfmt("%s-*", terms->term_good);
|
|
|
|
int no_checkout = ref_exists("BISECT_HEAD");
|
|
|
|
|
|
|
|
for_each_glob_ref_in(get_first_good, good_glob, "refs/bisect/",
|
|
|
|
&good_rev);
|
|
|
|
free(good_glob);
|
|
|
|
|
|
|
|
if (read_ref(no_checkout ? "BISECT_HEAD" : "HEAD", ¤t_rev))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
res = bisect_checkout(&good_rev, no_checkout);
|
|
|
|
if (res != BISECT_OK)
|
|
|
|
return -1;
|
|
|
|
|
2022-11-10 16:36:39 +00:00
|
|
|
rc = do_bisect_run(command);
|
bisect--helper: double-check run command on exit code 126 and 127
When a run command cannot be executed or found, shells return exit code
126 or 127, respectively. Valid run commands are allowed to return
these codes as well to indicate bad revisions, though, for historical
reasons. This means typos can cause bogus bisect runs that go over the
full distance and end up reporting invalid results.
The best solution would be to reserve exit codes 126 and 127, like
71b0251cdd (Bisect run: "skip" current commit if script exit code is
125., 2007-10-26) did for 125, and abort bisect run when we get them.
That might be inconvenient for those who relied on the documentation
stating that 126 and 127 can be used for bad revisions, though.
The workaround used by this patch is to run the command on a known-good
revision and abort if we still get the same error code. This adds one
step to runs with scripts that use exit codes 126 and 127, but keeps
them supported, with one exception: It won't work with commands that
cannot recognize the (manually marked) known-good revision as such.
Run commands that use low exit codes are unaffected. Typos are reported
after executing the missing command twice and three checkouts (the first
step, the known good revision and back to the revision of the first
step).
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-18 12:46:32 +00:00
|
|
|
|
|
|
|
res = bisect_checkout(¤t_rev, no_checkout);
|
|
|
|
if (res != BISECT_OK)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2023-01-12 15:19:10 +00:00
|
|
|
static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
|
2021-09-13 17:39:03 +00:00
|
|
|
{
|
|
|
|
int res = BISECT_OK;
|
|
|
|
struct strbuf command = STRBUF_INIT;
|
|
|
|
const char *new_state;
|
|
|
|
int temporary_stdout_fd, saved_stdout;
|
bisect--helper: double-check run command on exit code 126 and 127
When a run command cannot be executed or found, shells return exit code
126 or 127, respectively. Valid run commands are allowed to return
these codes as well to indicate bad revisions, though, for historical
reasons. This means typos can cause bogus bisect runs that go over the
full distance and end up reporting invalid results.
The best solution would be to reserve exit codes 126 and 127, like
71b0251cdd (Bisect run: "skip" current commit if script exit code is
125., 2007-10-26) did for 125, and abort bisect run when we get them.
That might be inconvenient for those who relied on the documentation
stating that 126 and 127 can be used for bad revisions, though.
The workaround used by this patch is to run the command on a known-good
revision and abort if we still get the same error code. This adds one
step to runs with scripts that use exit codes 126 and 127, but keeps
them supported, with one exception: It won't work with commands that
cannot recognize the (manually marked) known-good revision as such.
Run commands that use low exit codes are unaffected. Typos are reported
after executing the missing command twice and three checkouts (the first
step, the known good revision and back to the revision of the first
step).
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-18 12:46:32 +00:00
|
|
|
int is_first_run = 1;
|
2021-09-13 17:39:03 +00:00
|
|
|
|
|
|
|
if (bisect_next_check(terms, NULL))
|
|
|
|
return BISECT_FAILED;
|
|
|
|
|
2022-11-10 16:36:37 +00:00
|
|
|
if (!argc) {
|
2021-09-13 17:39:03 +00:00
|
|
|
error(_("bisect run failed: no command provided."));
|
|
|
|
return BISECT_FAILED;
|
|
|
|
}
|
|
|
|
|
2022-11-10 16:36:37 +00:00
|
|
|
sq_quote_argv(&command, argv);
|
2022-11-10 16:36:39 +00:00
|
|
|
strbuf_ltrim(&command);
|
2021-09-13 17:39:03 +00:00
|
|
|
while (1) {
|
2022-11-10 16:36:39 +00:00
|
|
|
res = do_bisect_run(command.buf);
|
2021-09-13 17:39:03 +00:00
|
|
|
|
bisect--helper: double-check run command on exit code 126 and 127
When a run command cannot be executed or found, shells return exit code
126 or 127, respectively. Valid run commands are allowed to return
these codes as well to indicate bad revisions, though, for historical
reasons. This means typos can cause bogus bisect runs that go over the
full distance and end up reporting invalid results.
The best solution would be to reserve exit codes 126 and 127, like
71b0251cdd (Bisect run: "skip" current commit if script exit code is
125., 2007-10-26) did for 125, and abort bisect run when we get them.
That might be inconvenient for those who relied on the documentation
stating that 126 and 127 can be used for bad revisions, though.
The workaround used by this patch is to run the command on a known-good
revision and abort if we still get the same error code. This adds one
step to runs with scripts that use exit codes 126 and 127, but keeps
them supported, with one exception: It won't work with commands that
cannot recognize the (manually marked) known-good revision as such.
Run commands that use low exit codes are unaffected. Typos are reported
after executing the missing command twice and three checkouts (the first
step, the known good revision and back to the revision of the first
step).
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-18 12:46:32 +00:00
|
|
|
/*
|
|
|
|
* Exit code 126 and 127 can either come from the shell
|
|
|
|
* if it was unable to execute or even find the script,
|
|
|
|
* or from the script itself. Check with a known-good
|
|
|
|
* revision to avoid trashing the bisect run due to a
|
|
|
|
* missing or non-executable script.
|
|
|
|
*/
|
|
|
|
if (is_first_run && (res == 126 || res == 127)) {
|
2022-11-10 16:36:39 +00:00
|
|
|
int rc = verify_good(terms, command.buf);
|
bisect--helper: double-check run command on exit code 126 and 127
When a run command cannot be executed or found, shells return exit code
126 or 127, respectively. Valid run commands are allowed to return
these codes as well to indicate bad revisions, though, for historical
reasons. This means typos can cause bogus bisect runs that go over the
full distance and end up reporting invalid results.
The best solution would be to reserve exit codes 126 and 127, like
71b0251cdd (Bisect run: "skip" current commit if script exit code is
125., 2007-10-26) did for 125, and abort bisect run when we get them.
That might be inconvenient for those who relied on the documentation
stating that 126 and 127 can be used for bad revisions, though.
The workaround used by this patch is to run the command on a known-good
revision and abort if we still get the same error code. This adds one
step to runs with scripts that use exit codes 126 and 127, but keeps
them supported, with one exception: It won't work with commands that
cannot recognize the (manually marked) known-good revision as such.
Run commands that use low exit codes are unaffected. Typos are reported
after executing the missing command twice and three checkouts (the first
step, the known good revision and back to the revision of the first
step).
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-18 12:46:32 +00:00
|
|
|
is_first_run = 0;
|
2022-11-10 16:36:40 +00:00
|
|
|
if (rc < 0 || 128 <= rc) {
|
2022-11-10 16:36:39 +00:00
|
|
|
error(_("unable to verify %s on good"
|
|
|
|
" revision"), command.buf);
|
bisect--helper: double-check run command on exit code 126 and 127
When a run command cannot be executed or found, shells return exit code
126 or 127, respectively. Valid run commands are allowed to return
these codes as well to indicate bad revisions, though, for historical
reasons. This means typos can cause bogus bisect runs that go over the
full distance and end up reporting invalid results.
The best solution would be to reserve exit codes 126 and 127, like
71b0251cdd (Bisect run: "skip" current commit if script exit code is
125., 2007-10-26) did for 125, and abort bisect run when we get them.
That might be inconvenient for those who relied on the documentation
stating that 126 and 127 can be used for bad revisions, though.
The workaround used by this patch is to run the command on a known-good
revision and abort if we still get the same error code. This adds one
step to runs with scripts that use exit codes 126 and 127, but keeps
them supported, with one exception: It won't work with commands that
cannot recognize the (manually marked) known-good revision as such.
Run commands that use low exit codes are unaffected. Typos are reported
after executing the missing command twice and three checkouts (the first
step, the known good revision and back to the revision of the first
step).
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-18 12:46:32 +00:00
|
|
|
res = BISECT_FAILED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (rc == res) {
|
|
|
|
error(_("bogus exit code %d for good revision"),
|
|
|
|
rc);
|
|
|
|
res = BISECT_FAILED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-13 17:39:03 +00:00
|
|
|
if (res < 0 || 128 <= res) {
|
|
|
|
error(_("bisect run failed: exit code %d from"
|
2022-11-10 16:36:39 +00:00
|
|
|
" %s is < 0 or >= 128"), res, command.buf);
|
2022-01-18 12:46:15 +00:00
|
|
|
break;
|
2021-09-13 17:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (res == 125)
|
|
|
|
new_state = "skip";
|
|
|
|
else if (!res)
|
|
|
|
new_state = terms->term_good;
|
|
|
|
else
|
|
|
|
new_state = terms->term_bad;
|
|
|
|
|
|
|
|
temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
|
|
|
|
|
2022-01-18 12:46:15 +00:00
|
|
|
if (temporary_stdout_fd < 0) {
|
|
|
|
res = error_errno(_("cannot open file '%s' for writing"), git_path_bisect_run());
|
|
|
|
break;
|
|
|
|
}
|
2021-09-13 17:39:03 +00:00
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
saved_stdout = dup(1);
|
|
|
|
dup2(temporary_stdout_fd, 1);
|
|
|
|
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_state(terms, 1, &new_state);
|
2021-09-13 17:39:03 +00:00
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
dup2(saved_stdout, 1);
|
|
|
|
close(saved_stdout);
|
|
|
|
close(temporary_stdout_fd);
|
|
|
|
|
|
|
|
print_file_to_stdout(git_path_bisect_run());
|
|
|
|
|
|
|
|
if (res == BISECT_ONLY_SKIPPED_LEFT)
|
|
|
|
error(_("bisect run cannot continue any more"));
|
|
|
|
else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
|
2022-11-10 16:36:38 +00:00
|
|
|
puts(_("bisect run success"));
|
2021-09-13 17:39:03 +00:00
|
|
|
res = BISECT_OK;
|
|
|
|
} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
|
2022-11-10 16:36:39 +00:00
|
|
|
puts(_("bisect found first bad commit"));
|
2021-09-13 17:39:03 +00:00
|
|
|
res = BISECT_OK;
|
|
|
|
} else if (res) {
|
2023-01-12 15:19:12 +00:00
|
|
|
error(_("bisect run failed: 'git bisect %s'"
|
2022-11-10 16:36:38 +00:00
|
|
|
" exited with error code %d"), new_state, res);
|
2021-09-13 17:39:03 +00:00
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2022-01-18 12:46:15 +00:00
|
|
|
break;
|
2021-09-13 17:39:03 +00:00
|
|
|
}
|
2022-01-18 12:46:15 +00:00
|
|
|
|
|
|
|
strbuf_release(&command);
|
|
|
|
return res;
|
2021-09-13 17:39:03 +00:00
|
|
|
}
|
|
|
|
|
2022-11-10 16:36:21 +00:00
|
|
|
static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
|
|
|
|
{
|
|
|
|
if (argc > 1)
|
2022-11-10 16:36:41 +00:00
|
|
|
return error(_("'%s' requires either no argument or a commit"),
|
|
|
|
"git bisect reset");
|
2022-11-10 16:36:21 +00:00
|
|
|
return bisect_reset(argc ? argv[0] : NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
if (argc > 1)
|
2022-11-10 16:36:41 +00:00
|
|
|
return error(_("'%s' requires 0 or 1 argument"),
|
|
|
|
"git bisect terms");
|
2022-11-10 16:36:21 +00:00
|
|
|
res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
|
|
|
|
free_terms(&terms);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
set_terms(&terms, "bad", "good");
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_start(&terms, argc, argv);
|
2022-11-10 16:36:21 +00:00
|
|
|
free_terms(&terms);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
if (argc)
|
2022-11-10 16:36:41 +00:00
|
|
|
return error(_("'%s' requires 0 arguments"),
|
|
|
|
"git bisect next");
|
2022-11-10 16:36:21 +00:00
|
|
|
get_terms(&terms);
|
|
|
|
res = bisect_next(&terms, prefix);
|
|
|
|
free_terms(&terms);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2022-11-10 16:36:45 +00:00
|
|
|
static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
|
2022-11-10 16:36:21 +00:00
|
|
|
{
|
|
|
|
return bisect_log();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
if (argc != 1)
|
|
|
|
return error(_("no logfile given"));
|
|
|
|
set_terms(&terms, "bad", "good");
|
|
|
|
res = bisect_replay(&terms, argv[0]);
|
|
|
|
free_terms(&terms);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
set_terms(&terms, "bad", "good");
|
|
|
|
get_terms(&terms);
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_skip(&terms, argc, argv);
|
2022-11-10 16:36:21 +00:00
|
|
|
free_terms(&terms);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
get_terms(&terms);
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_visualize(&terms, argc, argv);
|
2022-11-10 16:36:21 +00:00
|
|
|
free_terms(&terms);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
if (!argc)
|
2022-11-10 16:36:41 +00:00
|
|
|
return error(_("'%s' failed: no command provided."), "git bisect run");
|
2022-11-10 16:36:21 +00:00
|
|
|
get_terms(&terms);
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_run(&terms, argc, argv);
|
2022-11-10 16:36:21 +00:00
|
|
|
free_terms(&terms);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2022-11-10 16:36:46 +00:00
|
|
|
int cmd_bisect(int argc, const char **argv, const char *prefix)
|
2009-03-26 04:55:54 +00:00
|
|
|
{
|
bisect--helper: remove unused options
'git-bisect.sh' used to have a 'bisect_next_check' to check if we have
both good/bad, old/new terms set or not. In commit 129a6cf344
(bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),
a subcommand for bisect--helper was introduced to port the check to C.
Since d1bbbe45df (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13), all users of 'bisect_next_check' was
re-implemented in C, this subcommand was no longer used but we forgot
to remove '--bisect-next-check'.
'git-bisect.sh' also used to have a 'bisect_write' function, whose
third positional parameter was a "nolog" flag. This flag was only used
when 'bisect_start' invoked 'bisect_write' to write the starting good
and bad revisions. Then 0f30233a11 (bisect--helper: `bisect_write`
shell function in C, 2019-01-02) ported it to C as a command mode of
'bisect--helper', which (incorrectly) added the '--no-log' option,
and convert the only place ('bisect_start') that call 'bisect_write'
with 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'
instead of '--no-log', since 'bisect--helper' has command modes not
subcommands, all other command modes see and handle that option as well.
This bogus state didn't last long, however, because in the same patch
series 06f5608c14 (bisect--helper: `bisect_start` shell function
partially in C, 2019-01-02) the C reimplementation of bisect_start()
started calling the bisect_write() C function, this time with the
right 'nolog' function parameter. From then on there was no need for
the '--no-log' option in 'bisect--helper'. Eventually all bisect
subcommands were ported to C as 'bisect--helper' command modes, each
calling the bisect_write() C function instead, but when the
'--bisect-write' command mode was removed in 68efed8c8a
(bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it
forgot to remove that '--no-log' option.
'--no-log' option had never been used and it's unused now.
Let's remove --bisect-next-check and --no-log from option parsing.
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2022-11-10 16:36:20 +00:00
|
|
|
int res = 0;
|
2022-11-10 16:36:22 +00:00
|
|
|
parse_opt_subcommand_fn *fn = NULL;
|
2009-03-26 04:55:54 +00:00
|
|
|
struct option options[] = {
|
2022-11-10 16:36:22 +00:00
|
|
|
OPT_SUBCOMMAND("reset", &fn, cmd_bisect__reset),
|
|
|
|
OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
|
|
|
|
OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
|
|
|
|
OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
|
|
|
|
OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
|
|
|
|
OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
|
|
|
|
OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
|
|
|
|
OPT_SUBCOMMAND("visualize", &fn, cmd_bisect__visualize),
|
|
|
|
OPT_SUBCOMMAND("view", &fn, cmd_bisect__visualize),
|
|
|
|
OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
|
2009-03-26 04:55:54 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
2022-11-10 16:36:44 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
|
|
|
|
PARSE_OPT_SUBCOMMAND_OPTIONAL);
|
|
|
|
|
|
|
|
if (!fn) {
|
|
|
|
struct bisect_terms terms = { 0 };
|
|
|
|
|
|
|
|
if (!argc)
|
|
|
|
usage_msg_opt(_("need a command"), git_bisect_usage, options);
|
|
|
|
|
|
|
|
set_terms(&terms, "bad", "good");
|
|
|
|
get_terms(&terms);
|
|
|
|
if (check_and_set_terms(&terms, argv[0]))
|
|
|
|
usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
|
|
|
|
options, argv[0]);
|
2023-01-12 15:19:10 +00:00
|
|
|
res = bisect_state(&terms, argc, argv);
|
2022-11-10 16:36:44 +00:00
|
|
|
free_terms(&terms);
|
|
|
|
} else {
|
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
res = fn(argc, argv, prefix);
|
|
|
|
}
|
2020-02-17 08:40:37 +00:00
|
|
|
|
2023-01-12 15:19:09 +00:00
|
|
|
return is_bisect_success(res) ? 0 : -res;
|
2009-03-26 04:55:54 +00:00
|
|
|
}
|