git-commit-vandalism/git-bisect.sh
Junio C Hamano 434d036fe4 Do not fail after calling bisect_auto_next()
As a convenience measure, 'bisect bad' or 'bisect good' automatically
does 'bisect next' when it knows it can, but the result of that test
to see if it can was leaking through as the exit code from the whole
thing, which was bad.  Noticed by Anton Blanchard.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-09-17 13:51:03 -07:00

223 lines
5.1 KiB
Bash
Executable File

#!/bin/sh
. git-sh-setup || dir "Not a git archive"
usage() {
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
git bisect start 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 next find next bisection to test and check it out.
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.'
exit 1
}
bisect_autostart() {
test -d "$GIT_DIR/refs/bisect" || {
echo >&2 'You need to start by "git bisect start"'
if test -t 0
then
echo >&2 -n 'Do you want me to do it for you [Y/n]? '
read yesno
case "$yesno" in
[Nn]*)
exit ;;
esac
bisect_start
else
exit 1
fi
}
}
bisect_start() {
case "$#" in 0) ;; *) usage ;; esac
#
# Verify HEAD. If we were bisecting before this, reset to the
# top-of-line master first!
#
head=$(readlink $GIT_DIR/HEAD) || die "Bad HEAD - I need a symlink"
case "$head" in
refs/heads/bisect*)
git checkout master || exit
;;
refs/heads/*)
;;
*)
die "Bad HEAD - strange symlink"
;;
esac
#
# Get rid of any old bisect state
#
rm -f "$GIT_DIR/refs/heads/bisect"
rm -rf "$GIT_DIR/refs/bisect/"
mkdir "$GIT_DIR/refs/bisect"
echo "git-bisect start" >"$GIT_DIR/BISECT_LOG"
}
bisect_bad() {
bisect_autostart
case "$#" in
0)
rev=$(git-rev-parse --verify HEAD) ;;
1)
rev=$(git-rev-parse --verify "$1") ;;
*)
usage ;;
esac || exit
echo "$rev" >"$GIT_DIR/refs/bisect/bad"
echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
bisect_auto_next
}
bisect_good() {
bisect_autostart
case "$#" in
0) revs=$(git-rev-parse --verify HEAD) || exit ;;
*) revs=$(git-rev-parse --revs-only --no-flags "$@") &&
test '' != "$revs" || die "Bad rev input: $@" ;;
esac
for rev in $revs
do
rev=$(git-rev-parse --verify "$rev") || exit
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
done
bisect_auto_next
}
bisect_next_check() {
next_ok=no
test -f "$GIT_DIR/refs/bisect/bad" &&
case "$(cd "$GIT_DIR" && echo refs/bisect/good-*)" in
refs/bisect/good-\*) ;;
*) next_ok=yes ;;
esac
case "$next_ok,$1" in
no,) false ;;
no,fail)
echo >&2 'You need to give me at least one good and one bad revisions.'
exit 1 ;;
*)
true ;;
esac
}
bisect_auto_next() {
bisect_next_check && bisect_next || :
}
bisect_next() {
case "$#" in 0) ;; *) usage ;; esac
bisect_autostart
bisect_next_check fail
bad=$(git-rev-parse --verify refs/bisect/bad) &&
good=$(git-rev-parse --sq --revs-only --not \
$(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
rev=$(eval "git-rev-list --bisect $good $bad") || exit
if [ -z "$rev" ]; then
echo "$bad was both good and bad"
exit 1
fi
if [ "$rev" = "$bad" ]; then
echo "$rev is first bad commit"
git-diff-tree --pretty $rev
exit 0
fi
nr=$(eval "git-rev-list $rev $good" | wc -l) || exit
echo "Bisecting: $nr revisions left to test after this"
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
git checkout new-bisect || exit
mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
ln -sf refs/heads/bisect "$GIT_DIR/HEAD"
git-show-branch "$rev"
}
bisect_visualize() {
bisect_next_check fail
gitk bisect/bad --not `cd "$GIT_DIR/refs" && echo bisect/good-*`
}
bisect_reset() {
case "$#" in
0) branch=master ;;
1) test -f "$GIT_DIR/refs/heads/$1" || {
echo >&2 "$1 does not seem to be a valid branch"
exit 1
}
branch="$1" ;;
*)
usage ;;
esac
git checkout "$branch" &&
rm -fr "$GIT_DIR/refs/bisect"
rm -f "$GIT_DIR/refs/heads/bisect"
rm -f "$GIT_DIR/BISECT_LOG"
}
bisect_replay () {
test -r "$1" || {
echo >&2 "cannot read $1 for replaying"
exit 1
}
bisect_reset
while read bisect command rev
do
test "$bisect" = "git-bisect" || continue
case "$command" in
start)
bisect_start
;;
good)
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
;;
bad)
echo "$rev" >"$GIT_DIR/refs/bisect/bad"
echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
;;
*)
echo >&2 "?? what are you talking about?"
exit 1 ;;
esac
done <"$1"
bisect_auto_next
}
case "$#" in
0)
usage ;;
*)
cmd="$1"
shift
case "$cmd" in
start)
bisect_start "$@" ;;
bad)
bisect_bad "$@" ;;
good)
bisect_good "$@" ;;
next)
# Not sure we want "next" at the UI level anymore.
bisect_next "$@" ;;
visualize)
bisect_visualize "$@" ;;
reset)
bisect_reset "$@" ;;
replay)
bisect_replay "$@" ;;
log)
cat "$GIT_DIR/BISECT_LOG" ;;
*)
usage ;;
esac
esac