summaryrefslogtreecommitdiffstats
path: root/git-bisect-lk2009.html
blob: 4e6d340cf96a29e63be7344163a4ab88459291ab (plain)
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<meta name="generator" content="AsciiDoc 10.2.0" />
<title>Fighting regressions with git bisect</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */

/* Default font. */
body {
  font-family: Georgia,serif;
}

/* Title font. */
h1, h2, h3, h4, h5, h6,
div.title, caption.title,
thead, p.table.header,
#toctitle,
#author, #revnumber, #revdate, #revremark,
#footer {
  font-family: Arial,Helvetica,sans-serif;
}

body {
  margin: 1em 5% 1em 5%;
}

a {
  color: blue;
  text-decoration: underline;
}
a:visited {
  color: fuchsia;
}

em {
  font-style: italic;
  color: navy;
}

strong {
  font-weight: bold;
  color: #083194;
}

h1, h2, h3, h4, h5, h6 {
  color: #527bbd;
  margin-top: 1.2em;
  margin-bottom: 0.5em;
  line-height: 1.3;
}

h1, h2, h3 {
  border-bottom: 2px solid silver;
}
h2 {
  padding-top: 0.5em;
}
h3 {
  float: left;
}
h3 + * {
  clear: left;
}
h5 {
  font-size: 1.0em;
}

div.sectionbody {
  margin-left: 0;
}

hr {
  border: 1px solid silver;
}

p {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

ul, ol, li > p {
  margin-top: 0;
}
ul > li     { color: #aaa; }
ul > li > * { color: black; }

.monospaced, code, pre {
  font-family: "Courier New", Courier, monospace;
  font-size: inherit;
  color: navy;
  padding: 0;
  margin: 0;
}
pre {
  white-space: pre-wrap;
}

#author {
  color: #527bbd;
  font-weight: bold;
  font-size: 1.1em;
}
#email {
}
#revnumber, #revdate, #revremark {
}

#footer {
  font-size: small;
  border-top: 2px solid silver;
  padding-top: 0.5em;
  margin-top: 4.0em;
}
#footer-text {
  float: left;
  padding-bottom: 0.5em;
}
#footer-badges {
  float: right;
  padding-bottom: 0.5em;
}

#preamble {
  margin-top: 1.5em;
  margin-bottom: 1.5em;
}
div.imageblock, div.exampleblock, div.verseblock,
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
div.admonitionblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.admonitionblock {
  margin-top: 2.0em;
  margin-bottom: 2.0em;
  margin-right: 10%;
  color: #606060;
}

div.content { /* Block element content. */
  padding: 0;
}

/* Block element titles. */
div.title, caption.title {
  color: #527bbd;
  font-weight: bold;
  text-align: left;
  margin-top: 1.0em;
  margin-bottom: 0.5em;
}
div.title + * {
  margin-top: 0;
}

td div.title:first-child {
  margin-top: 0.0em;
}
div.content div.title:first-child {
  margin-top: 0.0em;
}
div.content + div.title {
  margin-top: 0.0em;
}

div.sidebarblock > div.content {
  background: #ffffee;
  border: 1px solid #dddddd;
  border-left: 4px solid #f0f0f0;
  padding: 0.5em;
}

div.listingblock > div.content {
  border: 1px solid #dddddd;
  border-left: 5px solid #f0f0f0;
  background: #f8f8f8;
  padding: 0.5em;
}

div.quoteblock, div.verseblock {
  padding-left: 1.0em;
  margin-left: 1.0em;
  margin-right: 10%;
  border-left: 5px solid #f0f0f0;
  color: #888;
}

div.quoteblock > div.attribution {
  padding-top: 0.5em;
  text-align: right;
}

div.verseblock > pre.content {
  font-family: inherit;
  font-size: inherit;
}
div.verseblock > div.attribution {
  padding-top: 0.75em;
  text-align: left;
}
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
div.verseblock + div.attribution {
  text-align: left;
}

div.admonitionblock .icon {
  vertical-align: top;
  font-size: 1.1em;
  font-weight: bold;
  text-decoration: underline;
  color: #527bbd;
  padding-right: 0.5em;
}
div.admonitionblock td.content {
  padding-left: 0.5em;
  border-left: 3px solid #dddddd;
}

div.exampleblock > div.content {
  border-left: 3px solid #dddddd;
  padding-left: 0.5em;
}

div.imageblock div.content { padding-left: 0; }
span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }

dl {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
dt {
  margin-top: 0.5em;
  margin-bottom: 0;
  font-style: normal;
  color: navy;
}
dd > *:first-child {
  margin-top: 0.1em;
}

ul, ol {
    list-style-position: outside;
}
ol.arabic {
  list-style-type: decimal;
}
ol.loweralpha {
  list-style-type: lower-alpha;
}
ol.upperalpha {
  list-style-type: upper-alpha;
}
ol.lowerroman {
  list-style-type: lower-roman;
}
ol.upperroman {
  list-style-type: upper-roman;
}

div.compact ul, div.compact ol,
div.compact p, div.compact p,
div.compact div, div.compact div {
  margin-top: 0.1em;
  margin-bottom: 0.1em;
}

tfoot {
  font-weight: bold;
}
td > div.verse {
  white-space: pre;
}

div.hdlist {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
div.hdlist tr {
  padding-bottom: 15px;
}
dt.hdlist1.strong, td.hdlist1.strong {
  font-weight: bold;
}
td.hdlist1 {
  vertical-align: top;
  font-style: normal;
  padding-right: 0.8em;
  color: navy;
}
td.hdlist2 {
  vertical-align: top;
}
div.hdlist.compact tr {
  margin: 0;
  padding-bottom: 0;
}

.comment {
  background: yellow;
}

.footnote, .footnoteref {
  font-size: 0.8em;
}

span.footnote, span.footnoteref {
  vertical-align: super;
}

#footnotes {
  margin: 20px 0 20px 0;
  padding: 7px 0 0 0;
}

#footnotes div.footnote {
  margin: 0 0 5px 0;
}

#footnotes hr {
  border: none;
  border-top: 1px solid silver;
  height: 1px;
  text-align: left;
  margin-left: 0;
  width: 20%;
  min-width: 100px;
}

div.colist td {
  padding-right: 0.5em;
  padding-bottom: 0.3em;
  vertical-align: top;
}
div.colist td img {
  margin-top: 0.3em;
}

@media print {
  #footer-badges { display: none; }
}

#toc {
  margin-bottom: 2.5em;
}

#toctitle {
  color: #527bbd;
  font-size: 1.1em;
  font-weight: bold;
  margin-top: 1.0em;
  margin-bottom: 0.1em;
}

div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
  margin-top: 0;
  margin-bottom: 0;
}
div.toclevel2 {
  margin-left: 2em;
  font-size: 0.9em;
}
div.toclevel3 {
  margin-left: 4em;
  font-size: 0.9em;
}
div.toclevel4 {
  margin-left: 6em;
  font-size: 0.9em;
}

span.aqua { color: aqua; }
span.black { color: black; }
span.blue { color: blue; }
span.fuchsia { color: fuchsia; }
span.gray { color: gray; }
span.green { color: green; }
span.lime { color: lime; }
span.maroon { color: maroon; }
span.navy { color: navy; }
span.olive { color: olive; }
span.purple { color: purple; }
span.red { color: red; }
span.silver { color: silver; }
span.teal { color: teal; }
span.white { color: white; }
span.yellow { color: yellow; }

span.aqua-background { background: aqua; }
span.black-background { background: black; }
span.blue-background { background: blue; }
span.fuchsia-background { background: fuchsia; }
span.gray-background { background: gray; }
span.green-background { background: green; }
span.lime-background { background: lime; }
span.maroon-background { background: maroon; }
span.navy-background { background: navy; }
span.olive-background { background: olive; }
span.purple-background { background: purple; }
span.red-background { background: red; }
span.silver-background { background: silver; }
span.teal-background { background: teal; }
span.white-background { background: white; }
span.yellow-background { background: yellow; }

span.big { font-size: 2em; }
span.small { font-size: 0.6em; }

span.underline { text-decoration: underline; }
span.overline { text-decoration: overline; }
span.line-through { text-decoration: line-through; }

div.unbreakable { page-break-inside: avoid; }


/*
 * xhtml11 specific
 *
 * */

div.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.tableblock > table {
  border: 3px solid #527bbd;
}
thead, p.table.header {
  font-weight: bold;
  color: #527bbd;
}
p.table {
  margin-top: 0;
}
/* Because the table frame attribute is overridden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
  border-style: none;
}
div.tableblock > table[frame="hsides"] {
  border-left-style: none;
  border-right-style: none;
}
div.tableblock > table[frame="vsides"] {
  border-top-style: none;
  border-bottom-style: none;
}


/*
 * html5 specific
 *
 * */

