1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
| | HOW TO USE GIT BISECT TO PINPOINT EMACS BUGS -*- outline -*-
This documents explains how to use git bisect to find the commit that
introduced an Emacs bug. Bisecting works best if the bug is easy and
relatively quick to reproduce in a clean ‘emacs -Q’ instance.
For general information about bisecting, use ‘M-x man git-bisect’.
This document contains quick-start instructions and Emacs-specific
tips.
* Bisecting Emacs bugs
First, find a recipe that reproduces the bug in emacs -Q. Then use
this recipe to locate a revision in which the bug doesn't happen. If
it's a new bug, a not-too-recent revision could do; otherwise,
checking for the bug previous releases of Emacs works well.
Then, run the following command to start bisecting
git bisect start <buggy-revision> <good-revision>
<buggy-revision> is usually HEAD in practice.
Git will then check out revisions between these two bounds,; at each
step, you need to run ‘git bisect good’ or ‘git bisect bad’ to inform
git of the status of the current revision: ‘bad’ if it has the bug;
good if it doesn't.
If Emacs' build is broken in the current revision, use ‘git bisect
skip’ to move to a neighboring revision.
** Automating ‘git bisect’
You can also write ‘git bisect run <some-shell-script>’ to automate
the process. ‘<some-shell-script>’ should build Emacs, run your bug
reproduction test, and return 0 if the current revision is good, and 1
otherwise. Returning 125 is equivalent to doing ‘git bisect skip’.
Concretely, ‘<some-shell-script>’ usually looks like this:
#!/usr/bin/env bash
# Remove leftovers from previous runs
git clean -xfd > /dev/null
# Build Emacs and skip commit if build fails
(./autogen.sh && ./configure --cache-file=/tmp/emacs.config.cache && make -j4) || exit 125
# Reproduce the bug, writing output somewhere
src/emacs -Q -l "../reproduce-the-bug.el" || exit 125
# Remove leftovers again
git clean -xfd > /dev/null
# Analyze output and produce exit code
cmp ../reference-output current-output
Some caveats:
- This script cleans Emacs' source directory with ‘git clean -xfd’, so
make sure your uncommitted changes are saved somewhere else.
- You should produce the ‘../reproduce-your-bug.el’ script on your own
(it should check if the bug exists, and save a different output to a
file named ‘current-output’ based on the result of that check), as
well as a file ‘../reference-output’ containing the expected output
in the good case.
** Using ‘git bisect’ to find display-related bugs
Most bugs that manifest graphically can be checked for by
programmatically inspecting text properties, but some are only
apparent through visual inspection. Since building Emacs takes a long
time, it can be a pain to debug these manually.
Fortunately, it's relatively easy to bisect such bugs automatically.
Use the following template for ‘../reproduce-the-bug.el’:
(defun take-screenshot-and-exit (fname x y w h)
"Save a screenshot of Emacs as FNAME, then exit.
X and Y are the coordinates of the top-left point of the area of interest.
W, and H are its dimensions."
(let ((window-id (frame-parameter nil 'outer-window-id)))
(call-process "xwd" nil nil nil "-silent" "-id" window-id "-out" fname))
(call-process "mogrify" nil nil nil fname "-crop" (format "%dx%d+%d+%d" w h x y))
(kill-emacs))
(defun main ()
;; Reproduce your bug here
…
;; Force a redisplay
(redisplay t)
;; Insert rough X, Y, W, H values below
(run-with-timer 0 nil #'take-screenshot-and-exit "screenshot.xwd" … … … …))
(main)
This script makes a screenshot of Emacs after reproducing your bug (if
‘xwd’ isn't available, you can use ImageMagick's ‘import’ tool,
passing it a ‘-window’ argument where ‘xwd’ wants ‘id’). Cropping the
image is useful to weed out unrelated display changes; try to include
only a small portion of the screen containing your bug.
Then to produce the right exit code use ImageMagick's ‘identify’ tool:
cmp <(identify -quiet -format "%#" "../screenshot.xwd") <(identify -quiet -format "%#" "../good.xwd")
‘good.xwd’ should be the image produced by your script in the good state.
|