Skip to content

Commit

Permalink
bisect: add the terms old/new
Browse files Browse the repository at this point in the history
When not looking for a regression during a bisect but for a fix or a
change in another given property, it can be confusing to use 'good'
and 'bad'.

This patch introduce `git bisect new` and `git bisect old` as an
alternative to 'bad' and good': the commits which have a certain
property must be marked as `new` and the ones which do not as `old`.

The output will be the first commit after the change in the property.
During a new/old bisect session you cannot use bad/good commands and
vice-versa.

Some commands are still not available for old/new:
     * git rev-list --bisect does not treat the revs/bisect/new and
       revs/bisect/old-SHA1 files.

Old discussions:
	- http://thread.gmane.org/gmane.comp.version-control.git/86063
		introduced bisect fix unfixed to find fix.
	- http://thread.gmane.org/gmane.comp.version-control.git/182398
		discussion around bisect yes/no or old/new.
	- http://thread.gmane.org/gmane.comp.version-control.git/199758
		last discussion and reviews
New discussions:
	- http://thread.gmane.org/gmane.comp.version-control.git/271320
		( v2 1/7-4/7 )
	- http://comments.gmane.org/gmane.comp.version-control.git/271343
		( v2 5/7-7/7 )

Signed-off-by: Antoine Delaite <[email protected]>
Signed-off-by: Louis Stuber <[email protected]>
Signed-off-by: Valentin Duperray <[email protected]>
Signed-off-by: Franck Jonas <[email protected]>
Signed-off-by: Lucien Kong <[email protected]>
Signed-off-by: Thomas Nguy <[email protected]>
Signed-off-by: Huynh Khoi Nguyen Nguyen <[email protected]>
Signed-off-by: Matthieu Moy <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
CanardChouChinois authored and gitster committed Aug 3, 2015
1 parent fe67687 commit 21e5cfd
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 14 deletions.
58 changes: 56 additions & 2 deletions Documentation/git-bisect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ The command takes various subcommands, and different options depending
on the subcommand:

git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect bad [<rev>]
git bisect good [<rev>...]
git bisect (bad|new) [<rev>]
git bisect (good|old) [<rev>...]
git bisect skip [(<rev>|<range>)...]
git bisect reset [<commit>]
git bisect visualize
Expand All @@ -36,6 +36,13 @@ whether the selected commit is "good" or "bad". It continues narrowing
down the range until it finds the exact commit that introduced the
change.

In fact, `git bisect` can be used to find the commit that changed
*any* property of your project; e.g., the commit that fixed a bug, or
the commit that caused a benchmark's performance to improve. To
support this more general usage, the terms "old" and "new" can be used
in place of "good" and "bad". See
section "Alternate terms" below for more information.

Basic bisect commands: start, bad, good
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -111,6 +118,45 @@ bad revision, while `git bisect reset HEAD` will leave you on the
current bisection commit and avoid switching commits at all.


Alternate terms
~~~~~~~~~~~~~~~

Sometimes you are not looking for the commit that introduced a
breakage, but rather for a commit that caused a change between some
other "old" state and "new" state. For example, you might be looking
for the commit that introduced a particular fix. Or you might be
looking for the first commit in which the source-code filenames were
finally all converted to your company's naming standard. Or whatever.

In such cases it can be very confusing to use the terms "good" and
"bad" to refer to "the state before the change" and "the state after
the change". So instead, you can use the terms "old" and "new",
respectively, in place of "good" and "bad". (But note that you cannot
mix "good" and "bad" with "old" and "new" in a single session.)

In this more general usage, you provide `git bisect` with a "new"
commit has some property and an "old" commit that doesn't have that
property. Each time `git bisect` checks out a commit, you test if that
commit has the property. If it does, mark the commit as "new";
otherwise, mark it as "old". When the bisection is done, `git bisect`
will report which commit introduced the property.

To use "old" and "new" instead of "good" and bad, you must run `git
bisect start` without commits as argument and then run the following
commands to add the commits:

------------------------------------------------
git bisect old [<rev>]
------------------------------------------------

to indicate that a commit was before the sought change, or

------------------------------------------------
git bisect new [<rev>...]
------------------------------------------------

to indicate that it was after.

Bisect visualize
~~~~~~~~~~~~~~~~

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

* Look for a fix instead of a regression in the code
+
------------
$ git bisect start
$ git bisect new HEAD # current commit is marked as new
$ git bisect old HEAD~10 # the tenth commit from now is marked as old
------------