table.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
thead, p.tableblock.header {
  font-weight: bold;
  color: #527bbd;
}
p.tableblock {
  margin-top: 0;
}
table.tableblock {
  border-width: 3px;
  border-spacing: 0px;
  border-style: solid;
  border-color: #527bbd;
  border-collapse: collapse;
}
th.tableblock, td.tableblock {
  border-width: 1px;
  padding: 4px;
  border-style: solid;
  border-color: #527bbd;
}

table.tableblock.frame-topbot {
  border-left-style: hidden;
  border-right-style: hidden;
}
table.tableblock.frame-sides {
  border-top-style: hidden;
  border-bottom-style: hidden;
}
table.tableblock.frame-none {
  border-style: hidden;
}

th.tableblock.halign-left, td.tableblock.halign-left {
  text-align: left;
}
th.tableblock.halign-center, td.tableblock.halign-center {
  text-align: center;
}
th.tableblock.halign-right, td.tableblock.halign-right {
  text-align: right;
}

th.tableblock.valign-top, td.tableblock.valign-top {
  vertical-align: top;
}
th.tableblock.valign-middle, td.tableblock.valign-middle {
  vertical-align: middle;
}
th.tableblock.valign-bottom, td.tableblock.valign-bottom {
  vertical-align: bottom;
}


/*
 * manpage specific
 *
 * */

body.manpage h1 {
  padding-top: 0.5em;
  padding-bottom: 0.5em;
  border-top: 2px solid silver;
  border-bottom: 2px solid silver;
}
body.manpage h2 {
  border-style: none;
}
body.manpage div.sectionbody {
  margin-left: 3em;
}

@media print {
  body.manpage div#toc { display: none; }
}


</style>
<script type="text/javascript">
/*<![CDATA[*/
var asciidoc = {  // Namespace.

/////////////////////////////////////////////////////////////////////
// Table Of Contents generator
/////////////////////////////////////////////////////////////////////

/* Author: Mihai Bazon, September 2002
 * http://students.infoiasi.ro/~mishoo
 *
 * Table Of Content generator
 * Version: 0.4
 *
 * Feel free to use this script under the terms of the GNU General Public
 * License, as long as you do not remove or alter this notice.
 */

 /* modified by Troy D. Hanson, September 2006. License: GPL */
 /* modified by Stuart Rackham, 2006, 2009. License: GPL */

// toclevels = 1..4.
toc: function (toclevels) {

  function getText(el) {
    var text = "";
    for (var i = el.firstChild; i != null; i = i.nextSibling) {
      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
        text += i.data;
      else if (i.firstChild != null)
        text += getText(i);
    }
    return text;
  }

  function TocEntry(el, text, toclevel) {
    this.element = el;
    this.text = text;
    this.toclevel = toclevel;
  }

  function tocEntries(el, toclevels) {
    var result = new Array;
    var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
    // Function that scans the DOM tree for header elements (the DOM2
    // nodeIterator API would be a better technique but not supported by all
    // browsers).
    var iterate = function (el) {
      for (var i = el.firstChild; i != null; i = i.nextSibling) {
        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
          var mo = re.exec(i.tagName);
          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
          }
          iterate(i);
        }
      }
    }
    iterate(el);
    return result;
  }

  var toc = document.getElementById("toc");
  if (!toc) {
    return;
  }

  // Delete existing TOC entries in case we're reloading the TOC.
  var tocEntriesToRemove = [];
  var i;
  for (i = 0; i < toc.childNodes.length; i++) {
    var entry = toc.childNodes[i];
    if (entry.nodeName.toLowerCase() == 'div'
     && entry.getAttribute("class")
     && entry.getAttribute("class").match(/^toclevel/))
      tocEntriesToRemove.push(entry);
  }
  for (i = 0; i < tocEntriesToRemove.length; i++) {
    toc.removeChild(tocEntriesToRemove[i]);
  }

  // Rebuild TOC entries.
  var entries = tocEntries(document.getElementById("content"), toclevels);
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    if (entry.element.id == "")
      entry.element.id = "_toc_" + i;
    var a = document.createElement("a");
    a.href = "#" + entry.element.id;
    a.appendChild(document.createTextNode(entry.text));
    var div = document.createElement("div");
    div.appendChild(a);
    div.className = "toclevel" + entry.toclevel;
    toc.appendChild(div);
  }
  if (entries.length == 0)
    toc.parentNode.removeChild(toc);
},


/////////////////////////////////////////////////////////////////////
// Footnotes generator
/////////////////////////////////////////////////////////////////////

/* Based on footnote generation code from:
 * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
 */

