hgbook / fr / ch09-undo.xml

   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
<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->

<chapter id="chap:undo">
  <?dbhtml filename="finding-and-fixing-mistakes.html"?>
  <title>Finding and fixing mistakes</title>

  <para id="x_d2">To err might be human, but to really handle the consequences
    well takes a top-notch revision control system.  In this chapter,
    we'll discuss some of the techniques you can use when you find
    that a problem has crept into your project.  Mercurial has some
    highly capable features that will help you to isolate the sources
    of problems, and to handle them appropriately.</para>

  <sect1>
    <title>Erasing local history</title>

    <sect2>
      <title>The accidental commit</title>

      <para id="x_d3">I have the occasional but persistent problem of typing
	rather more quickly than I can think, which sometimes results
	in me committing a changeset that is either incomplete or
	plain wrong.  In my case, the usual kind of incomplete
	changeset is one in which I've created a new source file, but
	forgotten to <command role="hg-cmd">hg add</command> it.  A
	<quote>plain wrong</quote> changeset is not as common, but no
	less annoying.</para>

    </sect2>
    <sect2 id="sec:undo:rollback">
      <title>Rolling back a transaction</title>

      <para id="x_d4">In <xref linkend="sec:concepts:txn"/>, I
	mentioned that Mercurial treats each modification of a
	repository as a <emphasis>transaction</emphasis>.  Every time
	you commit a changeset or pull changes from another
	repository, Mercurial remembers what you did.  You can undo,
	or <emphasis>roll back</emphasis>, exactly one of these
	actions using the <command role="hg-cmd">hg rollback</command>
	command.  (See <xref linkend="sec:undo:rollback-after-push"/>
	for an important caveat about the use of this command.)</para>

      <para id="x_d5">Here's a mistake that I often find myself making:
	committing a change in which I've created a new file, but
	forgotten to <command role="hg-cmd">hg add</command>
	it.</para>

      &interaction.rollback.commit;

      <para id="x_d6">Looking at the output of <command role="hg-cmd">hg
	  status</command> after the commit immediately confirms the
	error.</para>

      &interaction.rollback.status;

      <para id="x_d7">The commit captured the changes to the file
	<filename>a</filename>, but not the new file
	<filename>b</filename>.  If I were to push this changeset to a
	repository that I shared with a colleague, the chances are
	high that something in <filename>a</filename> would refer to
	<filename>b</filename>, which would not be present in their
	repository when they pulled my changes.  I would thus become
	the object of some indignation.</para>

      <para id="x_d8">However, luck is with me&emdash;I've caught my error
	before I pushed the changeset.  I use the <command
	  role="hg-cmd">hg rollback</command> command, and Mercurial
	makes that last changeset vanish.</para>

      &interaction.rollback.rollback;

      <para id="x_d9">Notice that the changeset is no longer present in the
	repository's history, and the working directory once again
	thinks that the file <filename>a</filename> is modified.  The
	commit and rollback have left the working directory exactly as
	it was prior to the commit; the changeset has been completely
	erased.  I can now safely <command role="hg-cmd">hg
	  add</command> the file <filename>b</filename>, and rerun my
	commit.</para>

      &interaction.rollback.add;

    </sect2>
    <sect2>
      <title>The erroneous pull</title>

      <para id="x_da">It's common practice with Mercurial to maintain separate
	development branches of a project in different repositories.
	Your development team might have one shared repository for
	your project's <quote>0.9</quote> release, and another,
	containing different changes, for the <quote>1.0</quote>
	release.</para>

      <para id="x_db">Given this, you can imagine that the consequences could be
	messy if you had a local <quote>0.9</quote> repository, and
	accidentally pulled changes from the shared <quote>1.0</quote>
	repository into it.  At worst, you could be paying
	insufficient attention, and push those changes into the shared
	<quote>0.9</quote> tree, confusing your entire team (but don't
	worry, we'll return to this horror scenario later).  However,
	it's more likely that you'll notice immediately, because
	Mercurial will display the URL it's pulling from, or you will
	see it pull a suspiciously large number of changes into the
	repository.</para>

      <para id="x_dc">The <command role="hg-cmd">hg rollback</command> command
	will work nicely to expunge all of the changesets that you
	just pulled.  Mercurial groups all changes from one <command
	  role="hg-cmd">hg pull</command> into a single transaction,
	so one <command role="hg-cmd">hg rollback</command> is all you
	need to undo this mistake.</para>

    </sect2>
    <sect2 id="sec:undo:rollback-after-push">
      <title>Rolling back is useless once you've pushed</title>

      <para id="x_dd">The value of the <command role="hg-cmd">hg
	  rollback</command> command drops to zero once you've pushed
	your changes to another repository.  Rolling back a change
	makes it disappear entirely, but <emphasis>only</emphasis> in
	the repository in which you perform the <command
	  role="hg-cmd">hg rollback</command>.  Because a rollback
	eliminates history, there's no way for the disappearance of a
	change to propagate between repositories.</para>

      <para id="x_de">If you've pushed a change to another
	repository&emdash;particularly if it's a shared
	repository&emdash;it has essentially <quote>escaped into the
	  wild,</quote> and you'll have to recover from your mistake
	in a different way.  If you push a changeset somewhere, then
	roll it back, then pull from the repository you pushed to, the
	changeset you thought you'd gotten rid of will simply reappear
	in your repository.</para>

      <para id="x_df">(If you absolutely know for sure that the change
	you want to roll back is the most recent change in the
	repository that you pushed to, <emphasis>and</emphasis> you
	know that nobody else could have pulled it from that
	repository, you can roll back the changeset there, too, but
	you really should not expect this to work reliably.  Sooner or
	later a change really will make it into a repository that you
	don't directly control (or have forgotten about), and come
	back to bite you.)</para>

    </sect2>
    <sect2>
      <title>You can only roll back once</title>

      <para id="x_e0">Mercurial stores exactly one transaction in its
	transaction log; that transaction is the most recent one that
	occurred in the repository. This means that you can only roll
	back one transaction.  If you expect to be able to roll back
	one transaction, then its predecessor, this is not the
	behavior you will get.</para>

      &interaction.rollback.twice;

      <para id="x_e1">Once you've rolled back one transaction in a repository,
	you can't roll back again in that repository until you perform
	another commit or pull.</para>

    </sect2>
  </sect1>
  <sect1>
    <title>Reverting the mistaken change</title>

    <para id="x_e2">If you make a modification to a file, and decide that you
      really didn't want to change the file at all, and you haven't
      yet committed your changes, the <command role="hg-cmd">hg
	revert</command> command is the one you'll need.  It looks at
      the changeset that's the parent of the working directory, and
      restores the contents of the file to their state as of that
      changeset. (That's a long-winded way of saying that, in the
      normal case, it undoes your modifications.)</para>

    <para id="x_e3">Let's illustrate how the <command role="hg-cmd">hg
	revert</command> command works with yet another small example.
      We'll begin by modifying a file that Mercurial is already
      tracking.</para>

    &interaction.daily.revert.modify;

    <para id="x_e4">If we don't
      want that change, we can simply <command role="hg-cmd">hg
	revert</command> the file.</para>

      &interaction.daily.revert.unmodify;

    <para id="x_e5">The <command role="hg-cmd">hg revert</command> command
      provides us with an extra degree of safety by saving our
      modified file with a <filename>.orig</filename>
      extension.</para>

    &interaction.daily.revert.status;

    <tip>
      <title>Be careful with <filename>.orig</filename> files</title>

      <para id="x_6b8">It's extremely unlikely that you are either using
	Mercurial to manage files with <filename>.orig</filename>
	extensions or that you even care about the contents of such
	files.  Just in case, though, it's useful to remember that
	<command role="hg-cmd">hg revert</command> will
	unconditionally overwrite an existing file with a
	<filename>.orig</filename> extension. For instance, if you
	already have a file named <filename>foo.orig</filename> when
	you revert <filename>foo</filename>, the contents of
	<filename>foo.orig</filename> will be clobbered.</para>
    </tip>

    <para id="x_e6">Here is a summary of the cases that the <command
	role="hg-cmd">hg revert</command> command can deal with.  We
      will describe each of these in more detail in the section that
      follows.</para>
    <itemizedlist>
      <listitem><para id="x_e7">If you modify a file, it will restore the file
	  to its unmodified state.</para>
      </listitem>
      <listitem><para id="x_e8">If you <command role="hg-cmd">hg add</command> a
	  file, it will undo the <quote>added</quote> state of the
	  file, but leave the file itself untouched.</para>
      </listitem>
      <listitem><para id="x_e9">If you delete a file without telling Mercurial,
	  it will restore the file to its unmodified contents.</para>
      </listitem>
      <listitem><para id="x_ea">If you use the <command role="hg-cmd">hg
	    remove</command> command to remove a file, it will undo
	  the <quote>removed</quote> state of the file, and restore
	  the file to its unmodified contents.</para>
      </listitem></itemizedlist>

    <sect2 id="sec:undo:mgmt">
      <title>File management errors</title>

      <para id="x_eb">The <command role="hg-cmd">hg revert</command> command is
	useful for more than just modified files.  It lets you reverse
	the results of all of Mercurial's file management
	commands&emdash;<command role="hg-cmd">hg add</command>,
	<command role="hg-cmd">hg remove</command>, and so on.</para>

      <para id="x_ec">If you <command role="hg-cmd">hg add</command> a file,
	then decide that in fact you don't want Mercurial to track it,
	use <command role="hg-cmd">hg revert</command> to undo the
	add.  Don't worry; Mercurial will not modify the file in any
	way.  It will just <quote>unmark</quote> the file.</para>

      &interaction.daily.revert.add;

      <para id="x_ed">Similarly, if you ask Mercurial to <command
	  role="hg-cmd">hg remove</command> a file, you can use
	<command role="hg-cmd">hg revert</command> to restore it to
	the contents it had as of the parent of the working directory.
	&interaction.daily.revert.remove; This works just as
	well for a file that you deleted by hand, without telling
	Mercurial (recall that in Mercurial terminology, this kind of
	file is called <quote>missing</quote>).</para>

      &interaction.daily.revert.missing;

      <para id="x_ee">If you revert a <command role="hg-cmd">hg copy</command>,
	the copied-to file remains in your working directory
	afterwards, untracked.  Since a copy doesn't affect the
	copied-from file in any way, Mercurial doesn't do anything
	with the copied-from file.</para>

      &interaction.daily.revert.copy;
    </sect2>
  </sect1>

  <sect1>
    <title>Dealing with committed changes</title>

    <para id="x_f5">Consider a case where you have committed a change
      <emphasis>a</emphasis>, and another change
      <emphasis>b</emphasis> on top of it; you then realise that
      change <emphasis>a</emphasis> was incorrect.  Mercurial lets you
      <quote>back out</quote> an entire changeset automatically, and
      building blocks that let you reverse part of a changeset by
      hand.</para>

    <para id="x_f6">Before you read this section, here's something to
      keep in mind: the <command role="hg-cmd">hg backout</command>
      command undoes the effect of a change by
      <emphasis>adding</emphasis> to your repository's history, not by
      modifying or erasing it.  It's the right tool to use if you're
      fixing bugs, but not if you're trying to undo some change that
      has catastrophic consequences.  To deal with those, see
      <xref linkend="sec:undo:aaaiiieee"/>.</para>

    <sect2>
      <title>Backing out a changeset</title>

      <para id="x_f7">The <command role="hg-cmd">hg backout</command> command
	lets you <quote>undo</quote> the effects of an entire
	changeset in an automated fashion.  Because Mercurial's
	history is immutable, this command <emphasis>does
	  not</emphasis> get rid of the changeset you want to undo.
	Instead, it creates a new changeset that
	<emphasis>reverses</emphasis> the effect of the to-be-undone
	changeset.</para>

      <para id="x_f8">The operation of the <command role="hg-cmd">hg
	  backout</command> command is a little intricate, so let's
	illustrate it with some examples.  First, we'll create a
	repository with some simple changes.</para>

      &interaction.backout.init;

      <para id="x_f9">The <command role="hg-cmd">hg backout</command> command
	takes a single changeset ID as its argument; this is the
	changeset to back out.  Normally, <command role="hg-cmd">hg
	  backout</command> will drop you into a text editor to write
	a commit message, so you can record why you're backing the
	change out.  In this example, we provide a commit message on
	the command line using the <option
	  role="hg-opt-backout">-m</option> option.</para>

    </sect2>
    <sect2>
      <title>Backing out the tip changeset</title>

      <para id="x_fa">We're going to start by backing out the last changeset we
	committed.</para>

      &interaction.backout.simple;

      <para id="x_fb">You can see that the second line from
	<filename>myfile</filename> is no longer present.  Taking a
	look at the output of <command role="hg-cmd">hg log</command>
	gives us an idea of what the <command role="hg-cmd">hg
	  backout</command> command has done.
	&interaction.backout.simple.log; Notice that the new changeset
	that <command role="hg-cmd">hg backout</command> has created
	is a child of the changeset we backed out.  It's easier to see
	this in <xref linkend="fig:undo:backout"/>, which presents a
	graphical view of the change history.  As you can see, the
	history is nice and linear.</para>

      <figure id="fig:undo:backout">
	<title>Backing out a change using the <command
	    role="hg-cmd">hg backout</command> command</title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/undo-simple.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

    </sect2>
    <sect2>
      <title>Backing out a non-tip change</title>

      <para id="x_fd">If you want to back out a change other than the last one
	you committed, pass the <option
	  role="hg-opt-backout">--merge</option> option to the
	<command role="hg-cmd">hg backout</command> command.</para>

      &interaction.backout.non-tip.clone;

      <para id="x_fe">This makes backing out any changeset a
	<quote>one-shot</quote> operation that's usually simple and
	fast.</para>

      &interaction.backout.non-tip.backout;

      <para id="x_ff">If you take a look at the contents of
	<filename>myfile</filename> after the backout finishes, you'll
	see that the first and third changes are present, but not the
	second.</para>

      &interaction.backout.non-tip.cat;

      <para id="x_100">As the graphical history in <xref
	  linkend="fig:undo:backout-non-tip"/> illustrates, Mercurial
	still commits one change in this kind of situation (the
	box-shaped node is the ones that Mercurial commits
	automatically), but the revision graph now looks different.
	Before Mercurial begins the backout process, it first
	remembers what the current parent of the working directory is.
	It then backs out the target changeset, and commits that as a
	changeset.  Finally, it merges back to the previous parent of
	the working directory, but notice that it <emphasis>does not
	  commit</emphasis> the result of the merge.  The repository
	now contains two heads, and the working directory is in a
	merge state.</para>

      <figure id="fig:undo:backout-non-tip">
	<title>Automated backout of a non-tip change using the
	  <command role="hg-cmd">hg backout</command> command</title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/undo-non-tip.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

      <para id="x_103">The result is that you end up <quote>back where you
	  were</quote>, only with some extra history that undoes the
	effect of the changeset you wanted to back out.</para>

      <para id="x_6b9">You might wonder why Mercurial does not commit the result
	of the merge that it performed.  The reason lies in Mercurial
	behaving conservatively: a merge naturally has more scope for
	error than simply undoing the effect of the tip changeset,
	so your work will be safest if you first inspect (and test!)
	the result of the merge, <emphasis>then</emphasis> commit
	it.</para>

      <sect3>
	<title>Always use the <option
	    role="hg-opt-backout">--merge</option> option</title>

	<para id="x_104">In fact, since the <option
	    role="hg-opt-backout">--merge</option> option will do the
	  <quote>right thing</quote> whether or not the changeset
	  you're backing out is the tip (i.e. it won't try to merge if
	  it's backing out the tip, since there's no need), you should
	  <emphasis>always</emphasis> use this option when you run the
	  <command role="hg-cmd">hg backout</command> command.</para>

      </sect3>
    </sect2>
    <sect2>
      <title>Gaining more control of the backout process</title>

      <para id="x_105">While I've recommended that you always use the <option
	  role="hg-opt-backout">--merge</option> option when backing
	out a change, the <command role="hg-cmd">hg backout</command>
	command lets you decide how to merge a backout changeset.
	Taking control of the backout process by hand is something you
	will rarely need to do, but it can be useful to understand
	what the <command role="hg-cmd">hg backout</command> command
	is doing for you automatically.  To illustrate this, let's
	clone our first repository, but omit the backout change that
	it contains.</para>

      &interaction.backout.manual.clone;

      <para id="x_106">As with our
	earlier example, We'll commit a third changeset, then back out
	its parent, and see what happens.</para>

      &interaction.backout.manual.backout;

      <para id="x_107">Our new changeset is again a descendant of the changeset
	we backout out; it's thus a new head, <emphasis>not</emphasis>
	a descendant of the changeset that was the tip.  The <command
	  role="hg-cmd">hg backout</command> command was quite
	explicit in telling us this.</para>

      &interaction.backout.manual.log;

      <para id="x_108">Again, it's easier to see what has happened by looking at
	a graph of the revision history, in <xref
	  linkend="fig:undo:backout-manual"/>.  This makes it clear
	that when we use <command role="hg-cmd">hg backout</command>
	to back out a change other than the tip, Mercurial adds a new
	head to the repository (the change it committed is
	box-shaped).</para>

      <figure id="fig:undo:backout-manual">
	<title>Backing out a change using the <command
	    role="hg-cmd">hg backout</command> command</title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/undo-manual.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

      <para id="x_10a">After the <command role="hg-cmd">hg backout</command>
	command has completed, it leaves the new
	<quote>backout</quote> changeset as the parent of the working
	directory.</para>

      &interaction.backout.manual.parents;

      <para id="x_10b">Now we have two isolated sets of changes.</para>

      &interaction.backout.manual.heads;

      <para id="x_10c">Let's think about what we expect to see as the contents of
	<filename>myfile</filename> now.  The first change should be
	present, because we've never backed it out.  The second change
	should be missing, as that's the change we backed out.  Since
	the history graph shows the third change as a separate head,
	we <emphasis>don't</emphasis> expect to see the third change
	present in <filename>myfile</filename>.</para>

      &interaction.backout.manual.cat;

      <para id="x_10d">To get the third change back into the file, we just do a
	normal merge of our two heads.</para>

      &interaction.backout.manual.merge;

      <para id="x_10e">Afterwards, the graphical history of our
	repository looks like
	<xref linkend="fig:undo:backout-manual-merge"/>.</para>

      <figure id="fig:undo:backout-manual-merge">
	<title>Manually merging a backout change</title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/undo-manual-merge.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

    </sect2>
    <sect2>
      <title>Why <command role="hg-cmd">hg backout</command> works as
	it does</title>

      <para id="x_110">Here's a brief description of how the <command
	  role="hg-cmd">hg backout</command> command works.</para>
      <orderedlist>
	<listitem><para id="x_111">It ensures that the working directory is
	    <quote>clean</quote>, i.e. that the output of <command
	      role="hg-cmd">hg status</command> would be empty.</para>
	</listitem>
	<listitem><para id="x_112">It remembers the current parent of the working
	    directory.  Let's call this changeset
	    <literal>orig</literal>.</para>
	</listitem>
	<listitem><para id="x_113">It does the equivalent of a <command
	      role="hg-cmd">hg update</command> to sync the working
	    directory to the changeset you want to back out.  Let's
	    call this changeset <literal>backout</literal>.</para>
	</listitem>
	<listitem><para id="x_114">It finds the parent of that changeset.  Let's
	    call that changeset <literal>parent</literal>.</para>
	</listitem>
	<listitem><para id="x_115">For each file that the
	    <literal>backout</literal> changeset affected, it does the
	    equivalent of a <command role="hg-cmd">hg revert -r
	      parent</command> on that file, to restore it to the
	    contents it had before that changeset was
	    committed.</para>
	</listitem>
	<listitem><para id="x_116">It commits the result as a new changeset.
	    This changeset has <literal>backout</literal> as its
	    parent.</para>
	</listitem>
	<listitem><para id="x_117">If you specify <option
	      role="hg-opt-backout">--merge</option> on the command
	    line, it merges with <literal>orig</literal>, and commits
	    the result of the merge.</para>
	</listitem></orderedlist>

      <para id="x_118">An alternative way to implement the <command
	  role="hg-cmd">hg backout</command> command would be to
	<command role="hg-cmd">hg export</command> the
	to-be-backed-out changeset as a diff, then use the <option
	  role="cmd-opt-patch">--reverse</option> option to the
	<command>patch</command> command to reverse the effect of the
	change without fiddling with the working directory.  This
	sounds much simpler, but it would not work nearly as
	well.</para>

      <para id="x_119">The reason that <command role="hg-cmd">hg
	  backout</command> does an update, a commit, a merge, and
	another commit is to give the merge machinery the best chance
	to do a good job when dealing with all the changes
	<emphasis>between</emphasis> the change you're backing out and
	the current tip.</para>

      <para id="x_11a">If you're backing out a changeset that's 100 revisions
	back in your project's history, the chances that the
	<command>patch</command> command will be able to apply a
	reverse diff cleanly are not good, because intervening changes
	are likely to have <quote>broken the context</quote> that
	<command>patch</command> uses to determine whether it can
	apply a patch (if this sounds like gibberish, see <xref
	  linkend="sec:mq:patch"/> for a
	discussion of the <command>patch</command> command).  Also,
	Mercurial's merge machinery will handle files and directories
	being renamed, permission changes, and modifications to binary
	files, none of which <command>patch</command> can deal
	with.</para>

    </sect2>
  </sect1>
  <sect1 id="sec:undo:aaaiiieee">
    <title>Changes that should never have been</title>

    <para id="x_11b">Most of the time, the <command role="hg-cmd">hg
	backout</command> command is exactly what you need if you want
      to undo the effects of a change.  It leaves a permanent record
      of exactly what you did, both when committing the original
      changeset and when you cleaned up after it.</para>

    <para id="x_11c">On rare occasions, though, you may find that you've
      committed a change that really should not be present in the
      repository at all.  For example, it would be very unusual, and
      usually considered a mistake, to commit a software project's
      object files as well as its source files.  Object files have
      almost no intrinsic value, and they're <emphasis>big</emphasis>,
      so they increase the size of the repository and the amount of
      time it takes to clone or pull changes.</para>

    <para id="x_11d">Before I discuss the options that you have if you commit a
      <quote>brown paper bag</quote> change (the kind that's so bad
      that you want to pull a brown paper bag over your head), let me
      first discuss some approaches that probably won't work.</para>

    <para id="x_11e">Since Mercurial treats history as
      accumulative&emdash;every change builds on top of all changes
      that preceded it&emdash;you generally can't just make disastrous
      changes disappear.  The one exception is when you've just
      committed a change, and it hasn't been pushed or pulled into
      another repository.  That's when you can safely use the <command
	role="hg-cmd">hg rollback</command> command, as I detailed in
      <xref linkend="sec:undo:rollback"/>.</para>

    <para id="x_11f">After you've pushed a bad change to another repository, you
      <emphasis>could</emphasis> still use <command role="hg-cmd">hg
	rollback</command> to make your local copy of the change
      disappear, but it won't have the consequences you want.  The
      change will still be present in the remote repository, so it
      will reappear in your local repository the next time you
      pull.</para>

    <para id="x_120">If a situation like this arises, and you know which
      repositories your bad change has propagated into, you can
      <emphasis>try</emphasis> to get rid of the change from
      <emphasis>every</emphasis> one of those repositories.  This is,
      of course, not a satisfactory solution: if you miss even a
      single repository while you're expunging, the change is still
      <quote>in the wild</quote>, and could propagate further.</para>

    <para id="x_121">If you've committed one or more changes
      <emphasis>after</emphasis> the change that you'd like to see
      disappear, your options are further reduced. Mercurial doesn't
      provide a way to <quote>punch a hole</quote> in history, leaving
      changesets intact.</para>

    <sect2>
      <title>Backing out a merge</title>

      <para id="x_6ba">Since merges are often complicated, it is not unheard of
	for a merge to be mangled badly, but committed erroneously.
	Mercurial provides an important safeguard against bad merges
	by refusing to commit unresolved files, but human ingenuity
	guarantees that it is still possible to mess a merge up and
	commit it.</para>

      <para id="x_6bb">Given a bad merge that has been committed, usually the
	best way to approach it is to simply try to repair the damage
	by hand.  A complete disaster that cannot be easily fixed up
	by hand ought to be very rare, but the <command
	  role="hg-cmd">hg backout</command> command may help in
	making the cleanup easier. It offers a <option
	  role="hg-opt-backout">--parent</option> option, which lets
	you specify which parent to revert to when backing out a
	merge.</para>

      <figure id="fig:undo:bad-merge-1">
	<title>A bad merge</title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/bad-merge-1.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

      <para id="x_6bc">Suppose we have a revision graph like that in <xref
	  linkend="fig:undo:bad-merge-1"/>.  What we'd like is to
	<emphasis>redo</emphasis> the merge of revisions 2 and
	3.</para>

      <para id="x_6bd">One way to do so would be as follows.</para>

      <orderedlist>
	<listitem>
	  <para id="x_6be">Call <command role="hg-cmd">hg backout --rev=4
	      --parent=2</command>.  This tells <command
	      role="hg-cmd">hg backout</command> to back out revision
	    4, which is the bad merge, and to when deciding which
	    revision to prefer, to choose parent 2, one of the parents
	    of the merge.  The effect can be seen in <xref
	      linkend="fig:undo:bad-merge-2"/>.</para>
	  <figure id="fig:undo:bad-merge-2">
	    <title>Backing out the merge, favoring one parent</title>
	    <mediaobject>
	      <imageobject><imagedata fileref="figs/bad-merge-2.png"/></imageobject>
	      <textobject><phrase>XXX add text</phrase></textobject>
	    </mediaobject>
	  </figure>
	</listitem>

	<listitem>
	  <para id="x_6bf">Call <command role="hg-cmd">hg backout --rev=4
	      --parent=3</command>.  This tells <command
	      role="hg-cmd">hg backout</command> to back out revision
	    4 again, but this time to choose parent 3, the other
	    parent of the merge.  The result is visible in <xref
	    linkend="fig:undo:bad-merge-3"/>, in which the repository
	    now contains three heads.</para>
	  <figure id="fig:undo:bad-merge-3">
	    <title>Backing out the merge, favoring the other
	      parent</title>
	    <mediaobject>
	      <imageobject><imagedata fileref="figs/bad-merge-3.png"/></imageobject>
	      <textobject><phrase>XXX add text</phrase></textobject>
	    </mediaobject>
	  </figure>
	</listitem>

	<listitem>
	  <para id="x_6c0">Redo the bad merge by merging the two backout heads,
	    which reduces the number of heads in the repository to
	    two, as can be seen in <xref
	      linkend="fig:undo:bad-merge-4"/>.</para>
	  <figure id="fig:undo:bad-merge-4">
	    <title>Merging the backouts</title>
	    <mediaobject>
	      <imageobject><imagedata fileref="figs/bad-merge-4.png"/></imageobject>
	      <textobject><phrase>XXX add text</phrase></textobject>
	    </mediaobject>
	  </figure>
	</listitem>

	<listitem>
	  <para id="x_6c1">Merge with the commit that was made after the bad
	    merge, as shown in <xref
	      linkend="fig:undo:bad-merge-5"/>.</para>
	  <figure id="fig:undo:bad-merge-5">
	    <title>Merging the backouts</title>
	    <mediaobject>
	      <imageobject><imagedata fileref="figs/bad-merge-5.png"/></imageobject>
	      <textobject><phrase>XXX add text</phrase></textobject>
	    </mediaobject>
	  </figure>
	</listitem>
      </orderedlist>
    </sect2>

    <sect2>
      <title>Protect yourself from <quote>escaped</quote>
	changes</title>

      <para id="x_123">If you've committed some changes to your local repository
	and they've been pushed or pulled somewhere else, this isn't
	necessarily a disaster.  You can protect yourself ahead of
	time against some classes of bad changeset.  This is
	particularly easy if your team usually pulls changes from a
	central repository.</para>

      <para id="x_124">By configuring some hooks on that repository to validate
	incoming changesets (see chapter <xref linkend="chap:hook"/>),
	you can
	automatically prevent some kinds of bad changeset from being
	pushed to the central repository at all.  With such a
	configuration in place, some kinds of bad changeset will
	naturally tend to <quote>die out</quote> because they can't
	propagate into the central repository.  Better yet, this
	happens without any need for explicit intervention.</para>

      <para id="x_125">For instance, an incoming change hook that
	verifies that a changeset will actually compile can prevent
	people from inadvertently <quote>breaking the
	  build</quote>.</para>
    </sect2>

    <sect2>
      <title>What to do about sensitive changes that escape</title>

      <para id="x_6c2">Even a carefully run project can suffer an unfortunate
	event such as the committing and uncontrolled propagation of a
	file that contains important passwords.</para>

      <para id="x_6c3">If something like this happens to you, and the information
	that gets accidentally propagated is truly sensitive, your
	first step should be to mitigate the effect of the leak
	without trying to control the leak itself. If you are not 100%
	certain that you know exactly who could have seen the changes,
	you should immediately change passwords, cancel credit cards,
	or find some other way to make sure that the information that
	has leaked is no longer useful.  In other words, assume that
	the change has propagated far and wide, and that there's
	nothing more you can do.</para>

      <para id="x_6c4">You might hope that there would be mechanisms you could
	use to either figure out who has seen a change or to erase the
	change permanently everywhere, but there are good reasons why
	these are not possible.</para>

      <para id="x_6c5">Mercurial does not provide an audit trail of who has
	pulled changes from a repository, because it is usually either
	impossible to record such information or trivial to spoof it.
	In a multi-user or networked environment, you should thus be
	extremely skeptical of yourself if you think that you have
	identified every place that a sensitive changeset has
	propagated to.  Don't forget that people can and will send
	bundles by email, have their backup software save data
	offsite, carry repositories on USB sticks, and find other
	completely innocent ways to confound your attempts to track
	down every copy of a problematic change.</para>

      <para id="x_6c6">Mercurial also does not provide a way to make a file or
	changeset completely disappear from history, because there is
	no way to enforce its disappearance; someone could easily
	modify their copy of Mercurial to ignore such directives. In
	addition, even if Mercurial provided such a capability,
	someone who simply hadn't pulled a <quote>make this file
	  disappear</quote> changeset wouldn't be affected by it, nor
	would web crawlers visiting at the wrong time, disk backups,
	or other mechanisms.  Indeed, no distributed revision control
	system can make data reliably vanish. Providing the illusion
	of such control could easily give a false sense of security,
	and be worse than not providing it at all.</para>
    </sect2>
  </sect1>

  <sect1 id="sec:undo:bisect">
    <title>Finding the source of a bug</title>

    <para id="x_126">While it's all very well to be able to back out a changeset
      that introduced a bug, this requires that you know which
      changeset to back out.  Mercurial provides an invaluable
      command, called <command role="hg-cmd">hg bisect</command>, that
      helps you to automate this process and accomplish it very
      efficiently.</para>

    <para id="x_127">The idea behind the <command role="hg-cmd">hg
	bisect</command> command is that a changeset has introduced
      some change of behavior that you can identify with a simple
      pass/fail test.  You don't know which piece of code introduced the
      change, but you know how to test for the presence of the bug.
      The <command role="hg-cmd">hg bisect</command> command uses your
      test to direct its search for the changeset that introduced the
      code that caused the bug.</para>

    <para id="x_128">Here are a few scenarios to help you understand how you
      might apply this command.</para>
    <itemizedlist>
      <listitem><para id="x_129">The most recent version of your software has a
	  bug that you remember wasn't present a few weeks ago, but
	  you don't know when it was introduced.  Here, your binary
	  test checks for the presence of that bug.</para>
      </listitem>
      <listitem><para id="x_12a">You fixed a bug in a rush, and now it's time to
	  close the entry in your team's bug database.  The bug
	  database requires a changeset ID when you close an entry,
	  but you don't remember which changeset you fixed the bug in.
	  Once again, your binary test checks for the presence of the
	  bug.</para>
      </listitem>
      <listitem><para id="x_12b">Your software works correctly, but runs 15%
	  slower than the last time you measured it.  You want to know
	  which changeset introduced the performance regression.  In
	  this case, your binary test measures the performance of your
	  software, to see whether it's <quote>fast</quote> or
	  <quote>slow</quote>.</para>
      </listitem>
      <listitem><para id="x_12c">The sizes of the components of your project that
	  you ship exploded recently, and you suspect that something
	  changed in the way you build your project.</para>
      </listitem></itemizedlist>

    <para id="x_12d">From these examples, it should be clear that the <command
	role="hg-cmd">hg bisect</command> command is not useful only
      for finding the sources of bugs.  You can use it to find any
      <quote>emergent property</quote> of a repository (anything that
      you can't find from a simple text search of the files in the
      tree) for which you can write a binary test.</para>

    <para id="x_12e">We'll introduce a little bit of terminology here, just to
      make it clear which parts of the search process are your
      responsibility, and which are Mercurial's.  A
      <emphasis>test</emphasis> is something that
      <emphasis>you</emphasis> run when <command role="hg-cmd">hg
	bisect</command> chooses a changeset.  A
      <emphasis>probe</emphasis> is what <command role="hg-cmd">hg
	bisect</command> runs to tell whether a revision is good.
      Finally, we'll use the word <quote>bisect</quote>, as both a
      noun and a verb, to stand in for the phrase <quote>search using
	the <command role="hg-cmd">hg bisect</command>
	command</quote>.</para>

    <para id="x_12f">One simple way to automate the searching process would be
      simply to probe every changeset.  However, this scales poorly.
      If it took ten minutes to test a single changeset, and you had
      10,000 changesets in your repository, the exhaustive approach
      would take on average 35 <emphasis>days</emphasis> to find the
      changeset that introduced a bug.  Even if you knew that the bug
      was introduced by one of the last 500 changesets, and limited
      your search to those, you'd still be looking at over 40 hours to
      find the changeset that introduced your bug.</para>

    <para id="x_130">What the <command role="hg-cmd">hg bisect</command> command
      does is use its knowledge of the <quote>shape</quote> of your
      project's revision history to perform a search in time
      proportional to the <emphasis>logarithm</emphasis> of the number
      of changesets to check (the kind of search it performs is called
      a dichotomic search).  With this approach, searching through
      10,000 changesets will take less than three hours, even at ten
      minutes per test (the search will require about 14 tests).
      Limit your search to the last hundred changesets, and it will
      take only about an hour (roughly seven tests).</para>

    <para id="x_131">The <command role="hg-cmd">hg bisect</command> command is
      aware of the <quote>branchy</quote> nature of a Mercurial
      project's revision history, so it has no problems dealing with
      branches, merges, or multiple heads in a repository.  It can
      prune entire branches of history with a single probe, which is
      how it operates so efficiently.</para>

    <sect2>
      <title>Using the <command role="hg-cmd">hg bisect</command>
	command</title>

      <para id="x_132">Here's an example of <command role="hg-cmd">hg
	  bisect</command> in action.</para>

      <note>
	<para id="x_133">  In versions 0.9.5 and earlier of Mercurial, <command
	    role="hg-cmd">hg bisect</command> was not a core command:
	  it was distributed with Mercurial as an extension. This
	  section describes the built-in command, not the old
	  extension.</para>
      </note>

      <para id="x_134">Now let's create a repository, so that we can try out the
	<command role="hg-cmd">hg bisect</command> command in
	isolation.</para>

      &interaction.bisect.init;

      <para id="x_135">We'll simulate a project that has a bug in it in a
	simple-minded way: create trivial changes in a loop, and
	nominate one specific change that will have the
	<quote>bug</quote>.  This loop creates 35 changesets, each
	adding a single file to the repository. We'll represent our
	<quote>bug</quote> with a file that contains the text <quote>i
	  have a gub</quote>.</para>

      &interaction.bisect.commits;

      <para id="x_136">The next thing that we'd like to do is figure out how to
	use the <command role="hg-cmd">hg bisect</command> command.
	We can use Mercurial's normal built-in help mechanism for
	this.</para>

      &interaction.bisect.help;

      <para id="x_137">The <command role="hg-cmd">hg bisect</command> command
	works in steps.  Each step proceeds as follows.</para>
      <orderedlist>
	<listitem><para id="x_138">You run your binary test.</para>
	  <itemizedlist>
	    <listitem><para id="x_139">If the test succeeded, you tell <command
		  role="hg-cmd">hg bisect</command> by running the
		<command role="hg-cmd">hg bisect --good</command>
		command.</para>
	    </listitem>
	    <listitem><para id="x_13a">If it failed, run the <command
		  role="hg-cmd">hg bisect --bad</command>
		command.</para></listitem></itemizedlist>
	</listitem>
	<listitem><para id="x_13b">The command uses your information to decide
	    which changeset to test next.</para>
	</listitem>
	<listitem><para id="x_13c">It updates the working directory to that
	    changeset, and the process begins again.</para>
	</listitem></orderedlist>
      <para id="x_13d">The process ends when <command role="hg-cmd">hg
	  bisect</command> identifies a unique changeset that marks
	the point where your test transitioned from
	<quote>succeeding</quote> to <quote>failing</quote>.</para>

      <para id="x_13e">To start the search, we must run the <command
	  role="hg-cmd">hg bisect --reset</command> command.</para>

      &interaction.bisect.search.init;

      <para id="x_13f">In our case, the binary test we use is simple: we check to
	see if any file in the repository contains the string <quote>i
	  have a gub</quote>.  If it does, this changeset contains the
	change that <quote>caused the bug</quote>.  By convention, a
	changeset that has the property we're searching for is
	<quote>bad</quote>, while one that doesn't is
	<quote>good</quote>.</para>

      <para id="x_140">Most of the time, the revision to which the working
	directory is synced (usually the tip) already exhibits the
	problem introduced by the buggy change, so we'll mark it as
	<quote>bad</quote>.</para>

      &interaction.bisect.search.bad-init;

      <para id="x_141">Our next task is to nominate a changeset that we know
	<emphasis>doesn't</emphasis> have the bug; the <command
	  role="hg-cmd">hg bisect</command> command will
	<quote>bracket</quote> its search between the first pair of
	good and bad changesets.  In our case, we know that revision
	10 didn't have the bug.  (I'll have more words about choosing
	the first <quote>good</quote> changeset later.)</para>

      &interaction.bisect.search.good-init;

      <para id="x_142">Notice that this command printed some output.</para>
      <itemizedlist>
	<listitem><para id="x_143">It told us how many changesets it must
	    consider before it can identify the one that introduced
	    the bug, and how many tests that will require.</para>
	</listitem>
	<listitem><para id="x_144">It updated the working directory to the next
	    changeset to test, and told us which changeset it's
	    testing.</para>
	</listitem></itemizedlist>

      <para id="x_145">We now run our test in the working directory.  We use the
	<command>grep</command> command to see if our
	<quote>bad</quote> file is present in the working directory.
	If it is, this revision is bad; if not, this revision is good.
	&interaction.bisect.search.step1;</para>

      <para id="x_146">This test looks like a perfect candidate for automation,
	so let's turn it into a shell function.</para>
      &interaction.bisect.search.mytest;

      <para id="x_147">We can now run an entire test step with a single command,
	<literal>mytest</literal>.</para>

      &interaction.bisect.search.step2;

      <para id="x_148">A few more invocations of our canned test step command,
	and we're done.</para>

      &interaction.bisect.search.rest;

      <para id="x_149">Even though we had 40 changesets to search through, the
	<command role="hg-cmd">hg bisect</command> command let us find
	the changeset that introduced our <quote>bug</quote> with only
	five tests.  Because the number of tests that the <command
	  role="hg-cmd">hg bisect</command> command performs grows
	logarithmically with the number of changesets to search, the
	advantage that it has over the <quote>brute force</quote>
	search approach increases with every changeset you add.</para>

    </sect2>
    <sect2>
      <title>Cleaning up after your search</title>

      <para id="x_14a">When you're finished using the <command role="hg-cmd">hg
	  bisect</command> command in a repository, you can use the
	<command role="hg-cmd">hg bisect --reset</command> command to
	drop the information it was using to drive your search.  The
	command doesn't use much space, so it doesn't matter if you
	forget to run this command.  However, <command
	  role="hg-cmd">hg bisect</command> won't let you start a new
	search in that repository until you do a <command
	  role="hg-cmd">hg bisect --reset</command>.</para>

      &interaction.bisect.search.reset;

    </sect2>
  </sect1>
  <sect1>
    <title>Tips for finding bugs effectively</title>

    <sect2>
      <title>Give consistent input</title>

      <para id="x_14b">The <command role="hg-cmd">hg bisect</command> command
	requires that you correctly report the result of every test
	you perform.  If you tell it that a test failed when it really
	succeeded, it <emphasis>might</emphasis> be able to detect the
	inconsistency.  If it can identify an inconsistency in your
	reports, it will tell you that a particular changeset is both
	good and bad. However, it can't do this perfectly; it's about
	as likely to report the wrong changeset as the source of the
	bug.</para>

    </sect2>
    <sect2>
      <title>Automate as much as possible</title>

      <para id="x_14c">When I started using the <command role="hg-cmd">hg
	  bisect</command> command, I tried a few times to run my
	tests by hand, on the command line.  This is an approach that
	I, at least, am not suited to.  After a few tries, I found
	that I was making enough mistakes that I was having to restart
	my searches several times before finally getting correct
	results.</para>

      <para id="x_14d">My initial problems with driving the <command
	  role="hg-cmd">hg bisect</command> command by hand occurred
	even with simple searches on small repositories; if the
	problem you're looking for is more subtle, or the number of
	tests that <command role="hg-cmd">hg bisect</command> must
	perform increases, the likelihood of operator error ruining
	the search is much higher.  Once I started automating my
	tests, I had much better results.</para>

      <para id="x_14e">The key to automated testing is twofold:</para>
      <itemizedlist>
	<listitem><para id="x_14f">always test for the same symptom, and</para>
	</listitem>
	<listitem><para id="x_150">always feed consistent input to the <command
	      role="hg-cmd">hg bisect</command> command.</para>
	</listitem></itemizedlist>
      <para id="x_151">In my tutorial example above, the <command>grep</command>
	command tests for the symptom, and the <literal>if</literal>
	statement takes the result of this check and ensures that we
	always feed the same input to the <command role="hg-cmd">hg
	  bisect</command> command.  The <literal>mytest</literal>
	function marries these together in a reproducible way, so that
	every test is uniform and consistent.</para>

    </sect2>
    <sect2>
      <title>Check your results</title>

      <para id="x_152">Because the output of a <command role="hg-cmd">hg
	  bisect</command> search is only as good as the input you
	give it, don't take the changeset it reports as the absolute
	truth.  A simple way to cross-check its report is to manually
	run your test at each of the following changesets:</para>
      <itemizedlist>
	<listitem><para id="x_153">The changeset that it reports as the first bad
	    revision.  Your test should still report this as
	    bad.</para>
	</listitem>
	<listitem><para id="x_154">The parent of that changeset (either parent,
	    if it's a merge). Your test should report this changeset
	    as good.</para>
	</listitem>
	<listitem><para id="x_155">A child of that changeset.  Your test should
	    report this changeset as bad.</para>
	</listitem></itemizedlist>

    </sect2>
    <sect2>
      <title>Beware interference between bugs</title>

      <para id="x_156">It's possible that your search for one bug could be
	disrupted by the presence of another.  For example, let's say
	your software crashes at revision 100, and worked correctly at
	revision 50.  Unknown to you, someone else introduced a
	different crashing bug at revision 60, and fixed it at
	revision 80.  This could distort your results in one of
	several ways.</para>

      <para id="x_157">It is possible that this other bug completely
	<quote>masks</quote> yours, which is to say that it occurs
	before your bug has a chance to manifest itself.  If you can't
	avoid that other bug (for example, it prevents your project
	from building), and so can't tell whether your bug is present
	in a particular changeset, the <command role="hg-cmd">hg
	  bisect</command> command cannot help you directly.  Instead,
	you can mark a changeset as untested by running <command
	  role="hg-cmd">hg bisect --skip</command>.</para>

      <para id="x_158">A different problem could arise if your test for a bug's
	presence is not specific enough.  If you check for <quote>my
	  program crashes</quote>, then both your crashing bug and an
	unrelated crashing bug that masks it will look like the same
	thing, and mislead <command role="hg-cmd">hg
	  bisect</command>.</para>

      <para id="x_159">Another useful situation in which to use <command
	  role="hg-cmd">hg bisect --skip</command> is if you can't
	test a revision because your project was in a broken and hence
	untestable state at that revision, perhaps because someone
	checked in a change that prevented the project from
	building.</para>

    </sect2>
    <sect2>
      <title>Bracket your search lazily</title>

      <para id="x_15a">Choosing the first <quote>good</quote> and
	<quote>bad</quote> changesets that will mark the end points of
	your search is often easy, but it bears a little discussion
	nevertheless.  From the perspective of <command
	  role="hg-cmd">hg bisect</command>, the <quote>newest</quote>
	changeset is conventionally <quote>bad</quote>, and the older
	changeset is <quote>good</quote>.</para>

      <para id="x_15b">If you're having trouble remembering when a suitable
	<quote>good</quote> change was, so that you can tell <command
	  role="hg-cmd">hg bisect</command>, you could do worse than
	testing changesets at random.  Just remember to eliminate
	contenders that can't possibly exhibit the bug (perhaps
	because the feature with the bug isn't present yet) and those
	where another problem masks the bug (as I discussed
	above).</para>

      <para id="x_15c">Even if you end up <quote>early</quote> by thousands of
	changesets or months of history, you will only add a handful
	of tests to the total number that <command role="hg-cmd">hg
	  bisect</command> must perform, thanks to its logarithmic
	behavior.</para>

    </sect2>
  </sect1>
</chapter>

<!--
local variables: 
sgml-parent-document: ("00book.xml" "book" "chapter")
end:
-->
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.