提交 5bba1b35 编写于 作者: J Junio C Hamano

Merge branch 'cc/bisect'

* cc/bisect:
  git-bisect: allow bisecting with only one bad commit.
  t6030: add a bit more tests to git-bisect
  git-bisect: modernization
  Documentation: bisect: "start" accepts one bad and many good commits
  Bisect: teach "bisect start" to optionally use one bad and many good revs.
...@@ -15,7 +15,7 @@ DESCRIPTION ...@@ -15,7 +15,7 @@ DESCRIPTION
The command takes various subcommands, and different options depending The command takes various subcommands, and different options depending
on the subcommand: on the subcommand:
git bisect start [<paths>...] git bisect start [<bad> [<good>...]] [--] [<paths>...]
git bisect bad <rev> git bisect bad <rev>
git bisect good <rev> git bisect good <rev>
git bisect reset [<branch>] git bisect reset [<branch>]
...@@ -134,15 +134,26 @@ $ git reset --hard HEAD~3 # try 3 revs before what ...@@ -134,15 +134,26 @@ $ git reset --hard HEAD~3 # try 3 revs before what
Then compile and test the one you chose to try. After that, tell Then compile and test the one you chose to try. After that, tell
bisect what the result was as usual. bisect what the result was as usual.
Cutting down bisection by giving path parameter to bisect start Cutting down bisection by giving more parameters to bisect start
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can further cut down the number of trials if you know what part of You can further cut down the number of trials if you know what part of
the tree is involved in the problem you are tracking down, by giving the tree is involved in the problem you are tracking down, by giving
paths parameters when you say `bisect start`, like this: paths parameters when you say `bisect start`, like this:
------------ ------------
$ git bisect start arch/i386 include/asm-i386 $ git bisect start -- arch/i386 include/asm-i386
------------
If you know beforehand more than one good commits, you can narrow the
bisect space down without doing the whole tree checkout every time you
give good commits. You give the bad revision immediately after `start`
and then you give all the good revisions you have:
------------
$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
# v2.6.20-rc6 is bad
# v2.6.20-rc4 and v2.6.20-rc1 are good
------------ ------------
Bisect run Bisect run
......
#!/bin/sh #!/bin/sh
USAGE='[start|bad|good|next|reset|visualize|replay|log|run]' USAGE='[start|bad|good|next|reset|visualize|replay|log|run]'
LONG_USAGE='git bisect start [<pathspec>] reset bisect state and start bisection. LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
git bisect bad [<rev>] mark <rev> a known-bad revision. reset bisect state and start bisection.
git bisect good [<rev>...] mark <rev>... known-good revisions. git bisect bad [<rev>]
git bisect next find next bisection to test and check it out. mark <rev> a known-bad revision.
git bisect reset [<branch>] finish bisection search and go back to branch. git bisect good [<rev>...]
git bisect visualize show bisect status in gitk. mark <rev>... known-good revisions.
git bisect replay <logfile> replay bisection log. git bisect next
git bisect log show bisect log. find next bisection to test and check it out.
git bisect run <cmd>... use <cmd>... to automatically bisect.' git bisect reset [<branch>]
finish bisection search and go back to branch.
git bisect visualize
show bisect status in gitk.
git bisect replay <logfile>
replay bisection log.
git bisect log
show bisect log.
git bisect run <cmd>...
use <cmd>... to automatically bisect.'
. git-sh-setup . git-sh-setup
require_work_tree require_work_tree
...@@ -70,14 +79,48 @@ bisect_start() { ...@@ -70,14 +79,48 @@ bisect_start() {
# #
# Get rid of any old bisect state # Get rid of any old bisect state
# #
rm -f "$GIT_DIR/refs/heads/bisect" bisect_clean_state
rm -rf "$GIT_DIR/refs/bisect/"
mkdir "$GIT_DIR/refs/bisect" mkdir "$GIT_DIR/refs/bisect"
#
# Check for one bad and then some good revisions.
#
has_double_dash=0
for arg; do
case "$arg" in --) has_double_dash=1; break ;; esac
done
orig_args=$(sq "$@")
bad_seen=0
while [ $# -gt 0 ]; do
arg="$1"
case "$arg" in
--)
shift
break
;;
*)
rev=$(git-rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
test $has_double_dash -eq 1 &&
die "'$arg' does not appear to be a valid revision"
break
}
if [ $bad_seen -eq 0 ]; then
bad_seen=1
bisect_write_bad "$rev"
else
bisect_write_good "$rev"
fi
shift
;;
esac
done
sq "$@" >"$GIT_DIR/BISECT_NAMES"
{ {
printf "git-bisect start" printf "git-bisect start"
sq "$@" echo "$orig_args"
} >"$GIT_DIR/BISECT_LOG" } >>"$GIT_DIR/BISECT_LOG"
sq "$@" >"$GIT_DIR/BISECT_NAMES" bisect_auto_next
} }
bisect_bad() { bisect_bad() {
...@@ -90,12 +133,17 @@ bisect_bad() { ...@@ -90,12 +133,17 @@ bisect_bad() {
*) *)
usage ;; usage ;;
esac || exit esac || exit
echo "$rev" >"$GIT_DIR/refs/bisect/bad" bisect_write_bad "$rev"
echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG" echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
bisect_auto_next bisect_auto_next
} }
bisect_write_bad() {
rev="$1"
echo "$rev" >"$GIT_DIR/refs/bisect/bad"
echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
}
bisect_good() { bisect_good() {
bisect_autostart bisect_autostart
case "$#" in case "$#" in
...@@ -106,35 +154,54 @@ bisect_good() { ...@@ -106,35 +154,54 @@ bisect_good() {
for rev in $revs for rev in $revs
do do
rev=$(git-rev-parse --verify "$rev^{commit}") || exit rev=$(git-rev-parse --verify "$rev^{commit}") || exit
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev" bisect_write_good "$rev"
echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG" echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
done done
bisect_auto_next bisect_auto_next
} }
bisect_write_good() {
rev="$1"
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
}
bisect_next_check() { bisect_next_check() {
next_ok=no missing_good= missing_bad=
test -f "$GIT_DIR/refs/bisect/bad" && git show-ref -q --verify refs/bisect/bad || missing_bad=t
case "$(cd "$GIT_DIR" && echo refs/bisect/good-*)" in test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
refs/bisect/good-\*) ;;
*) next_ok=yes ;; case "$missing_good,$missing_bad,$1" in
esac ,,*)
case "$next_ok,$1" in : have both good and bad - ok
no,) false ;; ;;
no,fail) *,)
THEN='' # do not have both but not asked to fail - just report.
test -d "$GIT_DIR/refs/bisect" || { false
echo >&2 'You need to start by "git bisect start".' ;;
THEN='then ' t,,good)
} # have bad but not good. we could bisect although
echo >&2 'You '$THEN'need to give me at least one good' \ # this is less optimum.
'and one bad revisions.' echo >&2 'Warning: bisecting only with a bad commit.'
echo >&2 '(You can use "git bisect bad" and' \ if test -t 0
'"git bisect good" for that.)' then
exit 1 ;; printf >&2 'Are you sure [Y/n]? '
case "$(read yesno)" in [Nn]*) exit 1 ;; esac
fi
: bisect without good...
;;
*) *)
true ;; THEN=''
test -d "$GIT_DIR/refs/bisect" || {
echo >&2 'You need to start by "git bisect start".'
THEN='then '
}
echo >&2 'You '$THEN'need to give me at least one good' \
'and one bad revisions.'
echo >&2 '(You can use "git bisect bad" and' \
'"git bisect good" for that.)'
exit 1 ;;
esac esac
} }
...@@ -145,27 +212,32 @@ bisect_auto_next() { ...@@ -145,27 +212,32 @@ bisect_auto_next() {
bisect_next() { bisect_next() {
case "$#" in 0) ;; *) usage ;; esac case "$#" in 0) ;; *) usage ;; esac
bisect_autostart bisect_autostart
bisect_next_check fail bisect_next_check good
bad=$(git-rev-parse --verify refs/bisect/bad) && bad=$(git-rev-parse --verify refs/bisect/bad) &&
good=$(git-rev-parse --sq --revs-only --not \ good=$(git for-each-ref --format='^%(objectname)' \
$(cd "$GIT_DIR" && ls refs/bisect/good-*)) && "refs/bisect/good-*" | tr '[\012]' ' ') &&
rev=$(eval "git-rev-list --bisect $good $bad -- $(cat "$GIT_DIR/BISECT_NAMES")") || exit eval="git-rev-list --bisect-vars $good $bad --" &&
if [ -z "$rev" ]; then eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" &&
echo "$bad was both good and bad" eval=$(eval "$eval") &&
exit 1 eval "$eval" || exit
if [ -z "$bisect_rev" ]; then
echo "$bad was both good and bad"
exit 1
fi fi
if [ "$rev" = "$bad" ]; then if [ "$bisect_rev" = "$bad" ]; then
echo "$rev is first bad commit" echo "$bisect_rev is first bad commit"
git-diff-tree --pretty $rev git-diff-tree --pretty $bisect_rev
exit 0 exit 0
fi fi
nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
echo "Bisecting: $nr revisions left to test after this" echo "Bisecting: $bisect_nr revisions left to test after this"
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect" echo "$bisect_rev" >"$GIT_DIR/refs/heads/new-bisect"
git checkout -q new-bisect || exit git checkout -q new-bisect || exit
mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" && mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
git-show-branch "$rev" git-show-branch "$bisect_rev"
} }
bisect_visualize() { bisect_visualize() {
...@@ -190,14 +262,19 @@ bisect_reset() { ...@@ -190,14 +262,19 @@ bisect_reset() {
usage ;; usage ;;
esac esac
if git checkout "$branch"; then if git checkout "$branch"; then
rm -fr "$GIT_DIR/refs/bisect" rm -f "$GIT_DIR/head-name"
rm -f "$GIT_DIR/refs/heads/bisect" "$GIT_DIR/head-name" bisect_clean_state
rm -f "$GIT_DIR/BISECT_LOG"
rm -f "$GIT_DIR/BISECT_NAMES"
rm -f "$GIT_DIR/BISECT_RUN"
fi fi
} }
bisect_clean_state() {
rm -fr "$GIT_DIR/refs/bisect"
rm -f "$GIT_DIR/refs/heads/bisect"
rm -f "$GIT_DIR/BISECT_LOG"
rm -f "$GIT_DIR/BISECT_NAMES"
rm -f "$GIT_DIR/BISECT_RUN"
}
bisect_replay () { bisect_replay () {
test -r "$1" || { test -r "$1" || {
echo >&2 "cannot read $1 for replaying" echo >&2 "cannot read $1 for replaying"
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
# #
# Copyright (c) 2007 Christian Couder # Copyright (c) 2007 Christian Couder
# #
test_description='Tests git-bisect run functionality' test_description='Tests git-bisect functionality'
exec </dev/null
. ./test-lib.sh . ./test-lib.sh
...@@ -37,11 +39,40 @@ test_expect_success \ ...@@ -37,11 +39,40 @@ test_expect_success \
HASH3=$(git rev-list HEAD | head -2 | tail -1) && HASH3=$(git rev-list HEAD | head -2 | tail -1) &&
HASH4=$(git rev-list HEAD | head -1)' HASH4=$(git rev-list HEAD | head -1)'
test_expect_success 'bisect starts with only one bad' '
git bisect reset &&
git bisect start &&
git bisect bad $HASH4 &&
git bisect next
'
test_expect_success 'bisect starts with only one good' '
git bisect reset &&
git bisect start &&
git bisect good $HASH1 || return 1
if git bisect next
then
echo Oops, should have failed.
false
else
:
fi
'
test_expect_success 'bisect start with one bad and good' '
git bisect reset &&
git bisect start &&
git bisect good $HASH1 &&
git bisect bad $HASH4 &&
git bisect next
'
# We want to automatically find the commit that # We want to automatically find the commit that
# introduced "Another" into hello. # introduced "Another" into hello.
test_expect_success \ test_expect_success \
'git bisect run simple case' \ '"git bisect run" simple case' \
'echo "#!/bin/sh" > test_script.sh && 'echo "#"\!"/bin/sh" > test_script.sh &&
echo "grep Another hello > /dev/null" >> test_script.sh && echo "grep Another hello > /dev/null" >> test_script.sh &&
echo "test \$? -ne 0" >> test_script.sh && echo "test \$? -ne 0" >> test_script.sh &&
chmod +x test_script.sh && chmod +x test_script.sh &&
...@@ -49,7 +80,21 @@ test_expect_success \ ...@@ -49,7 +80,21 @@ test_expect_success \
git bisect good $HASH1 && git bisect good $HASH1 &&
git bisect bad $HASH4 && git bisect bad $HASH4 &&
git bisect run ./test_script.sh > my_bisect_log.txt && git bisect run ./test_script.sh > my_bisect_log.txt &&
grep "$HASH3 is first bad commit" my_bisect_log.txt' grep "$HASH3 is first bad commit" my_bisect_log.txt &&
git bisect reset'
# We want to automatically find the commit that
# introduced "Ciao" into hello.
test_expect_success \
'"git bisect run" with more complex "git bisect start"' \
'echo "#"\!"/bin/sh" > test_script.sh &&
echo "grep Ciao hello > /dev/null" >> test_script.sh &&
echo "test \$? -ne 0" >> test_script.sh &&
chmod +x test_script.sh &&
git bisect start $HASH4 $HASH1 &&
git bisect run ./test_script.sh > my_bisect_log.txt &&
grep "$HASH4 is first bad commit" my_bisect_log.txt &&
git bisect reset'
# #
# #
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册