footnotes: function () {
  // Delete existing footnote entries in case we're reloading the footnodes.
  var i;
  var noteholder = document.getElementById("footnotes");
  if (!noteholder) {
    return;
  }
  var entriesToRemove = [];
  for (i = 0; i < noteholder.childNodes.length; i++) {
    var entry = noteholder.childNodes[i];
    if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
      entriesToRemove.push(entry);
  }
  for (i = 0; i < entriesToRemove.length; i++) {
    noteholder.removeChild(entriesToRemove[i]);
  }

  // Rebuild footnote entries.
  var cont = document.getElementById("content");
  var spans = cont.getElementsByTagName("span");
  var refs = {};
  var n = 0;
  for (i=0; i<spans.length; i++) {
    if (spans[i].className == "footnote") {
      n++;
      var note = spans[i].getAttribute("data-note");
      if (!note) {
        // Use [\s\S] in place of . so multi-line matches work.
        // Because JavaScript has no s (dotall) regex flag.
        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
        spans[i].innerHTML =
          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
        spans[i].setAttribute("data-note", note);
      }
      noteholder.innerHTML +=
        "<div class='footnote' id='_footnote_" + n + "'>" +
        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
        n + "</a>. " + note + "</div>";
      var id =spans[i].getAttribute("id");
      if (id != null) refs["#"+id] = n;
    }
  }
  if (n == 0)
    noteholder.parentNode.removeChild(noteholder);
  else {
    // Process footnoterefs.
    for (i=0; i<spans.length; i++) {
      if (spans[i].className == "footnoteref") {
        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
        href = href.match(/#.*/)[0];  // Because IE return full URL.
        n = refs[href];
        spans[i].innerHTML =
          "[<a href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
      }
    }
  }
},

install: function(toclevels) {
  var timerId;

  function reinstall() {
    asciidoc.footnotes();
    if (toclevels) {
      asciidoc.toc(toclevels);
    }
  }

  function reinstallAndRemoveTimer() {
    clearInterval(timerId);
    reinstall();
  }

  timerId = setInterval(reinstall, 500);
  if (document.addEventListener)
    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
  else
    window.onload = reinstallAndRemoveTimer;
}

}
asciidoc.install();
/*]]>*/
</script>
</head>
<body class="article">
<div id="header">
<h1>Fighting regressions with git bisect</h1>
<span id="author">Christian Couder</span><br />
<span id="email"><code>&lt;<a href="mailto:chriscool@tuxfamily.org">chriscool@tuxfamily.org</a>&gt;</code></span><br />
<span id="revdate">2024-04-29</span>
</div>
<div id="content">
<div class="sect1">
<h2 id="_abstract">Abstract</h2>
<div class="sectionbody">
<div class="paragraph"><p>"git bisect" enables software users and developers to easily find the
commit that introduced a regression. We show why it is important to
have good tools to fight regressions. We describe how "git bisect"
works from the outside and the algorithms it uses inside. Then we
explain how to take advantage of "git bisect" to improve current
practices. And we discuss how "git bisect" could improve in the
future.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_introduction_to_git_bisect">Introduction to "git bisect"</h2>
<div class="sectionbody">
<div class="paragraph"><p>Git is a Distributed Version Control system (DVCS) created by Linus
Torvalds and maintained by Junio Hamano.</p></div>
<div class="paragraph"><p>In Git like in many other Version Control Systems (VCS), the different
states of the data that is managed by the system are called
commits. And, as VCS are mostly used to manage software source code,
sometimes "interesting" changes of behavior in the software are
introduced in some commits.</p></div>
<div class="paragraph"><p>In fact people are specially interested in commits that introduce a
"bad" behavior, called a bug or a regression. They are interested in
these commits because a commit (hopefully) contains a very small set
of source code changes. And it&#8217;s much easier to understand and
properly fix a problem when you only need to check a very small set of
changes, than when you don&#8217;t know where look in the first place.</p></div>
<div class="paragraph"><p>So to help people find commits that introduce a "bad" behavior, the
"git bisect" set of commands was invented. And it follows of course
that in "git bisect" parlance, commits where the "interesting
behavior" is present are called "bad" commits, while other commits are
called "good" commits. And a commit that introduce the behavior we are
interested in is called a "first bad commit". Note that there could be
more than one "first bad commit" in the commit space we are searching.</p></div>
<div class="paragraph"><p>So "git bisect" is designed to help find a "first bad commit". And to
be as efficient as possible, it tries to perform a binary search.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_fighting_regressions_overview">Fighting regressions overview</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_regressions_a_big_problem">Regressions: a big problem</h3>
<div class="paragraph"><p>Regressions are a big problem in the software industry. But it&#8217;s
difficult to put some real numbers behind that claim.</p></div>
<div class="paragraph"><p>There are some numbers about bugs in general, like a NIST study in
2002 <a href="#1">[1]</a> that said:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>Software bugs, or errors, are so prevalent and so detrimental that
they cost the U.S. economy an estimated $59.5 billion annually, or
about 0.6 percent of the gross domestic product, according to a newly
released study commissioned by the Department of Commerce&#8217;s National
Institute of Standards and Technology (NIST). At the national level,
over half of the costs are borne by software users and the remainder
by software developers/vendors.  The study also found that, although
all errors cannot be removed, more than a third of these costs, or an
estimated $22.2 billion, could be eliminated by an improved testing
infrastructure that enables earlier and more effective identification
and removal of software defects. These are the savings associated with
finding an increased percentage (but not 100 percent) of errors closer
to the development stages in which they are introduced. Currently,
over half of all errors are not found until "downstream" in the
development process or during post-sale software use.</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>And then:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>Software developers already spend approximately 80 percent of
development costs on identifying and correcting defects, and yet few
products of any type other than software are shipped with such high
levels of errors.</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>Eventually the conclusion started with:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>The path to higher software quality is significantly improved software
testing.</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>There are other estimates saying that 80% of the cost related to
software is about maintenance <a href="#2">[2]</a>.</p></div>
<div class="paragraph"><p>Though, according to Wikipedia <a href="#3">[3]</a>:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>A common perception of maintenance is that it is merely fixing
bugs. However, studies and surveys over the years have indicated that
the majority, over 80%, of the maintenance effort is used for
non-corrective actions (Pigosky 1997). This perception is perpetuated
by users submitting problem reports that in reality are functionality
enhancements to the system.</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>But we can guess that improving on existing software is very costly
because you have to watch out for regressions. At least this would
make the above studies consistent among themselves.</p></div>
<div class="paragraph"><p>Of course some kind of software is developed, then used during some
time without being improved on much, and then finally thrown away. In
this case, of course, regressions may not be a big problem. But on the
other hand, there is a lot of big software that is continually
developed and maintained during years or even tens of years by a lot
of people. And as there are often many people who depend (sometimes
critically) on such software, regressions are a really big problem.</p></div>
<div class="paragraph"><p>One such software is the Linux kernel. And if we look at the Linux
kernel, we can see that a lot of time and effort is spent to fight
regressions. The release cycle start with a 2 weeks long merge
window. Then the first release candidate (rc) version is tagged. And
after that about 7 or 8 more rc versions will appear with around one
week between each of them, before the final release.</p></div>
<div class="paragraph"><p>The time between the first rc release and the final release is
supposed to be used to test rc versions and fight bugs and especially
regressions. And this time is more than 80% of the release cycle
time. But this is not the end of the fight yet, as of course it
continues after the release.</p></div>
<div class="paragraph"><p>And then this is what Ingo Molnar (a well known Linux kernel
developer) says about his use of git bisect:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>I most actively use it during the merge window (when a lot of trees
get merged upstream and when the influx of bugs is the highest) - and
yes, there have been cases that i used it multiple times a day. My
average is roughly once a day.</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>So regressions are fought all the time by developers, and indeed it is
well known that bugs should be fixed as soon as possible, so as soon
as they are found. That&#8217;s why it is interesting to have good tools for
this purpose.</p></div>
</div>
<div class="sect2">
<h3 id="_other_tools_to_fight_regressions">Other tools to fight regressions</h3>
<div class="paragraph"><p>So what are the tools used to fight regressions? They are nearly the
same as those used to fight regular bugs. The only specific tools are
test suites and tools similar as "git bisect".</p></div>
<div class="paragraph"><p>Test suites are very nice. But when they are used alone, they are
supposed to be used so that all the tests are checked after each
commit. This means that they are not very efficient, because many
tests are run for no interesting result, and they suffer from
combinatorial explosion.</p></div>
<div class="paragraph"><p>In fact the problem is that big software often has many different
configuration options and that each test case should pass for each
configuration after each commit. So if you have for each release: N
configurations, M commits and T test cases, you should perform:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>N * M * T tests</code></pre>
</div></div>
<div class="paragraph"><p>where N, M and T are all growing with the size your software.</p></div>
<div class="paragraph"><p>So very soon it will not be possible to completely test everything.</p></div>
<div class="paragraph"><p>And if some bugs slip through your test suite, then you can add a test
to your test suite. But if you want to use your new improved test
suite to find where the bug slipped in, then you will either have to
emulate a bisection process or you will perhaps bluntly test each
commit backward starting from the "bad" commit you have which may be
very wasteful.</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_git_bisect_overview">"git bisect" overview</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_starting_a_bisection">Starting a bisection</h3>
<div class="paragraph"><p>The first "git bisect" subcommand to use is "git bisect start" to
start the search. Then bounds must be set to limit the commit
space. This is done usually by giving one "bad" and at least one
"good" commit. They can be passed in the initial call to "git bisect
start" like this:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect start [BAD [GOOD...]]</code></pre>
</div></div>
<div class="paragraph"><p>or they can be set using:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect bad [COMMIT]</code></pre>
</div></div>
<div class="paragraph"><p>and:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect good [COMMIT...]</code></pre>
</div></div>
<div class="paragraph"><p>where BAD, GOOD and COMMIT are all names that can be resolved to a
commit.</p></div>
<div class="paragraph"><p>Then "git bisect" will checkout a commit of its choosing and ask the
user to test it, like this:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect start v2.6.27 v2.6.25
Bisecting: 10928 revisions left to test after this (roughly 14 steps)
[2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86: clean up using max_low_pfn on 32-bit</code></pre>
</div></div>
<div class="paragraph"><p>Note that the example that we will use is really a toy example, we
will be looking for the first commit that has a version like
"2.6.26-something", that is the commit that has a "SUBLEVEL = 26" line
in the top level Makefile. This is a toy example because there are
better ways to find this commit with Git than using "git bisect" (for
example "git blame" or "git log -S&lt;string&gt;").</p></div>
</div>
<div class="sect2">
<h3 id="_driving_a_bisection_manually">Driving a bisection manually</h3>
<div class="paragraph"><p>At this point there are basically 2 ways to drive the search. It can
be driven manually by the user or it can be driven automatically by a
script or a command.</p></div>
<div class="paragraph"><p>If the user is driving it, then at each step of the search, the user
will have to test the current commit and say if it is "good" or "bad"
using the "git bisect good" or "git bisect bad" commands respectively
that have been described above. For example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect bad
Bisecting: 5480 revisions left to test after this (roughly 13 steps)
[66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file-&gt;f_count abuse in kvm</code></pre>
</div></div>
<div class="paragraph"><p>And after a few more steps like that, "git bisect" will eventually
find a first bad commit:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect bad
2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
commit 2ddcca36c8bcfa251724fe342c8327451988be0d
Author: Linus Torvalds &lt;torvalds@linux-foundation.org&gt;
Date:   Sat May 3 11:59:44 2008 -0700

    Linux 2.6.26-rc1

:100644 100644 5cf82581... 4492984e... M      Makefile</code></pre>
</div></div>
<div class="paragraph"><p>At this point we can see what the commit does, check it out (if it&#8217;s
not already checked out) or tinker with it, for example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git show HEAD
commit 2ddcca36c8bcfa251724fe342c8327451988be0d
Author: Linus Torvalds &lt;torvalds@linux-foundation.org&gt;
Date:   Sat May 3 11:59:44 2008 -0700

    Linux 2.6.26-rc1

diff --git a/Makefile b/Makefile
index 5cf8258..4492984 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 25
-EXTRAVERSION =
+SUBLEVEL = 26
+EXTRAVERSION = -rc1
 NAME = Funky Weasel is Jiggy wit it

 # *DOCUMENTATION*</code></pre>
</div></div>
<div class="paragraph"><p>And when we are finished we can use "git bisect reset" to go back to
the branch we were in before we started bisecting:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect reset
Checking out files: 100% (21549/21549), done.
Previous HEAD position was 2ddcca3... Linux 2.6.26-rc1
Switched to branch 'master'</code></pre>
</div></div>
</div>
<div class="sect2">
<h3 id="_driving_a_bisection_automatically">Driving a bisection automatically</h3>
<div class="paragraph"><p>The other way to drive the bisection process is to tell "git bisect"
to launch a script or command at each bisection step to know if the
current commit is "good" or "bad". To do that, we use the "git bisect
run" command. For example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect start v2.6.27 v2.6.25
Bisecting: 10928 revisions left to test after this (roughly 14 steps)
[2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86: clean up using max_low_pfn on 32-bit
$
$ git bisect run grep '^SUBLEVEL = 25' Makefile
running grep ^SUBLEVEL = 25 Makefile
Bisecting: 5480 revisions left to test after this (roughly 13 steps)
[66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file-&gt;f_count abuse in kvm
running grep ^SUBLEVEL = 25 Makefile
SUBLEVEL = 25
Bisecting: 2740 revisions left to test after this (roughly 12 steps)
[671294719628f1671faefd4882764886f8ad08cb] V4L/DVB(7879): Adding cx18 Support for mxl5005s
...
...
running grep ^SUBLEVEL = 25 Makefile
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[2ddcca36c8bcfa251724fe342c8327451988be0d] Linux 2.6.26-rc1
running grep ^SUBLEVEL = 25 Makefile
2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
commit 2ddcca36c8bcfa251724fe342c8327451988be0d
Author: Linus Torvalds &lt;torvalds@linux-foundation.org&gt;
Date:   Sat May 3 11:59:44 2008 -0700

    Linux 2.6.26-rc1

:100644 100644 5cf82581... 4492984e... M      Makefile
bisect run success</code></pre>
</div></div>
<div class="paragraph"><p>In this example, we passed "grep <em>^SUBLEVEL = 25</em> Makefile" as
parameter to "git bisect run". This means that at each step, the grep
command we passed will be launched. And if it exits with code 0 (that
means success) then git bisect will mark the current state as
"good". If it exits with code 1 (or any code between 1 and 127
included, except the special code 125), then the current state will be
marked as "bad".</p></div>
<div class="paragraph"><p>Exit code between 128 and 255 are special to "git bisect run". They
make it stop immediately the bisection process. This is useful for
example if the command passed takes too long to complete, because you
can kill it with a signal and it will stop the bisection process.</p></div>
<div class="paragraph"><p>It can also be useful in scripts passed to "git bisect run" to "exit
255" if some very abnormal situation is detected.</p></div>
</div>
<div class="sect2">
<h3 id="_avoiding_untestable_commits">Avoiding untestable commits</h3>
<div class="paragraph"><p>Sometimes it happens that the current state cannot be tested, for
example if it does not compile because there was a bug preventing it
at that time. This is what the special exit code 125 is for. It tells
"git bisect run" that the current commit should be marked as
untestable and that another one should be chosen and checked out.</p></div>
<div class="paragraph"><p>If the bisection process is driven manually, you can use "git bisect
skip" to do the same thing. (In fact the special exit code 125 makes
"git bisect run" use "git bisect skip" in the background.)</p></div>
<div class="paragraph"><p>Or if you want more control, you can inspect the current state using
for example "git bisect visualize". It will launch gitk (or "git log"
if the <code>DISPLAY</code> environment variable is not set) to help you find a
better bisection point.</p></div>
<div class="paragraph"><p>Either way, if you have a string of untestable commits, it might
happen that the regression you are looking for has been introduced by
one of these untestable commits. In this case it&#8217;s not possible to
tell for sure which commit introduced the regression.</p></div>
<div class="paragraph"><p>So if you used "git bisect skip" (or the run script exited with
special code 125) you could get a result like this:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>There are only 'skip'ped commits left to test.
The first bad commit could be any of:
15722f2fa328eaba97022898a305ffc8172db6b1
78e86cf3e850bd755bb71831f42e200626fbd1e0
e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace
070eab2303024706f2924822bfec8b9847e4ac1b
We cannot bisect more!</code></pre>
</div></div>
</div>
<div class="sect2">
<h3 id="_saving_a_log_and_replaying_it">Saving a log and replaying it</h3>
<div class="paragraph"><p>If you want to show other people your bisection process, you can get a
log using for example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect log &gt; bisect_log.txt</code></pre>
</div></div>
<div class="paragraph"><p>And it is possible to replay it using:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect replay bisect_log.txt</code></pre>
</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_git_bisect_details">"git bisect" details</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_bisection_algorithm">Bisection algorithm</h3>
<div class="paragraph"><p>As the Git commits form a directed acyclic graph (DAG), finding the
best bisection commit to test at each step is not so simple. Anyway
Linus found and implemented a "truly stupid" algorithm, later improved
by Junio Hamano, that works quite well.</p></div>
<div class="paragraph"><p>So the algorithm used by "git bisect" to find the best bisection
commit when there are no skipped commits is the following:</p></div>
<div class="paragraph"><p>1) keep only the commits that:</p></div>
<div class="paragraph"><p>a) are ancestor of the "bad" commit (including the "bad" commit itself),
b) are not ancestor of a "good" commit (excluding the "good" commits).</p></div>
<div class="paragraph"><p>This means that we get rid of the uninteresting commits in the DAG.</p></div>
<div class="paragraph"><p>For example if we start with a graph like this:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>G-Y-G-W-W-W-X-X-X-X
           \ /
            W-W-B
           /
