Skip to content

Commit

Permalink
Merge branch 'js/bisect-no-checkout'
Browse files Browse the repository at this point in the history
* js/bisect-no-checkout:
  bisect: add support for bisecting bare repositories
  bisect: further style nitpicks
  bisect: replace "; then" with "\n<tab>*then"
  bisect: cleanup whitespace errors in git-bisect.sh.
  bisect: add documentation for --no-checkout option.
  bisect: add tests for the --no-checkout option.
  bisect: introduce --no-checkout support into porcelain.
  bisect: introduce support for --no-checkout option.
  bisect: add tests to document expected behaviour in presence of broken trees.
  bisect: use && to connect statements that are deferred with eval.
  bisect: move argument parsing before state modification.
  • Loading branch information
Junio C Hamano committed Aug 18, 2011
2 parents ca01600 + 24c5128 commit da68bf3
Show file tree
Hide file tree
Showing 7 changed files with 430 additions and 178 deletions.
34 changes: 33 additions & 1 deletion Documentation/git-bisect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The command takes various subcommands, and different options depending
on the subcommand:

git bisect help
git bisect start [<bad> [<good>...]] [--] [<paths>...]
git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect bad [<rev>]
git bisect good [<rev>...]
git bisect skip [(<rev>|<range>)...]
Expand Down Expand Up @@ -263,6 +263,19 @@ rewind the tree to the pristine state. Finally the script should exit
with the status of the real test to let the "git bisect run" command loop
determine the eventual outcome of the bisect session.

OPTIONS
-------
--no-checkout::
+
Do not checkout the new working tree at each iteration of the bisection
process. Instead just update a special reference named 'BISECT_HEAD' to make
it point to the commit that should be tested.
+
This option may be useful when the test you would perform in each step
does not require a checked out tree.
+
If the repository is bare, `--no-checkout` is assumed.

EXAMPLES
--------

Expand Down Expand Up @@ -343,6 +356,25 @@ $ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
This shows that you can do without a run script if you write the test
on a single line.

* Locate a good region of the object graph in a damaged repository
+
------------
$ git bisect start HEAD <known-good-commit> [ <boundary-commit> ... ] --no-checkout
$ git bisect run sh -c '
GOOD=$(git for-each-ref "--format=%(objectname)" refs/bisect/good-*) &&
git rev-list --objects BISECT_HEAD --not $GOOD >tmp.$$ &&
git pack-objects --stdout >/dev/null <tmp.$$
rc=$?
rm -f tmp.$$
test $rc = 0'

------------
+
In this case, when 'git bisect run' finishes, bisect/bad will refer to a commit that
has at least one parent whose reachable graph is fully traversable in the sense
required by 'git pack objects'.


SEE ALSO
--------
link:git-bisect-lk2009.html[Fighting regressions with git bisect],
Expand Down
33 changes: 22 additions & 11 deletions bisect.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct argv_array {

static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
static const char *argv_update_ref[] = {"update-ref", "--no-deref", "BISECT_HEAD", NULL, NULL};

/* bits #0-15 in revision.h */

Expand Down Expand Up @@ -707,16 +708,23 @@ static void mark_expected_rev(char *bisect_rev_hex)
die("closing file %s: %s", filename, strerror(errno));
}