Getting help
~~~~~~~~~~~~

Expand Down
11 changes: 8 additions & 3 deletions bisect.c
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,11 @@ static void handle_bad_merge_base(void)
"This means the bug has been fixed "
"between %s and [%s].\n",
bad_hex, bad_hex, good_hex);
} else if (!strcmp(term_bad, "new") && !strcmp(term_good, "old")) {
fprintf(stderr, "The merge base %s is new.\n"
"The property has changed "
"between %s and [%s].\n",
bad_hex, bad_hex, good_hex);
} else {
fprintf(stderr, "The merge base %s is %s.\n"
"This means the first '%s' commit is "
Expand Down Expand Up @@ -778,11 +783,11 @@ static void handle_skipped_merge_base(const unsigned char *mb)
}

/*
* "check_merge_bases" checks that merge bases are not "bad".
* "check_merge_bases" checks that merge bases are not "bad" (or "new").
*
* - If one is "bad", it means the user assumed something wrong
* - If one is "bad" (or "new"), it means the user assumed something wrong
* and we must exit with a non 0 error code.
* - If one is "good", that's good, we have nothing to do.
* - If one is "good" (or "old"), that's good, we have nothing to do.
* - 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.
*/
Expand Down
26 changes: 17 additions & 9 deletions git-bisect.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#!/bin/sh

USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
USAGE='[help|start|bad|good|new|old|skip|next|reset|visualize|replay|log|run]'
LONG_USAGE='git bisect help
print this long help message.
git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
reset bisect state and start bisection.
git bisect bad [<rev>]
mark <rev> a known-bad revision.
git bisect good [<rev>...]
mark <rev>... known-good revisions.
git bisect (bad|new) [<rev>]
mark <rev> a known-bad revision/
a revision after change in a given property.
git bisect (good|old) [<rev>...]
mark <rev>... known-good revisions/
revisions before change in a given property.
git bisect skip [(<rev>|<range>)...]
mark <rev>... untestable revisions.
git bisect next
Expand Down Expand Up @@ -294,7 +296,7 @@ bisect_next_check() {
false
;;
t,,"$TERM_GOOD")
# have bad but not good. we could bisect although
# have bad (or new) but not good (or old). we could bisect although
# this is less optimum.
eval_gettextln "Warning: bisecting only with a \$TERM_BAD commit." >&2
if test -t 0
Expand Down Expand Up @@ -587,14 +589,20 @@ check_and_set_terms () {
write_terms bad good
fi
;;
new|old)
if ! test -s "$GIT_DIR/BISECT_TERMS"
then
write_terms new old
fi
;;
esac ;;
esac
}

bisect_voc () {
case "$1" in
bad) echo "bad" ;;
good) echo "good" ;;
bad) echo "bad|new" ;;
good) echo "good|old" ;;
esac
}

Expand All @@ -610,7 +618,7 @@ case "$#" in
git bisect -h ;;
start)
bisect_start "$@" ;;
bad|good|"$TERM_BAD"|"$TERM_GOOD")
bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
bisect_state "$cmd" "$@" ;;
skip)
bisect_skip "$@" ;;
Expand Down
38 changes: 38 additions & 0 deletions t/t6030-bisect-porcelain.sh
Original file line number Diff line number Diff line change
Expand Up @@ -759,4 +759,42 @@ test_expect_success '"git bisect bad HEAD" behaves as "git bisect bad"' '
git bisect reset
'

test_expect_success 'bisect starts with only one new' '
git bisect reset &&
git bisect start &&
git bisect new $HASH4 &&
git bisect next
'

test_expect_success 'bisect does not start with only one old' '
git bisect reset &&
git bisect start &&
git bisect old $HASH1 &&
test_must_fail git bisect next
'

test_expect_success 'bisect start with one new and old' '
git bisect reset &&
git bisect start &&
git bisect old $HASH1 &&
git bisect new $HASH4 &&
git bisect new &&
git bisect new >bisect_result &&
grep "$HASH2 is the first new commit" bisect_result &&
git bisect log >log_to_replay.txt &&
git bisect reset
'

test_expect_success 'bisect replay with old and new' '
git bisect replay log_to_replay.txt >bisect_result &&
grep "$HASH2 is the first new commit" bisect_result &&
git bisect reset
'

test_expect_success 'bisect cannot mix old/new and good/bad' '
git bisect start &&
git bisect bad $HASH4 &&
test_must_fail git bisect old $HASH1
'

test_done

0 comments on commit 21e5cfd

Please sign in to comment.