Y---G-W---W
 \ /   \
Y-Y     X-X-X-X

-&gt; time goes this way -&gt;</code></pre>
</div></div>
<div class="paragraph"><p>where B is the "bad" commit, "G" are "good" commits and W, X, and Y
are other commits, we will get the following graph after this first
step:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>W-W-W
     \
      W-W-B
     /
W---W</code></pre>
</div></div>
<div class="paragraph"><p>So only the W and B commits will be kept. Because commits X and Y will
have been removed by rules a) and b) respectively, and because commits
G are removed by rule b) too.</p></div>
<div class="paragraph"><p>Note for Git users, that it is equivalent as keeping only the commit
given by:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>git rev-list BAD --not GOOD1 GOOD2...</code></pre>
</div></div>
<div class="paragraph"><p>Also note that we don&#8217;t require the commits that are kept to be
descendants of a "good" commit. So in the following example, commits W
and Z will be kept:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>G-W-W-W-B
   /
Z-Z</code></pre>
</div></div>
<div class="paragraph"><p>2) starting from the "good" ends of the graph, associate to each
   commit the number of ancestors it has plus one</p></div>
<div class="paragraph"><p>For example with the following graph where H is the "bad" commit and A
and D are some parents of some "good" commits:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>A-B-C
     \
      F-G-H
     /
D---E</code></pre>
</div></div>
<div class="paragraph"><p>this will give:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>1 2 3
A-B-C
     \6 7 8
      F-G-H
1   2/
D---E</code></pre>
</div></div>
<div class="paragraph"><p>3) associate to each commit: min(X, N - X)</p></div>
<div class="paragraph"><p>where X is the value associated to the commit in step 2) and N is the
total number of commits in the graph.</p></div>
<div class="paragraph"><p>In the above example we have N = 8, so this will give:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>1 2 3
A-B-C
     \2 1 0
      F-G-H
1   2/
D---E</code></pre>
</div></div>
<div class="paragraph"><p>4) the best bisection point is the commit with the highest associated
   number</p></div>
