ae2b0f1518
Now all the users of this script detect its exit status and die, complaining that it is outside git repository. So move the code that dies from all callers to git-sh-setup script. Signed-off-by: Junio C Hamano <junkio@cox.net>
224 lines
5.1 KiB
Bash
Executable File
224 lines
5.1 KiB
Bash
Executable File
#!/bin/sh
|
|
. git-sh-setup
|
|
|
|
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=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD) ||
|
|
die "Bad HEAD - I need a symbolic ref"
|
|
case "$head" in
|
|
refs/heads/bisect*)
|
|
git checkout master || exit
|
|
;;
|
|
refs/heads/*)
|
|
;;
|
|
*)
|
|
die "Bad HEAD - strange symbolic ref"
|
|
;;
|
|
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" &&
|
|
GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
|
|
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
|