static int bisect_checkout(char *bisect_rev_hex)
static int bisect_checkout(char *bisect_rev_hex, int no_checkout)
{
int res;

mark_expected_rev(bisect_rev_hex);

argv_checkout[2] = bisect_rev_hex;
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
if (res)
exit(res);
if (no_checkout) {
argv_update_ref[3] = bisect_rev_hex;
if (run_command_v_opt(argv_update_ref, RUN_GIT_CMD))
die("update-ref --no-deref HEAD failed on %s",
bisect_rev_hex);
} else {
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
if (res)
exit(res);
}

argv_show_branch[1] = bisect_rev_hex;
return run_command_v_opt(argv_show_branch, RUN_GIT_CMD);
Expand Down Expand Up @@ -788,7 +796,7 @@ static void handle_skipped_merge_base(const unsigned char *mb)
* - If one is "skipped", we can't know but we should warn.
* - If we don't know, we should check it out and ask the user to test.
*/
static void check_merge_bases(void)
static void check_merge_bases(int no_checkout)
{
struct commit_list *result;
int rev_nr;
Expand All @@ -806,7 +814,7 @@ static void check_merge_bases(void)
handle_skipped_merge_base(mb);
} else {
printf("Bisecting: a merge base must be tested\n");
exit(bisect_checkout(sha1_to_hex(mb)));
exit(bisect_checkout(sha1_to_hex(mb), no_checkout));
}
}

Expand Down Expand Up @@ -849,7 +857,7 @@ static int check_ancestors(const char *prefix)
* If a merge base must be tested by the user, its source code will be
* checked out to be tested by the user and we will exit.
*/
static void check_good_are_ancestors_of_bad(const char *prefix)
static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
{
const char *filename = git_path("BISECT_ANCESTORS_OK");
struct stat st;
Expand All @@ -868,7 +876,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix)

/* Check if all good revs are ancestor of the bad rev. */
if (check_ancestors(prefix))
check_merge_bases();
check_merge_bases(no_checkout);

/* Create file BISECT_ANCESTORS_OK. */
fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
Expand Down Expand Up @@ -908,8 +916,11 @@ static void show_diff_tree(const char *prefix, struct commit *commit)
* We use the convention that exiting with an exit code 10 means that
* the bisection process finished successfully.
* In this case the calling shell script should exit 0.
*
* If no_checkout is non-zero, the bisection process does not
* checkout the trial commit but instead simply updates BISECT_HEAD.
*/
int bisect_next_all(const char *prefix)
int bisect_next_all(const char *prefix, int no_checkout)
{
struct rev_info revs;
struct commit_list *tried;
Expand All @@ -920,7 +931,7 @@ int bisect_next_all(const char *prefix)
if (read_bisect_refs())
die("reading bisect refs failed");

check_good_are_ancestors_of_bad(prefix);
check_good_are_ancestors_of_bad(prefix, no_checkout);

bisect_rev_setup(&revs, prefix, "%s", "^%s", 1);
revs.limited = 1;
Expand Down Expand Up @@ -966,6 +977,6 @@ int bisect_next_all(const char *prefix)
"(roughly %d step%s)\n", nr, (nr == 1 ? "" : "s"),
steps, (steps == 1 ? "" : "s"));

return bisect_checkout(bisect_rev_hex);
return bisect_checkout(bisect_rev_hex, no_checkout);
}

2 changes: 1 addition & 1 deletion bisect.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct rev_list_info {
const char *header_prefix;
};

extern int bisect_next_all(const char *prefix);
extern int bisect_next_all(const char *prefix, int no_checkout);

extern int estimate_bisect_steps(int all);

Expand Down
7 changes: 5 additions & 2 deletions builtin/bisect--helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
#include "bisect.h"

static const char * const git_bisect_helper_usage[] = {
"git bisect--helper --next-all",
"git bisect--helper --next-all [--no-checkout]",
NULL
};

int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
int next_all = 0;
int no_checkout = 0;
struct option options[] = {
OPT_BOOLEAN(0, "next-all", &next_all,
"perform 'git bisect next'"),
OPT_BOOLEAN(0, "no-checkout", &no_checkout,
"update BISECT_HEAD instead of checking out the current commit"),
OPT_END()
};

Expand All @@ -24,5 +27,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
usage_with_options(git_bisect_helper_usage, options);

/* next-all */
return bisect_next_all(prefix);
return bisect_next_all(prefix, no_checkout);
}
Loading

0 comments on commit da68bf3

Please sign in to comment.