Code

format-patch: pretty-print timestamp correctly.
[git.git] / git-bisect.sh
1 #!/bin/sh
3 USAGE='[start|bad|good|next|reset|visualize]'
4 LONG_USAGE='git bisect start [<pathspec>]       reset bisect state and start bisection.
5 git bisect bad [<rev>]          mark <rev> a known-bad revision.
6 git bisect good [<rev>...]      mark <rev>... known-good revisions.
7 git bisect next                 find next bisection to test and check it out.
8 git bisect reset [<branch>]     finish bisection search and go back to branch.
9 git bisect visualize            show bisect status in gitk.
10 git bisect replay <logfile>     replay bisection log
11 git bisect log                  show bisect log.'
13 . git-sh-setup
15 sq() {
16         perl -e '
17                 for (@ARGV) {
18                         s/'\''/'\'\\\\\'\''/g;
19                         print " '\''$_'\''";
20                 }
21                 print "\n";
22         ' "$@"
23 }
25 bisect_autostart() {
26         test -d "$GIT_DIR/refs/bisect" || {
27                 echo >&2 'You need to start by "git bisect start"'
28                 if test -t 0
29                 then
30                         echo >&2 -n 'Do you want me to do it for you [Y/n]? '
31                         read yesno
32                         case "$yesno" in
33                         [Nn]*)
34                                 exit ;;
35                         esac
36                         bisect_start
37                 else
38                         exit 1
39                 fi
40         }
41 }
43 bisect_start() {
44         #
45         # Verify HEAD. If we were bisecting before this, reset to the
46         # top-of-line master first!
47         #
48         head=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD) ||
49         die "Bad HEAD - I need a symbolic ref"
50         case "$head" in
51         refs/heads/bisect*)
52                 git checkout master || exit
53                 ;;
54         refs/heads/*)
55                 ;;
56         *)
57                 die "Bad HEAD - strange symbolic ref"
58                 ;;
59         esac
61         #
62         # Get rid of any old bisect state
63         #
64         rm -f "$GIT_DIR/refs/heads/bisect"
65         rm -rf "$GIT_DIR/refs/bisect/"
66         mkdir "$GIT_DIR/refs/bisect"
67         {
68             printf "git-bisect start"
69             sq "$@"
70         } >"$GIT_DIR/BISECT_LOG"
71         sq "$@" >"$GIT_DIR/BISECT_NAMES"
72 }
74 bisect_bad() {
75         bisect_autostart
76         case "$#" in
77         0)
78                 rev=$(git-rev-parse --verify HEAD) ;;
79         1)
80                 rev=$(git-rev-parse --verify "$1") ;;
81         *)
82                 usage ;;
83         esac || exit
84         echo "$rev" >"$GIT_DIR/refs/bisect/bad"
85         echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
86         echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
87         bisect_auto_next
88 }
90 bisect_good() {
91         bisect_autostart
92         case "$#" in
93         0)    revs=$(git-rev-parse --verify HEAD) || exit ;;
94         *)    revs=$(git-rev-parse --revs-only --no-flags "$@") &&
95                 test '' != "$revs" || die "Bad rev input: $@" ;;
96         esac
97         for rev in $revs
98         do
99                 rev=$(git-rev-parse --verify "$rev") || exit
100                 echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
101                 echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
102                 echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
103         done
104         bisect_auto_next
107 bisect_next_check() {
108         next_ok=no
109         test -f "$GIT_DIR/refs/bisect/bad" &&
110         case "$(cd "$GIT_DIR" && echo refs/bisect/good-*)" in
111         refs/bisect/good-\*) ;;
112         *) next_ok=yes ;;
113         esac
114         case "$next_ok,$1" in
115         no,) false ;;
116         no,fail)
117             echo >&2 'You need to give me at least one good and one bad revisions.'
118             exit 1 ;;
119         *)
120             true ;;
121         esac
124 bisect_auto_next() {
125         bisect_next_check && bisect_next || :
128 bisect_next() {
129         case "$#" in 0) ;; *) usage ;; esac
130         bisect_autostart
131         bisect_next_check fail
132         bad=$(git-rev-parse --verify refs/bisect/bad) &&
133         good=$(git-rev-parse --sq --revs-only --not \
134                 $(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
135         rev=$(eval "git-rev-list --bisect $good $bad -- $(cat $GIT_DIR/BISECT_NAMES)") || exit
136         if [ -z "$rev" ]; then
137             echo "$bad was both good and bad"
138             exit 1
139         fi
140         if [ "$rev" = "$bad" ]; then
141             echo "$rev is first bad commit"
142             git-diff-tree --pretty $rev
143             exit 0
144         fi
145         nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
146         echo "Bisecting: $nr revisions left to test after this"
147         echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
148         git checkout new-bisect || exit
149         mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
150         GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
151         git-show-branch "$rev"
154 bisect_visualize() {
155         bisect_next_check fail
156         not=`cd "$GIT_DIR/refs" && echo bisect/good-*`
157         eval gitk bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
160 bisect_reset() {
161         case "$#" in
162         0) branch=master ;;
163         1) test -f "$GIT_DIR/refs/heads/$1" || {
164                echo >&2 "$1 does not seem to be a valid branch"
165                exit 1
166            }
167            branch="$1" ;;
168         *)
169             usage ;;
170         esac
171         git checkout "$branch" &&
172         rm -fr "$GIT_DIR/refs/bisect"
173         rm -f "$GIT_DIR/refs/heads/bisect"
174         rm -f "$GIT_DIR/BISECT_LOG"
175         rm -f "$GIT_DIR/BISECT_NAMES"
178 bisect_replay () {
179         test -r "$1" || {
180                 echo >&2 "cannot read $1 for replaying"
181                 exit 1
182         }
183         bisect_reset
184         while read bisect command rev
185         do
186                 test "$bisect" = "git-bisect" || continue
187                 case "$command" in
188                 start)
189                         cmd="bisect_start $rev"
190                         eval "$cmd"
191                         ;;
192                 good)
193                         echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
194                         echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
195                         echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
196                         ;;
197                 bad)
198                         echo "$rev" >"$GIT_DIR/refs/bisect/bad"
199                         echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
200                         echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
201                         ;;
202                 *)
203                         echo >&2 "?? what are you talking about?"
204                         exit 1 ;;
205                 esac
206         done <"$1"
207         bisect_auto_next
210 case "$#" in
211 0)
212     usage ;;
213 *)
214     cmd="$1"
215     shift
216     case "$cmd" in
217     start)
218         bisect_start "$@" ;;
219     bad)
220         bisect_bad "$@" ;;
221     good)
222         bisect_good "$@" ;;
223     next)
224         # Not sure we want "next" at the UI level anymore.
225         bisect_next "$@" ;;
226     visualize)
227         bisect_visualize "$@" ;;
228     reset)
229         bisect_reset "$@" ;;
230     replay)
231         bisect_replay "$@" ;;
232     log)
233         cat "$GIT_DIR/BISECT_LOG" ;;
234     *)
235         usage ;;
236     esac
237 esac