<div class="paragraph"><p>So in the above example the best bisection point is commit C.</p></div>
<div class="paragraph"><p>5) note that some shortcuts are implemented to speed up the algorithm</p></div>
<div class="paragraph"><p>As we know N from the beginning, we know that min(X, N - X) can&#8217;t be
greater than N/2. So during steps 2) and 3), if we would associate N/2
to a commit, then we know this is the best bisection point. So in this
case we can just stop processing any other commit and return the
current commit.</p></div>
</div>
<div class="sect2">
<h3 id="_bisection_algorithm_debugging">Bisection algorithm debugging</h3>
<div class="paragraph"><p>For any commit graph, you can see the number associated with each
commit using "git rev-list --bisect-all".</p></div>
<div class="paragraph"><p>For example, for the above graph, a command like:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git rev-list --bisect-all BAD --not GOOD1 GOOD2</code></pre>
</div></div>
<div class="paragraph"><p>would output something like:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace (dist=3)
15722f2fa328eaba97022898a305ffc8172db6b1 (dist=2)
78e86cf3e850bd755bb71831f42e200626fbd1e0 (dist=2)
a1939d9a142de972094af4dde9a544e577ddef0e (dist=2)
070eab2303024706f2924822bfec8b9847e4ac1b (dist=1)
a3864d4f32a3bf5ed177ddef598490a08760b70d (dist=1)
a41baa717dd74f1180abf55e9341bc7a0bb9d556 (dist=1)
9e622a6dad403b71c40979743bb9d5be17b16bd6 (dist=0)</code></pre>
</div></div>
</div>
<div class="sect2">
<h3 id="_bisection_algorithm_discussed">Bisection algorithm discussed</h3>
<div class="paragraph"><p>First let&#8217;s define "best bisection point". We will say that a commit X
is a best bisection point or a best bisection commit if knowing its
state ("good" or "bad") gives as much information as possible whether
the state of the commit happens to be "good" or "bad".</p></div>
<div class="paragraph"><p>This means that the best bisection commits are the commits where the
following function is maximum:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>f(X) = min(information_if_good(X), information_if_bad(X))</code></pre>
</div></div>
<div class="paragraph"><p>where information_if_good(X) is the information we get if X is good
and information_if_bad(X) is the information we get if X is bad.</p></div>
<div class="paragraph"><p>Now we will suppose that there is only one "first bad commit". This
means that all its descendants are "bad" and all the other commits are
"good". And we will suppose that all commits have an equal probability
of being good or bad, or of being the first bad commit, so knowing the
state of c commits gives always the same amount of information
wherever these c commits are on the graph and whatever c is. (So we
suppose that these commits being for example on a branch or near a
good or a bad commit does not give more or less information).</p></div>
<div class="paragraph"><p>Let&#8217;s also suppose that we have a cleaned up graph like one after step
1) in the bisection algorithm above. This means that we can measure
   the information we get in terms of number of commit we can remove
   from the graph..</p></div>
<div class="paragraph"><p>And let&#8217;s take a commit X in the graph.</p></div>
<div class="paragraph"><p>If X is found to be "good", then we know that its ancestors are all
"good", so we want to say that:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>information_if_good(X) = number_of_ancestors(X)  (TRUE)</code></pre>
</div></div>
<div class="paragraph"><p>And this is true because at step 1) b) we remove the ancestors of the
"good" commits.</p></div>
<div class="paragraph"><p>If X is found to be "bad", then we know that its descendants are all
"bad", so we want to say that:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>information_if_bad(X) = number_of_descendants(X)  (WRONG)</code></pre>
</div></div>
<div class="paragraph"><p>But this is wrong because at step 1) a) we keep only the ancestors of
the bad commit. So we get more information when a commit is marked as
"bad", because we also know that the ancestors of the previous "bad"
commit that are not ancestors of the new "bad" commit are not the
first bad commit. We don&#8217;t know if they are good or bad, but we know
that they are not the first bad commit because they are not ancestor
of the new "bad" commit.</p></div>
<div class="paragraph"><p>So when a commit is marked as "bad" we know we can remove all the
commits in the graph except those that are ancestors of the new "bad"
commit. This means that:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>information_if_bad(X) = N - number_of_ancestors(X)  (TRUE)</code></pre>
</div></div>
<div class="paragraph"><p>where N is the number of commits in the (cleaned up) graph.</p></div>
<div class="paragraph"><p>So in the end this means that to find the best bisection commits we
should maximize the function:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>f(X) = min(number_of_ancestors(X), N - number_of_ancestors(X))</code></pre>
</div></div>
<div class="paragraph"><p>And this is nice because at step 2) we compute number_of_ancestors(X)
and so at step 3) we compute f(X).</p></div>
<div class="paragraph"><p>Let&#8217;s take the following graph as an example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>            G-H-I-J
           /       \
A-B-C-D-E-F         O
           \       /
            K-L-M-N</code></pre>
</div></div>
<div class="paragraph"><p>If we compute the following non optimal function on it:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>g(X) = min(number_of_ancestors(X), number_of_descendants(X))</code></pre>
</div></div>
<div class="paragraph"><p>we get:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>            4 3 2 1
            G-H-I-J
1 2 3 4 5 6/       \0
A-B-C-D-E-F         O
           \       /
            K-L-M-N
            4 3 2 1</code></pre>
</div></div>
<div class="paragraph"><p>but with the algorithm used by git bisect we get:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>            7 7 6 5
            G-H-I-J
1 2 3 4 5 6/       \0
A-B-C-D-E-F         O
           \       /
            K-L-M-N
            7 7 6 5</code></pre>
</div></div>
<div class="paragraph"><p>So we chose G, H, K or L as the best bisection point, which is better
than F. Because if for example L is bad, then we will know not only
that L, M and N are bad but also that G, H, I and J are not the first
bad commit (since we suppose that there is only one first bad commit
and it must be an ancestor of L).</p></div>
<div class="paragraph"><p>So the current algorithm seems to be the best possible given what we
initially supposed.</p></div>
</div>
<div class="sect2">
<h3 id="_skip_algorithm">Skip algorithm</h3>
<div class="paragraph"><p>When some commits have been skipped (using "git bisect skip"), then
the bisection algorithm is the same for step 1) to 3). But then we use
roughly the following steps:</p></div>
<div class="paragraph"><p>6) sort the commit by decreasing associated value</p></div>
<div class="paragraph"><p>7) if the first commit has not been skipped, we can return it and stop
   here</p></div>
<div class="paragraph"><p>8) otherwise filter out all the skipped commits in the sorted list</p></div>
<div class="paragraph"><p>9) use a pseudo random number generator (PRNG) to generate a random
   number between 0 and 1</p></div>
<div class="paragraph"><p>10) multiply this random number with its square root to bias it toward
    0</p></div>
<div class="paragraph"><p>11) multiply the result by the number of commits in the filtered list
    to get an index into this list</p></div>
<div class="paragraph"><p>12) return the commit at the computed index</p></div>
</div>
<div class="sect2">
<h3 id="_skip_algorithm_discussed">Skip algorithm discussed</h3>
<div class="paragraph"><p>After step 7) (in the skip algorithm), we could check if the second
commit has been skipped and return it if it is not the case. And in
fact that was the algorithm we used from when "git bisect skip" was
developed in Git version 1.5.4 (released on February 1st 2008) until
Git version 1.6.4 (released July 29th 2009).</p></div>
<div class="paragraph"><p>But Ingo Molnar and H. Peter Anvin (another well known linux kernel
developer) both complained that sometimes the best bisection points
all happened to be in an area where all the commits are
untestable. And in this case the user was asked to test many
untestable commits, which could be very inefficient.</p></div>
<div class="paragraph"><p>Indeed untestable commits are often untestable because a breakage was
introduced at one time, and that breakage was fixed only after many
other commits were introduced.</p></div>
<div class="paragraph"><p>This breakage is of course most of the time unrelated to the breakage
we are trying to locate in the commit graph. But it prevents us to
know if the interesting "bad behavior" is present or not.</p></div>
<div class="paragraph"><p>So it is a fact that commits near an untestable commit have a high
probability of being untestable themselves. And the best bisection
commits are often found together too (due to the bisection algorithm).</p></div>
<div class="paragraph"><p>This is why it is a bad idea to just chose the next best unskipped
bisection commit when the first one has been skipped.</p></div>
<div class="paragraph"><p>We found that most commits on the graph may give quite a lot of
information when they are tested. And the commits that will not on
average give a lot of information are the one near the good and bad
commits.</p></div>
<div class="paragraph"><p>So using a PRNG with a bias to favor commits away from the good and
bad commits looked like a good choice.</p></div>
<div class="paragraph"><p>One obvious improvement to this algorithm would be to look for a
commit that has an associated value near the one of the best bisection
commit, and that is on another branch, before using the PRNG. Because
if such a commit exists, then it is not very likely to be untestable
too, so it will probably give more information than a nearly randomly
chosen one.</p></div>
</div>
<div class="sect2">
<h3 id="_checking_merge_bases">Checking merge bases</h3>
<div class="paragraph"><p>There is another tweak in the bisection algorithm that has not been
described in the "bisection algorithm" above.</p></div>
<div class="paragraph"><p>We supposed in the previous examples that the "good" commits were
ancestors of the "bad" commit. But this is not a requirement of "git
bisect".</p></div>
<div class="paragraph"><p>Of course the "bad" commit cannot be an ancestor of a "good" commit,
because the ancestors of the good commits are supposed to be
"good". And all the "good" commits must be related to the bad commit.
They cannot be on a branch that has no link with the branch of the
"bad" commit. But it is possible for a good commit to be related to a
bad commit and yet not be neither one of its ancestor nor one of its
descendants.</p></div>
<div class="paragraph"><p>For example, there can be a "main" branch, and a "dev" branch that was
forked of the main branch at a commit named "D" like this:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>A-B-C-D-E-F-G  &lt;--main
       \
        H-I-J  &lt;--dev</code></pre>
</div></div>
<div class="paragraph"><p>The commit "D" is called a "merge base" for branch "main" and "dev"
because it&#8217;s the best common ancestor for these branches for a merge.</p></div>
<div class="paragraph"><p>Now let&#8217;s suppose that commit J is bad and commit G is good and that
we apply the bisection algorithm like it has been previously
described.</p></div>
<div class="paragraph"><p>As described in step 1) b) of the bisection algorithm, we remove all
the ancestors of the good commits because they are supposed to be good
too.</p></div>
<div class="paragraph"><p>So we would be left with only:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>H-I-J</code></pre>
</div></div>
<div class="paragraph"><p>But what happens if the first bad commit is "B" and if it has been
fixed in the "main" branch by commit "F"?</p></div>
<div class="paragraph"><p>The result of such a bisection would be that we would find that H is
the first bad commit, when in fact it&#8217;s B. So that would be wrong!</p></div>
<div class="paragraph"><p>And yes it can happen in practice that people working on one branch
are not aware that people working on another branch fixed a bug! It
could also happen that F fixed more than one bug or that it is a
revert of some big development effort that was not ready to be
released.</p></div>
<div class="paragraph"><p>In fact development teams often maintain both a development branch and
a maintenance branch, and it would be quite easy for them if "git
bisect" just worked when they want to bisect a regression on the
development branch that is not on the maintenance branch. They should
be able to start bisecting using:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect start dev main</code></pre>
</div></div>
<div class="paragraph"><p>To enable that additional nice feature, when a bisection is started
and when some good commits are not ancestors of the bad commit, we
first compute the merge bases between the bad and the good commits and
we chose these merge bases as the first commits that will be checked
out and tested.</p></div>
<div class="paragraph"><p>If it happens that one merge base is bad, then the bisection process
is stopped with a message like:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>The merge base BBBBBB is bad.
This means the bug has been fixed between BBBBBB and [GGGGGG,...].</code></pre>
</div></div>
<div class="paragraph"><p>where BBBBBB is the sha1 hash of the bad merge base and [GGGGGG,&#8230;]
is a comma separated list of the sha1 of the good commits.</p></div>
<div class="paragraph"><p>If some of the merge bases are skipped, then the bisection process
continues, but the following message is printed for each skipped merge
base:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>Warning: the merge base between BBBBBB and [GGGGGG,...] must be skipped.
So we cannot be sure the first bad commit is between MMMMMM and BBBBBB.
We continue anyway.</code></pre>
</div></div>
<div class="paragraph"><p>where BBBBBB is the sha1 hash of the bad commit, MMMMMM is the sha1
hash of the merge base that is skipped and [GGGGGG,&#8230;]  is a comma
separated list of the sha1 of the good commits.</p></div>
<div class="paragraph"><p>So if there is no bad merge base, the bisection process continues as
usual after this step.</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_best_bisecting_practices">Best bisecting practices</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_using_test_suites_and_git_bisect_together">Using test suites and git bisect together</h3>
<div class="paragraph"><p>If you both have a test suite and use git bisect, then it becomes less
important to check that all tests pass after each commit. Though of
course it is probably a good idea to have some checks to avoid
breaking too many things because it could make bisecting other bugs
more difficult.</p></div>
<div class="paragraph"><p>You can focus your efforts to check at a few points (for example rc
and beta releases) that all the T test cases pass for all the N
configurations. And when some tests don&#8217;t pass you can use "git
bisect" (or better "git bisect run"). So you should perform roughly:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>c * N * T + b * M * log2(M) tests</code></pre>
</div></div>
<div class="paragraph"><p>where c is the number of rounds of test (so a small constant) and b is
the ratio of bug per commit (hopefully a small constant too).</p></div>
<div class="paragraph"><p>So of course it&#8217;s much better as it&#8217;s O(N * T) vs O(N * T * M) if
you would test everything after each commit.</p></div>
<div class="paragraph"><p>This means that test suites are good to prevent some bugs from being
committed and they are also quite good to tell you that you have some
bugs. But they are not so good to tell you where some bugs have been
introduced. To tell you that efficiently, git bisect is needed.</p></div>
<div class="paragraph"><p>The other nice thing with test suites, is that when you have one, you
already know how to test for bad behavior. So you can use this
knowledge to create a new test case for "git bisect" when it appears
that there is a regression. So it will be easier to bisect the bug and
fix it. And then you can add the test case you just created to your
test suite.</p></div>
<div class="paragraph"><p>So if you know how to create test cases and how to bisect, you will be
subject to a virtuous circle:</p></div>
<div class="paragraph"><p>more tests &#8658; easier to create tests &#8658; easier to bisect &#8658; more tests</p></div>
<div class="paragraph"><p>So test suites and "git bisect" are complementary tools that are very
powerful and efficient when used together.</p></div>
</div>
<div class="sect2">
<h3 id="_bisecting_build_failures">Bisecting build failures</h3>
<div class="paragraph"><p>You can very easily automatically bisect broken builds using something
like:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect start BAD GOOD
$ git bisect run make</code></pre>
</div></div>
</div>
<div class="sect2">
<h3 id="_passing_sh_c_some_commands_to_git_bisect_run">Passing sh -c "some commands" to "git bisect run"</h3>
<div class="paragraph"><p>For example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect run sh -c "make || exit 125; ./my_app | grep 'good output'"</code></pre>
</div></div>
<div class="paragraph"><p>On the other hand if you do this often, then it can be worth having
scripts to avoid too much typing.</p></div>
</div>
<div class="sect2">
<h3 id="_finding_performance_regressions">Finding performance regressions</h3>
<div class="paragraph"><p>Here is an example script that comes slightly modified from a real
world script used by Junio Hamano <a href="#4">[4]</a>.</p></div>
<div class="paragraph"><p>This script can be passed to "git bisect run" to find the commit that
introduced a performance regression:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>#!/bin/sh

# Build errors are not what I am interested in.
make my_app || exit 255

# We are checking if it stops in a reasonable amount of time, so
# let it run in the background...

./my_app &gt;log 2&gt;&amp;1 &amp;

# ... and grab its process ID.
pid=$!

# ... and then wait for sufficiently long.
sleep $NORMAL_TIME

# ... and then see if the process is still there.
if kill -0 $pid
then
        # It is still running -- that is bad.
        kill $pid; sleep 1; kill $pid;
        exit 1
else
        # It has already finished (the $pid process was no more),
        # and we are happy.
        exit 0
fi</code></pre>
</div></div>
</div>
<div class="sect2">
<h3 id="_following_general_best_practices">Following general best practices</h3>
<div class="paragraph"><p>It is obviously a good idea not to have commits with changes that
knowingly break things, even if some other commits later fix the
breakage.</p></div>
<div class="paragraph"><p>It is also a good idea when using any VCS to have only one small
logical change in each commit.</p></div>
<div class="paragraph"><p>The smaller the changes in your commit, the most effective "git
bisect" will be. And you will probably need "git bisect" less in the
first place, as small changes are easier to review even if they are
only reviewed by the committer.</p></div>
<div class="paragraph"><p>Another good idea is to have good commit messages. They can be very
helpful to understand why some changes were made.</p></div>
<div class="paragraph"><p>These general best practices are very helpful if you bisect often.</p></div>
</div>
<div class="sect2">
<h3 id="_avoiding_bug_prone_merges">Avoiding bug prone merges</h3>
<div class="paragraph"><p>First merges by themselves can introduce some regressions even when
the merge needs no source code conflict resolution. This is because a
semantic change can happen in one branch while the other branch is not
aware of it.</p></div>
<div class="paragraph"><p>For example one branch can change the semantic of a function while the
other branch add more calls to the same function.</p></div>
<div class="paragraph"><p>This is made much worse if many files have to be fixed to resolve
conflicts. That&#8217;s why such merges are called "evil merges". They can
make regressions very difficult to track down. It can even be
misleading to know the first bad commit if it happens to be such a
merge, because people might think that the bug comes from bad conflict
resolution when it comes from a semantic change in one branch.</p></div>
<div class="paragraph"><p>Anyway "git rebase" can be used to linearize history. This can be used
either to avoid merging in the first place. Or it can be used to
bisect on a linear history instead of the non linear one, as this
should give more information in case of a semantic change in one
branch.</p></div>
<div class="paragraph"><p>Merges can be also made simpler by using smaller branches or by using
many topic branches instead of only long version related branches.</p></div>
<div class="paragraph"><p>And testing can be done more often in special integration branches
like linux-next for the linux kernel.</p></div>
</div>
<div class="sect2">
<h3 id="_adapting_your_work_flow">Adapting your work-flow</h3>
<div class="paragraph"><p>A special work-flow to process regressions can give great results.</p></div>
<div class="paragraph"><p>Here is an example of a work-flow used by Andreas Ericsson:</p></div>
<div class="ulist"><ul>
<li>
<p>
write, in the test suite, a test script that exposes the regression
</p>
</li>
<li>
<p>
use "git bisect run" to find the commit that introduced it
</p>
</li>
<li>
<p>
fix the bug that is often made obvious by the previous step
</p>
</li>
<li>
<p>
commit both the fix and the test script (and if needed more tests)
</p>
</li>
</ul></div>
<div class="paragraph"><p>And here is what Andreas said about this work-flow <a href="#5">[5]</a>:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>To give some hard figures, we used to have an average report-to-fix
cycle of 142.6 hours (according to our somewhat weird bug-tracker
which just measures wall-clock time). Since we moved to Git, we&#8217;ve
lowered that to 16.2 hours. Primarily because we can stay on top of
the bug fixing now, and because everyone&#8217;s jockeying to get to fix
bugs (we&#8217;re quite proud of how lazy we are to let Git find the bugs
for us). Each new release results in ~40% fewer bugs (almost certainly
due to how we now feel about writing tests).</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>Clearly this work-flow uses the virtuous circle between test suites
and "git bisect". In fact it makes it the standard procedure to deal
with regression.</p></div>
<div class="paragraph"><p>In other messages Andreas says that they also use the "best practices"
described above: small logical commits, topic branches, no evil
merge,&#8230; These practices all improve the bisectability of the commit
graph, by making it easier and more useful to bisect.</p></div>
<div class="paragraph"><p>So a good work-flow should be designed around the above points. That
is making bisecting easier, more useful and standard.</p></div>
</div>
<div class="sect2">
<h3 id="_involving_qa_people_and_if_possible_end_users">Involving QA people and if possible end users</h3>
<div class="paragraph"><p>One nice about "git bisect" is that it is not only a developer
tool. It can effectively be used by QA people or even end users (if
they have access to the source code or if they can get access to all
the builds).</p></div>
<div class="paragraph"><p>There was a discussion at one point on the linux kernel mailing list
of whether it was ok to always ask end user to bisect, and very good
points were made to support the point of view that it is ok.</p></div>
<div class="paragraph"><p>For example David Miller wrote <a href="#6">[6]</a>:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>What people don&#8217;t get is that this is a situation where the "end node
principle" applies. When you have limited resources (here: developers)
you don&#8217;t push the bulk of the burden upon them. Instead you push
things out to the resource you have a lot of, the end nodes (here:
users), so that the situation actually scales.</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>This means that it is often "cheaper" if QA people or end users can do
it.</p></div>
<div class="paragraph"><p>What is interesting too is that end users that are reporting bugs (or
QA people that reproduced a bug) have access to the environment where
the bug happens. So they can often more easily reproduce a
regression. And if they can bisect, then more information will be
extracted from the environment where the bug happens, which means that
it will be easier to understand and then fix the bug.</p></div>
<div class="paragraph"><p>For open source projects it can be a good way to get more useful
contributions from end users, and to introduce them to QA and
development activities.</p></div>
</div>
<div class="sect2">
<h3 id="_using_complex_scripts">Using complex scripts</h3>
<div class="paragraph"><p>In some cases like for kernel development it can be worth developing
complex scripts to be able to fully automate bisecting.</p></div>
<div class="paragraph"><p>Here is what Ingo Molnar says about that <a href="#7">[7]</a>:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>i have a fully automated bootup-hang bisection script. It is based on
"git-bisect run". I run the script, it builds and boots kernels fully
automatically, and when the bootup fails (the script notices that via
the serial log, which it continuously watches - or via a timeout, if
the system does not come up within 10 minutes it&#8217;s a "bad" kernel),
the script raises my attention via a beep and i power cycle the test
box. (yeah, i should make use of a managed power outlet to 100%
automate it)</p></div>
</div>
<div class="attribution">
</div></div>
</div>
<div class="sect2">
<h3 id="_combining_test_suites_git_bisect_and_other_systems_together">Combining test suites, git bisect and other systems together</h3>
<div class="paragraph"><p>We have seen that test suites and git bisect are very powerful when
used together. It can be even more powerful if you can combine them
with other systems.</p></div>
<div class="paragraph"><p>For example some test suites could be run automatically at night with
some unusual (or even random) configurations. And if a regression is
found by a test suite, then "git bisect" can be automatically
launched, and its result can be emailed to the author of the first bad
commit found by "git bisect", and perhaps other people too. And a new
entry in the bug tracking system could be automatically created too.</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_future_of_bisecting">The future of bisecting</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_git_replace">"git replace"</h3>
<div class="paragraph"><p>We saw earlier that "git bisect skip" is now using a PRNG to try to
avoid areas in the commit graph where commits are untestable. The
problem is that sometimes the first bad commit will be in an
untestable area.</p></div>
<div class="paragraph"><p>To simplify the discussion we will suppose that the untestable area is
a simple string of commits and that it was created by a breakage
introduced by one commit (let&#8217;s call it BBC for bisect breaking
commit) and later fixed by another one (let&#8217;s call it BFC for bisect
fixing commit).</p></div>
<div class="paragraph"><p>For example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...</code></pre>
</div></div>
<div class="paragraph"><p>where we know that Y is good and BFC is bad, and where BBC and X1 to
X6 are untestable.</p></div>
<div class="paragraph"><p>In this case if you are bisecting manually, what you can do is create
a special branch that starts just before the BBC. The first commit in
this branch should be the BBC with the BFC squashed into it. And the
other commits in the branch should be the commits between BBC and BFC
rebased on the first commit of the branch and then the commit after
BFC also rebased on.</p></div>
<div class="paragraph"><p>For example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>      (BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'
     /
...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...</code></pre>
</div></div>
<div class="paragraph"><p>where commits quoted with ' have been rebased.</p></div>
<div class="paragraph"><p>You can easily create such a branch with Git using interactive rebase.</p></div>
<div class="paragraph"><p>For example using:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git rebase -i Y Z</code></pre>
</div></div>
<div class="paragraph"><p>and then moving BFC after BBC and squashing it.</p></div>
<div class="paragraph"><p>After that you can start bisecting as usual in the new branch and you
should eventually find the first bad commit.</p></div>
<div class="paragraph"><p>For example:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>$ git bisect start Z' Y</code></pre>
</div></div>
<div class="paragraph"><p>If you are using "git bisect run", you can use the same manual fix up
as above, and then start another "git bisect run" in the special
branch. Or as the "git bisect" man page says, the script passed to
"git bisect run" can apply a patch before it compiles and test the
software <a href="#8">[8]</a>. The patch should turn a current untestable commits
into a testable one. So the testing will result in "good" or "bad" and
"git bisect" will be able to find the first bad commit. And the script
should not forget to remove the patch once the testing is done before
exiting from the script.</p></div>
<div class="paragraph"><p>(Note that instead of a patch you can use "git cherry-pick BFC" to
apply the fix, and in this case you should use "git reset --hard
HEAD^" to revert the cherry-pick after testing and before returning
from the script.)</p></div>
<div class="paragraph"><p>But the above ways to work around untestable areas are a little bit
clunky. Using special branches is nice because these branches can be
shared by developers like usual branches, but the risk is that people
will get many such branches. And it disrupts the normal "git bisect"
work-flow. So, if you want to use "git bisect run" completely
automatically, you have to add special code in your script to restart
bisection in the special branches.</p></div>
<div class="paragraph"><p>Anyway one can notice in the above special branch example that the Z'
and Z commits should point to the same source code state (the same
"tree" in git parlance). That&#8217;s because Z' result from applying the
same changes as Z just in a slightly different order.</p></div>
<div class="paragraph"><p>So if we could just "replace" Z by Z' when we bisect, then we would
not need to add anything to a script. It would just work for anyone in
the project sharing the special branches and the replacements.</p></div>
<div class="paragraph"><p>With the example above that would give:</p></div>
<div class="listingblock">
<div class="content">
<pre><code>      (BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'-...
     /
...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z</code></pre>
</div></div>
<div class="paragraph"><p>That&#8217;s why the "git replace" command was created. Technically it
stores replacements "refs" in the "refs/replace/" hierarchy. These
"refs" are like branches (that are stored in "refs/heads/") or tags
(that are stored in "refs/tags"), and that means that they can
automatically be shared like branches or tags among developers.</p></div>
<div class="paragraph"><p>"git replace" is a very powerful mechanism. It can be used to fix
commits in already released history, for example to change the commit
message or the author. And it can also be used instead of git "grafts"
to link a repository with another old repository.</p></div>
<div class="paragraph"><p>In fact it&#8217;s this last feature that "sold" it to the Git community, so
it is now in the "master" branch of Git&#8217;s Git repository and it should
be released in Git 1.6.5 in October or November 2009.</p></div>
<div class="paragraph"><p>One problem with "git replace" is that currently it stores all the
replacements refs in "refs/replace/", but it would be perhaps better
if the replacement refs that are useful only for bisecting would be in
"refs/replace/bisect/". This way the replacement refs could be used
only for bisecting, while other refs directly in "refs/replace/" would
be used nearly all the time.</p></div>
</div>
<div class="sect2">
<h3 id="_bisecting_sporadic_bugs">Bisecting sporadic bugs</h3>
<div class="paragraph"><p>Another possible improvement to "git bisect" would be to optionally
add some redundancy to the tests performed so that it would be more
reliable when tracking sporadic bugs.</p></div>
<div class="paragraph"><p>This has been requested by some kernel developers because some bugs
called sporadic bugs do not appear in all the kernel builds because
they are very dependent on the compiler output.</p></div>
<div class="paragraph"><p>The idea is that every 3 test for example, "git bisect" could ask the
user to test a commit that has already been found to be "good" or
"bad" (because one of its descendants or one of its ancestors has been
found to be "good" or "bad" respectively). If it happens that a commit
has been previously incorrectly classified then the bisection can be
aborted early, hopefully before too many mistakes have been made. Then
the user will have to look at what happened and then restart the
bisection using a fixed bisect log.</p></div>
<div class="paragraph"><p>There is already a project called BBChop created by Ealdwulf Wuffinga
on Github that does something like that using Bayesian Search Theory
<a href="#9">[9]</a>:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>BBChop is like <em>git bisect</em> (or equivalent), but works when your bug
is intermittent. That is, it works in the presence of false negatives
(when a version happens to work this time even though it contains the
bug). It assumes that there are no false positives (in principle, the
same approach would work, but adding it may be non-trivial).</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>But BBChop is independent of any VCS and it would be easier for Git
users to have something integrated in Git.</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph"><p>We have seen that regressions are an important problem, and that "git
bisect" has nice features that complement very well practices and
other tools, especially test suites, that are generally used to fight
regressions. But it might be needed to change some work-flows and
(bad) habits to get the most out of it.</p></div>
<div class="paragraph"><p>Some improvements to the algorithms inside "git bisect" are possible
and some new features could help in some cases, but overall "git
bisect" works already very well, is used a lot, and is already very
useful. To back up that last claim, let&#8217;s give the final word to Ingo
Molnar when he was asked by the author how much time does he think
"git bisect" saves him when he uses it:</p></div>
<div class="quoteblock">
<div class="content">
<div class="paragraph"><p>a <em>lot</em>.</p></div>
<div class="paragraph"><p>About ten years ago did i do my first <em>bisection</em> of a Linux patch
queue. That was prior the Git (and even prior the BitKeeper) days. I
literally days spent sorting out patches, creating what in essence
were standalone commits that i guessed to be related to that bug.</p></div>
<div class="paragraph"><p>It was a tool of absolute last resort. I&#8217;d rather spend days looking
at printk output than do a manual <em>patch bisection</em>.</p></div>
<div class="paragraph"><p>With Git bisect it&#8217;s a breeze: in the best case i can get a ~15 step
kernel bisection done in 20-30 minutes, in an automated way. Even with
manual help or when bisecting multiple, overlapping bugs, it&#8217;s rarely
more than an hour.</p></div>
<div class="paragraph"><p>In fact it&#8217;s invaluable because there are bugs i would never even
<em>try</em> to debug if it wasn&#8217;t for git bisect. In the past there were bug
patterns that were immediately hopeless for me to debug - at best i
could send the crash/bug signature to lkml and hope that someone else
can think of something.</p></div>
<div class="paragraph"><p>And even if a bisection fails today it tells us something valuable
about the bug: that it&#8217;s non-deterministic - timing or kernel image
layout dependent.</p></div>
<div class="paragraph"><p>So git bisect is unconditional goodness - and feel free to quote that
;-)</p></div>
</div>
<div class="attribution">
</div></div>
</div>
</div>
<div class="sect1">
<h2 id="_acknowledgments">Acknowledgments</h2>
<div class="sectionbody">
<div class="paragraph"><p>Many thanks to Junio Hamano for his help in reviewing this paper, for
reviewing the patches I sent to the Git mailing list, for discussing
some ideas and helping me improve them, for improving "git bisect" a
lot and for his awesome work in maintaining and developing Git.</p></div>
<div class="paragraph"><p>Many thanks to Ingo Molnar for giving me very useful information that
appears in this paper, for commenting on this paper, for his
suggestions to improve "git bisect" and for evangelizing "git bisect"
on the linux kernel mailing lists.</p></div>
<div class="paragraph"><p>Many thanks to Linus Torvalds for inventing, developing and
evangelizing "git bisect", Git and Linux.</p></div>
<div class="paragraph"><p>Many thanks to the many other great people who helped one way or
another when I worked on Git, especially to Andreas Ericsson, Johannes
Schindelin, H. Peter Anvin, Daniel Barkalow, Bill Lear, John Hawley,
Shawn O. Pierce, Jeff King, Sam Vilain, Jon Seymour.</p></div>
<div class="paragraph"><p>Many thanks to the Linux-Kongress program committee for choosing the
author to given a talk and for publishing this paper.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_references">References</h2>
<div class="sectionbody">
<div class="ulist"><ul>
<li>
<p>
<a id="1"></a>[1] <a href="https://web.archive.org/web/20091206032101/http://www.nist.gov/public_affairs/releases/n02-10.htm"><em>Software Errors Cost U.S. Economy $59.5 Billion Annually</em>. Nist News Release.</a> See also <a href="https://www.nist.gov/system/files/documents/director/planning/report02-3.pdf"><em>The Economic Impacts of Inadequate Infratructure for Software Testing</em>.  Nist Planning Report 02-3</a>, Executive Summary and Chapter 8.
</p>
</li>
<li>
<p>
<a id="2"></a>[2] <a href="https://www.oracle.com/java/technologies/javase/codeconventions-introduction.html"><em>Code Conventions for the Java Programming Language: 1. Introduction</em>. Sun Microsystems.</a>
</p>
</li>
<li>
<p>
<a id="3"></a>[3] <a href="https://en.wikipedia.org/wiki/Software_maintenance"><em>Software maintenance</em>. Wikipedia.</a>
</p>
</li>
<li>
<p>
<a id="4"></a>[4] <a href="https://lore.kernel.org/git/7vps5xsbwp.fsf_-_@assigned-by-dhcp.cox.net/">Junio C Hamano. <em>Automated bisect success story</em>.</a>
</p>
</li>
<li>
<p>
<a id="5"></a>[5] <a href="https://lwn.net/Articles/317154/">Christian Couder. <em>Fully automated bisecting with "git bisect run"</em>. LWN.net.</a>
</p>
</li>
<li>
<p>
<a id="6"></a>[6] <a href="https://lwn.net/Articles/277872/">Jonathan Corbet. <em>Bisection divides users and developers</em>. LWN.net.</a>
</p>
</li>
<li>
<p>
<a id="7"></a>[7] <a href="https://lore.kernel.org/lkml/20071207113734.GA14598@elte.hu/">Ingo Molnar. <em>Re: BUG 2.6.23-rc3 can&#8217;t see sd partitions on Alpha</em>. Linux-kernel mailing list.</a>
</p>
</li>
<li>
<p>
<a id="8"></a>[8] <a href="https://www.kernel.org/pub/software/scm/git/docs/git-bisect.html">Junio C Hamano and the git-list. <em>git-bisect(1) Manual Page</em>. Linux Kernel Archives.</a>
</p>
</li>
<li>
<p>
<a id="9"></a>[9] <a href="https://github.com/Ealdwulf/bbchop">Ealdwulf. <em>bbchop</em>. GitHub.</a>
</p>
</li>
</ul></div>
</div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated
 2023-01-21 17:52:14 PST
</div>
</div>
</body>
</html>