Source

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

<chapter id="chap:undo">
  <?dbhtml filename="finding-and-fixing-mistakes.html"?>
  <title>Поиск и исправление ваших ошибок</title>

  <para id="x_d2">Человек может ошибиться, но высококлассная система управления версиями берется исправить последствия. В этой главе мы расскажем о некоторых способах поиска проблем, закравшихся в ваш проект. Mercurial предоставляет высокоэффективные инструменты, позволяющие изолировать источник проблем и должным образом образом обработать.</para>

  <sect1>
    <title>Удаление локальной истории</title>

    <sect2>
      <title>Случайная фиксация</title>

      <para id="x_d3">Не часто, но постоянно у меня возникает проблема, что печатаю быстрее, чем думаю, в результате, зафиксированные изменения либо не законченные, либо просто ошибочные. Стандартный для меня тип не завершенных изменений, в том ,что я создал новый исходник, но забыл добавить (<command role="hg-cmd">hg add</command>) его. <quote>Просто ошибочные</quote> изменения не так часты, но не менее досаждающие.</para>

    </sect2>
    <sect2 id="sec:undo:rollback">
      <title>Откат транзакции</title>

      <para id="x_d4">В разделе <xref linkend="sec:concepts:txn"/> я упоминал, что Mercurial рассматривает каждую модификацию хранилища как <emphasis>транзакцию</emphasis>. Каждый раз, когда вы фиксируете изменения или подтягиваете изменения из другого хранилища, Mercurial запоминает, что вы сделали. Вы можете отменить, или <emphasis>откатить</emphasis>, только одно из этих действий с помощью команды <command role="hg-cmd">hg rollback</command>. (Смотрите раздел <xref linkend="sec:undo:rollback-after-push"/> о важном предупреждении о использовании данной команды.)</para>

      <para id="x_d5">Приведу пример частой собственной ошибки: фиксация изменений, в которых я создал новый файл, но забыл выполнить <command role="hg-cmd">hg add</command> для него.</para>

      &interaction.rollback.commit;

      <para id="x_d6">Вывод команды <command role="hg-cmd">hg status</command> после фиксации подтверждает ошибку.</para>

      &interaction.rollback.status;

      <para id="x_d7">Были зафиксированы изменения для файла <filename>a</filename>, но не для нового файла <filename>b</filename>. Если бы я отправил эти изменения в общее с коллегами хранилище, то велик шанс того, что что-то в <filename>a</filename> ссылается на <filename>b</filename>, отсутствующий в репозиториях коллег после того, как они получат мои изменения. В таком случае я мог бы стать объектом некоторого негодования.</para>

      <para id="x_d8">Однако, мне повезло &emdash; я заметил ошибку прежде, чем отослал изменения. Я воспользовался командой <command role="hg-cmd">hg rollback</command>, и Mercurial убрал последние измения.</para>

      &interaction.rollback.rollback;

      <para id="x_d9">Обратите внимание, что изменение отсутствует в истории хранилища, и репозиторий снова считает, что файл <filename>a</filename> в рабочей директории имеет не фиксированные модификации. Commit и rollback оставили рабочую директорию в том же состоянии, в котором она была перед commit; изменения полностью уничтожены. Теперь я могу безопасно выполнить <command role="hg-cmd">hg add</command> файл <filename>b</filename>, и снова запустить commit.</para>

      &interaction.rollback.add;

    </sect2>
    <sect2>
      <title>Ошибочное вытягивание</title>

      <para id="x_da">Стандартной методикой работы с Mercurial является поддержка разработки отдельных веток проекта в отдельных хранилищах. Ваша комманда разработчиков может содержать один репозиторий для релиза проекта версии <quote>0.9</quote>, и другой, для других изменений, войдущих в версию <quote>1.0</quote>.</para>

      <para id="x_db">На этом примере, можете представить себе неприятные последствия случайного вытягивания изменений из общего хранилища ветки <quote>1.0</quote> в ваш локальный репозиторий релиза <quote>0.9</quote>. В худшем случае, вы  заплатите за невнимательность втолкнув те самые изменения в общее <quote>0.9</quote> дерево, запутав остальных разработчиков. (Не волнуйтесь, к этому ужасному сценарию мы вернёмся позже). Впрочем, вероятнее всего, Вы заметите это сразу же, поскольку Mercurial покажет вам URL из которого происходит вытягивание. Или Вы обратите внимание на подозрительно большое число изменений в хранилище.</para>

      <para id="x_dc">Для исключения этих, только что втянутых правок, отлично подходит команда <command role="hg-cmd">hg rollback</command>. Mercurial группирует все изменения, внесенные командой <command role="hg-cmd">hg pull</command>, в одну трансакцию, поэтому всё, что вам нужно для исправления ошибки &emdash; одна команда <command role="hg-cmd">hg rollback</command>.</para>

    </sect2>
    <sect2 id="sec:undo:rollback-after-push">
      <title><command role="hg-cmd">hg rollback</command> бесполезен если изменения уже внесены.</title>

      <para id="x_dd">Ценность команды  <command role="hg-cmd">hg rollback</command> падает до нуля, как только вы втолкнете изменения в другое хранилище. Конечно, эта команда исправит ошибку, но <emphasis>только</emphasis> в том хранилище к которому вы её применяете. Поскольку rollback уничтожает историю, нет способа остановить распространение ошибочного изменения между хранилищами.</para>

      <para id="x_de">Если Вы втолкнули изменение в общее хранилище, оно по сути <quote>вырвалось на свободу</quote> и вам придётся исправлять ошибку другим способом. Что будет, если вы втолкнули набор изменений куда-либо, после чего стерли их у себя, а потом втянули то что вы только что проталкивали? Набор изменений, от которого (по вашему мнению) вы избавились, опять появится в Вашем хранилище.</para>

      <para id="x_df">(Если вы абсолютно точно знаете, что те изменения, которые вы собираетесь откатить, самые свежие в том самом хранилище, <emphasis>и</emphasis> вы знаете, что никто еще не успел их вытянуть из этого хранилища, то вы можете стереть их и там тоже. Но вам действительно не стоит ожидать что это будет работать надежно. Рано или поздно, изменения наконец таки попадут в неподконтрольное вам хранилище и вернутся назад, чтобы укусить вас.)</para>

    </sect2>
    <sect2>
      <title>Вы можете отменить только последнее изменение</title>

      <para id="x_e0">Mercurial хранит в своем логе только одну транзакцию &emdash; ту, что была выполнена последней  в данном хранилище. Это значит, что вы можете отменить только одну транзакцию. Если вы попытаетесь отменить еще одну, предшествующую последней, то вам не удастся этого сделать.</para>

      &interaction.rollback.twice;

      <para id="x_e1">Если вы произведете отмену транзакции, вы не сможете снова выполнять roll back до тех пор, пока не произведете другие операции commit или pull.</para>

    </sect2>
  </sect1>
  <sect1>
    <title>Отмена ошибочных изменений</title>

    <para id="x_e2">Если вы изменили файл, но потом решили, что вообще не хотите его изменять, и если вы ещё не зафиксировали изменения, то команда <command role="hg-cmd">hg revert</command> &emdash; то, что вам нужно.  Она смотрит на предыдущую ревизию рабочей директории и восстанавливает содержимое файла к состоянию из этой ревизии. (Это многоречивый способ сказать, что обычно эта команда отменяет ваши изменения.)</para>

    <para id="x_e3">Давайте посмотрим, как работает команда <command role="hg-cmd">hg revert</command>. В этом маленьком примере мы начнем с изменения файла, о котором Mercurial уже знает.</para>

    &interaction.daily.revert.modify;

    <para id="x_e4">Нам не нужно это изменение, поэтому мы вызываем <command role="hg-cmd">hg revert</command> для этого файла.</para>

      &interaction.daily.revert.unmodify;

    <para id="x_e5">Команда <command role="hg-cmd">hg revert</command> дополнительно заботится о безопасности данных, сохраняя наш измененный файл с расширением <filename>.orig</filename>.</para>

    &interaction.daily.revert.status;

    <tip>
      <title>Будьте осторожны с <filename>.orig</filename> файлами</title>

      <para id="x_6b8">Крайне нежелательно, чтобы вы управляли <filename>.orig</filename>-файлами с помощью Mercurial, и даже чтобы вы задумывались о содержании этих файлов. На всякий случай, полезно помнить, что <command role="hg-cmd">hg revert</command> безоговорочно переписывает существующий <filename>.orig</filename>-файл. Например, если у вас уже есть файл с именем <filename>foo.orig</filename> когда вы откатываете <filename>foo</filename>, содержимое <filename>foo.orig</filename> будет перезаписано.</para>
    </tip>

    <para id="x_e6">Ниже приведена сводка случаев, в которых может быть полезна команда <command role="hg-cmd">hg revert</command>. В следующей секции будет детальное описание каждого из них.</para>
    <itemizedlist>
      <listitem><para id="x_e7">Если вы изменяете файл, она восстановит его до немодифицированного состояния.</para>
      </listitem>
      <listitem><para id="x_e8">Если вы используете <command role="hg-cmd">hg add</command>, она отменит <quote>добавленное</quote> состояние файла, но оставит сам файл неизменным.</para>
      </listitem>
      <listitem><para id="x_e9">Если вы удаляете файл не сказав об этом Mercurial-у, она восстановит файл с его предыдущим содержанием.</para>
      </listitem>
      <listitem><para id="x_ea">Если вы удаляете файл командой <command role="hg-cmd">hg remove</command>, она отменит <quote>удаленное</quote> состояние файла, и восстановит его немодифицированное содержимое.</para>
      </listitem></itemizedlist>

    <sect2 id="sec:undo:mgmt">
      <title>Ошибки управления файлами</title>

      <para id="x_eb">Команда <command role="hg-cmd">hg revert</command> полезна не только для только что измененных файлов. Она позволяет отменить результат любой команды управления файлами &emdash; <command role="hg-cmd">hg add</command>, <command role="hg-cmd">hg remove</command> и др.</para>

      <para id="x_ec">Если вы использовали <command role="hg-cmd">hg add</command> для файла, но потом понимаете, что не хотите, чтобы Mercurial отслеживал его, используйте <command role="hg-cmd">hg revert</command> для отмены добавления. Не волнуйтесь: Mercurial не изменит файл ни в коем случае. Mercurial просто снимет пометку добавления файла.</para>

      &interaction.daily.revert.add;

      <para id="x_ed">Аналогично, если Вы применили к файлу  <command role="hg-cmd">hg remove</command>, то можете с помощью <command role="hg-cmd">hg revert</command> восстановить его с предыдущим содержимым.</para>
	
      &interaction.daily.revert.remove;
	
      <para id="x_ed_1">Это также сработает если файл был удалён <quote>в ручную</quote>, без помощи Mercurial (Напомним, что в терминологии Mercurial такие файлы называются <quote>missing</quote>).</para>

      &interaction.daily.revert.missing;

      <para id="x_ee">Если вы откатываете операцию <command role="hg-cmd">hg copy</command>, целевой (скопированный) файл все равно остается в вашей рабочей директории, однако изменения в нем не отслеживаются. Поскольку операция копирования в любом случае не затрагивает исходный файл, Mercurial никак не изменяет исходный файл.</para>

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

  <sect1>
    <title>Работа с зафиксированными изменениями</title>

    <para id="x_f5">Рассмотрим случай, когда вы зафиксировали изменение <emphasis>a</emphasis> и другое изменение <emphasis>b</emphasis> поверх него. Затем вы обнаружили, что изменение <emphasis>a</emphasis> было некорректным.  Mercurial позволяет вам автоматически <quote>вернуть</quote> (back out) изменение целиком, и создаёт блоки, которые позволяют вам отменить часть изменения вручную.</para>

    <para id="x_f6">Перед прочтением этой части руководства, вы должны четко представлять себе следующее: команда <command role="hg-cmd">hg backout</command> отменяет изменения <emphasis>добавляя</emphasis> новые записи к истории, но ни в коем случае не редактируя и не удаляя уже существующую в истории информацию. Эта утилита хорошо подходит для исправления небольших багов, но не для отмены больших изменений, приведших к серьезным проблемам. Чтобы разобраться с такими проблемами, смотрите секцию <xref linkend="sec:undo:aaaiiieee"/>.</para>

    <sect2>
      <title>Отзыв набора измений</title>

      <para id="x_f7">Команда <command role="hg-cmd">hg backout</command> позволяет вам автоматически <quote>отменить</quote> всю ревизию. Т.к.  Меркуриал не позволяет изменять уже существующую историю, а только лишь добавлять в неё новые записи, данная команда <emphasis>не</emphasis> может просто удалить  ревизию, которую вы хотите отменить. Вместо этого она создает новую ревизию, которая <emphasis>отражает</emphasis> состояние репозитория, если бы в него не была добавлена удаляемая ревизия.</para>

      <para id="x_f8">Действия выполняемые командой <command role="hg-cmd">hg backout</command> на первый взгляд могут показаться несколько запутанными, поэтому продемонстрируем их на примере. Для начала создадим репозиторий с несколькими простыми изменениями.</para>

      &interaction.backout.init;

      <para id="x_f9">В качестве единственного параметра команда <command role="hg-cmd">hg backout</command> принимает ID удаляемой ревизии. Обычно <command role="hg-cmd">hg backout</command> перебрасывает вас в текстовый редактор, где можно создать комментарий, объясняющий причину отмены изменений. В этом же примере мы добавили комментарий прямо в командной строке при помощи параметра <option role="hg-opt-backout">-m</option>.</para>

    </sect2>
    <sect2>
      <title>Отзыв последней ревизии (tip)</title>

      <para id="x_fa">Начнем с отзыва последней ревизии.</para>

      &interaction.backout.simple;

      <para id="x_fb">Как видите, в <filename>myfile</filename> второй строки уже нет. Взгляд на вывод команды <command role="hg-cmd">hg log</command> позволяет понять, что сделала <command role="hg-cmd">hg backout</command>.</para>

      &interaction.backout.simple.log;
      
      <para id="x_fb_1">Заметим, что новый набор изменений, который был создан командой <command role="hg-cmd">hg backout</command> является потомком отозванного набора. Это легко увидеть на рисунке <xref linkend="fig:undo:backout"/>, на котором показана история изменений в графическом виде. Как вы можете видеть, история изящная и прямолинейная.</para>

      <figure id="fig:undo:backout">
	<title>Отмена изменения используя команду <command role="hg-cmd">hg backout</command></title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/undo-simple.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

    </sect2>
    <sect2>
      <title>Отзыв ревизии, не являющейся последней</title>

      <para id="x_fd">Если Вы хотите отозвать не последний набор изменений добавляйте к <command role="hg-cmd">hg backout</command> опцию <option role="hg-opt-backout">--merge</option>.</para>

      &interaction.backout.non-tip.clone;

      <para id="x_fe">Это позволяет делать отзыв любой фиксации за одно действие, что обычно просто и быстро.</para>

      &interaction.backout.non-tip.backout;

      <para id="x_ff">Если Вы посмотрите на содержимое <filename>myfile</filename> после завершения отзЫва, то увидите, что присутствует первый и третий набор изменений. А второй отсутствует. (Примечание переводчика: пример несколько некорректен, т.к. получается конфликтное слияние, о чем уже написано в комментариях в оригинальном руководстве.)</para>

      &interaction.backout.non-tip.cat;

      <para id="x_100">На графическом представлении истории (рисунок <xref linkend="fig:undo:backout-non-tip"/> ) видим, что в этой ситуации, Mercurial так же фиксирует только одно изменение (прямоугольники &emdash; это узлы, которые Mercurial коммитит автоматически), но граф ревизий выглядит иначе. Перед тем, как Mercurial начнёт процесс отзыва, он запомнит текущего родителя рабочей директории. Затем он отзывает указанную ревизию и фиксирует этот отзыв. И наконец, он выполняет слияние с предыдущим родителем рабочей директории, но заметьте, что результат слияния <emphasis>не фиксируется</emphasis>. Репозиторий в настоящее время содержит 2 головы, и рабочий каталог в состоянии слияния.</para>

      <figure id="fig:undo:backout-non-tip">
	<title>Автоматический возврат не последнего набора изменений с помощью команды <command role="hg-cmd">hg backout</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">В результате вы оказываетесь <quote>там же, где и были</quote> лишь с небольшим увеличением истории, в которой отражён откат.</para>

      <para id="x_6b9">У вас может возникнуть вопрос, почему Mercurial не фиксирует результат слияния, которое он выполнил. Причина в осторожном поведении Mercurial: очевидно, что слияние имеет значительно большее поле для возможных ошибок, чем просто отмена эффекта последней ревизии, так что ваша работа будет безопаснее, если вы сперва проверите (и протестируете!)  результат слияния, и <emphasis>только потом</emphasis> его зафиксируете.</para>

      <sect3>
	<title>Всегда используйте опцию <option role="hg-opt-backout">--merge</option></title>

	<para id="x_104">Фактически, поскольку опция <option role="hg-opt-backout">--merge</option> делает то что надо, независимо от того, является ли отменяемый набор изменений вершиной, или нет (т.е. не пытается зафиксировать возврат набора изменений, являющегося вершиной, поскольку в этом нет необходимости), вам следует <emphasis>всегда</emphasis> использовать эту опцию команды <command role="hg-cmd">hg backout</command>.</para>

      </sect3>
    </sect2>
    <sect2>
      <title>Получение бОльшего контроля над процессом возврата</title>

      <para id="x_105">До сих пор я рекомендовал вам всегда использовать опцию <option role="hg-opt-backout">--merge</option>, когда вы возвращаете изменение, однако команда <command role="hg-cmd">hg backout</command> позволяет вам выбрать, каким образом произвести фиксацию возврата изменения. Получение полного контроля над на тем, что происходит в процессе возврата &emdash; это то, что вам понадобится достаточно редко, однако полезно понимать, что именно команда <command role="hg-cmd">hg backout</command> делает в автоматическом режиме. Чтобы проиллюстрировать этот процесс, создадим копию репозитория, исключив возвращенные изменения, которые он содержит.</para>

      &interaction.backout.manual.clone;

      <para id="x_106">Как и в предыдущем примере, Мы создадим третью ревизию, затем вернём в изначальное состояние, и посмотри что произошло.</para>

      &interaction.backout.manual.backout;

      <para id="x_107">Наш новый набор изменений опять является потомком набора изменений, который мы возвращаем, а <emphasis>не</emphasis> того, который являлся вершиной. Команда <command role="hg-cmd">hg backout</command> вполне явно сообщает нам об этом.</para>

      &interaction.backout.manual.log;

      <para id="x_108">И снова чтобы увидеть что произошло, проще взглянуть на граф истории ревизий на рисунке <xref linkend="fig:undo:backout-manual"/>. Он явно показывает, что когда мы использовали <command role="hg-cmd">hg backout</command> для возврата изменений, не являющихся вершиной, Меркуриал добавляет новый head в репозиторий (изменение, которое было зафиксировано, обозначено квадратом).</para>

      <figure id="fig:undo:backout-manual">
	<title>Возврат изменений с помощью команды <command role="hg-cmd">hg backout</command></title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/undo-manual.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

      <para id="x_10a">После выполнения команды  <command role="hg-cmd">hg backout</command>, новый <quote>backout</quote> набор изменений становится родителем рабочего каталога.</para>

      &interaction.backout.manual.parents;

      <para id="x_10b">Теперь у нас есть два отдельных набора изменений.</para>

      &interaction.backout.manual.heads;

      <para id="x_10c">Давайте подумаем о том, что мы ожидаем увидеть, в содержимом <filename>myfile</filename> сейчас. Первое изменение, должно присутствовать, потому что мы никогда не возвращали его. Второе изменение должно пропасть, как изменение, которое мы вернули. Поскольку граф истории показывает третье изменение в качестве отдельной головы, мы <emphasis>не</emphasis> ожидаем увидеть третье изменение в <filename>myfile</filename>.</para>

      &interaction.backout.manual.cat;

      <para id="x_10d">Чтобы получить третье изменение обратно в файл, мы просто делаем нормальное слияние двух наших голов.</para>

      &interaction.backout.manual.merge;

      <para id="x_10e">После этого графическая история нашего хранилища показана на <xref linkend="fig:undo:backout-manual-merge"/>.</para>

      <figure id="fig:undo:backout-manual-merge">
	<title>Ручное слияние возвращённых изменений</title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/undo-manual-merge.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

    </sect2>
    <sect2>
      <title>Почему команда <command role="hg-cmd">hg backout</command> работает именно так</title>

      <para id="x_110">Вот краткое описание как работает команда <command role="hg-cmd">hg backout</command>.</para>
      <orderedlist>
	<listitem><para id="x_111">Она гарантирует, что рабочий каталог будет <quote>чистым</quote>, т.е., вывод команды <command role="hg-cmd">hg status</command> будет пустым.</para>
	</listitem>
	<listitem><para id="x_112">Она запоминает текущего родителя рабочего каталога. Назовем эту ревизию оригинальной</para>
	</listitem>
	<listitem><para id="x_113">Она не эквивалентна команде <command role="hg-cmd">hg update</command>, синхронизирующей текущий каталог с ревизией к которой вы хотите вернуться. Назовем эту ревизию откатываемой.</para>
	</listitem>
	<listitem><para id="x_114">Она находит родителя ревизии, которую Вы хотите откатить. Назовем ее ревизия-родитель.</para>
	</listitem>
	<listitem><para id="x_115">Для всех файлов, измененных в откатываемой ревизии, делается эквивалент команды <command role="hg-cmd">hg revert -r parent</command>, для восстановления их до содержимого которое они имели перед этой ревизией.</para>
	</listitem>
	<listitem><para id="x_116">Результат сохраняется как новая ревизия. Эта ревизия имеет родителем откатываемую ревизию.</para>
	</listitem>
	<listitem><para id="x_117">Если Вы указали ключ <option role="hg-opt-backout">--merge</option> в коммандной строке, делается слияние с оригинальной ревизией и результат слияния сохраняется как новая ревизия</para>
	</listitem></orderedlist>

      <para id="x_118">Альтернативный способ реализации <command role="hg-cmd">hg backout</command> команда <command role="hg-cmd">hg export</command> применённую к откатываемому набору изменений как diff-у, а затем использовать опцию <option role="cmd-opt-patch">--reverse</option> для команды <command>patch</command> для ликвидации последствий изменения без возни с рабочей директорией. Это звучит гораздо проще, но работает это не так хорошо.</para>

      <para id="x_119">Причина, по которой <command role="hg-cmd">hg backout</command> делает обновление, фиксацию, слияние, и ещё одну фиксацию используя механизм слияния в том, что это лучший шанс сделать работу хорошо, когда речь идет об сохранении всех изменения <emphasis>между</emphasis> ревизией которую мы откатываем, и текущей ревизией.</para>

      <para id="x_11a">Если вы отказываясь ревизии, которая была 100 ревизий назад в истории вашего проекта, вероятность того, что команда <command>patch</command> сможет применить обратный diff аккуратно не велика, потому что вмешательство последующих ревизий возможно <quote>нарушило контекст</quote>, который использует <command>patch</command>, чтобы определить, может ли она применить патч (если это звучит для вас как бред, смотрите раздел <xref linkend="sec:mq:patch"/> для обсуждения строк команды <command>patch</command>). Кроме того, механизм слияние Mercurial будет работать с файлами и каталогами, который был переименованы, изменениями прав, и изменения в двоичных файлах, ни с одним из этих вариантов <command>patch</command> не может работать.</para>

    </sect2>
  </sect1>
  <sect1 id="sec:undo:aaaiiieee">
    <title>Изменения, которых быть не должно</title>

    <para id="x_11b">Большую часть времени, команда <command role="hg-cmd">hg backout</command> именно то, что вам нужно, если вы хотите устранить последствия изменений. Она оставляет постоянную запись именно того, что вы сделали, как при фиксации оригинального набора изменений, так и после очистки.</para>

    <para id="x_11c">В редких случаях, однако, вы можете обнаружить, что вы зафиксировали изменения, которые в действительности не должны присутствовать в общем репозитории. Например, было бы очень необычно, и обычно считается ошибкой, фиксация объектных файлов приложения, также как его исходных файлов. Объектные файлы не имеют почти никакой ценностью, и они <emphasis>большие</emphasis>, так что они увеличивают размер хранилища и количество времени, необходимое для клонирования или вытягивания изменении.</para>

    <para id="x_11d">Прежде чем обсудить варианты, которые у вас есть, если вы зафиксировали <quote>грязный пакет</quote> изменений (выглядящий так плохо, что вы хотите выкинуть грязный пакет из головой), позвольте мы сначала обсудим некоторые подходы, которые, вероятно, не будут работать.</para>

    <para id="x_11e">Mercurial рассматривает историю как накопление &emdash; каждое изменение создаётся поверх всех изменений, которые ей предшествовали &emdash; в общем вы не можете просто убрать внесённые изменения. Исключением является тот случай, когда вы только что совершили изменения, и не передали или вытянули их в другой репозиторий. Вот тогда можно смело использовать команду <command role="hg-cmd">hg rollback</command>, как я уже подробно описаны в разделе <xref linkend="sec:undo:rollback"/>.</para>

    <para id="x_11f">После того как вы передали плохие изменения в другой репозиторий, вы все равно <emphasis>сможете</emphasis> использовать <command role="hg-cmd">hg rollback</command> в локальной копии изменения исчезают, но это не будет иметь последствий которых вы хотели. Изменения будут присутствовать в удаленном хранилище, поэтому они снова появится в вашем хранилище в следующий раз вы будете забирать из него изменения.</para>

    <para id="x_120">Если возникает такая ситуация, и вы знаете, в какие репозитории распространили свои плохие изменения, можно <emphasis>попробовать</emphasis> избавиться от изменении в <emphasis>каждом</emphasis> из этих репозиториев. Это, конечно, не является удовлетворительным решением: если вы пропустите один из  репозиториев пока вы стираете, изменения находящиеся в <quote>диком</quote> мире, и может распространяться дальше.</para>

    <para id="x_121">Если вы зафиксировали одно или несколько изменений <emphasis>после</emphasis> изменений, которые вы хотели бы удалить, ваши ревизии в будущем будут раздроблены. Mercurial не предоставляет способа <quote>удалить дыру</quote> в истории, оставив нетронутыми ревизии.</para>

    <sect2>
      <title>Откат слияния</title>

      <para id="x_6ba">После слияния зачастую сложно, это не неслыханно для слияния чтоб оно было плохим, но можно ошибочно зафиксировать его. Mercurial предоставляет гарантии против плохих слияний, отказываясь фиксировать неразрешенные файлы, но и человеческая изобретательность безгранична, и беспорядок все еще возможен беспорядок при слиянии и его фиксации.</para>

      <para id="x_6bb">Учитывая плохие слияния, которые были зафиксированы, как правило, лучший способ исправить его &emdash; просто попытаться исправить ущерб вручную. Полная катастрофа, которая не может быть легко исправлена своими руками должен происходить очень редко, но команда <command role="hg-cmd">hg backout</command> может помочь в упрощении очистки. Он предлагает &emdash; опцию <option role="hg-opt-backout">--parent</option>, которая позволяет определить, к какому из родителей возвращаться при  откате слияния.</para>

      <figure id="fig:undo:bad-merge-1">
	<title>Плохое слияние</title>
	<mediaobject>
	  <imageobject><imagedata fileref="figs/bad-merge-1.png"/></imageobject>
	  <textobject><phrase>XXX add text</phrase></textobject>
	</mediaobject>
      </figure>

      <para id="x_6bc">Предположим, мы имеем граф ревизий, как на рисунке <xref linkend="fig:undo:bad-merge-1"/>. Мы бы хотели <emphasis>повторить</emphasis> это слияние ревизий 2 и 3.</para>

      <para id="x_6bd">Один из способов сделать это будет выглядеть следующим образом.</para>

      <orderedlist>
	<listitem>
	  <para id="x_6be">Вызываем <command role="hg-cmd">hg backout --rev=4 --parent=2</command>. Это говорит <command role="hg-cmd">hg backout</command> откатить ревизию 4, которая является плохим слиянием, а также при определяет какая ревизия выбрать родительской 2, одну из родителей слияния. Эффект может быть показан на рисунке <xref linkend="fig:undo:bad-merge-2"/>.</para>
	  <figure id="fig:undo:bad-merge-2">
	    <title>Откат слияния, в пользу одного из родителей</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">Вызываем <command role="hg-cmd">hg backout --rev=4 --parent=3</command>. Это говорит <command role="hg-cmd">hg backout</command> откатить ревизию 4, но на этот раз выбираем родителя 3, другого родителя слияния. В результате показано на рисунке <xref linkend="fig:undo:bad-merge-3"/>, на котором в это время репозиторий содержит три головы.</para>
	  <figure id="fig:undo:bad-merge-3">
	    <title>Поддержка отката слияния в пользу другого родителя</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">Повторяете плохое слияние путем объединения двух отозванных голов, что снижает количество голов в хранилище до двух, как это видно на рисунке <xref linkend="fig:undo:bad-merge-4"/>.</para>
	  <figure id="fig:undo:bad-merge-4">
	    <title>Слияние откатов</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">Слияние с фиксацией, того что было сделано после плохого слияния, как показано на рисунке <xref linkend="fig:undo:bad-merge-5"/>.</para>
	  <figure id="fig:undo:bad-merge-5">
	    <title>Слияние откатов</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>Защитите себя от <quote>беглых</quote> изменении</title>

      <para id="x_123">Если ты совершил некоторые изменения в локальном репозитории, и они были отправлены или вытянуты куда-то, это не всегда катастрофа. Вы можете защитить себя заранее в отношении некоторых классов плохих изменений. Это особенно удобно, если ваша команда обычно вытягивает изменения из центрального хранилища.</para>

      <para id="x_124">При настройке некоторых хуков в репозитории для проверки входящих ревизий (см. <xref linkend="chap:hook"/>), вы можете автоматически предотвращать некоторые виды плохих ревизий вынуждая всех отправлять изменения в центральное хранилище. При такой конфигурации на месте, некоторые виды плохих ревизий естественно, как правило, <quote>отмирают</quote>, поскольку они не могут появится в центральном хранилище. А самое хорошее то, что это происходит без необходимости явного вмешательства.</para>

      <para id="x_125">Например, хук на входящие изменения проверяющий, что набор изменений может быть скомпилирован, может помешать людям нечаянно <quote>Нарушить сборку</quote>.</para>
    </sect2>

    <sect2>
      <title>Что делать с чувствительными изменениями, как избежать</title>

      <para id="x_6c2">Даже тщательно запущенный проект может пострадать от печального события, такого как фиксация и неконтролируемое распространение файла, который содержит важные пароли.</para>

      <para id="x_6c3">Если что-то подобное произойдет с вами, и информация, которая случайно распространяется, действительно чувствительна, ваш первый шаг должен быть для смягчения последствий утечки, не пытаясь контролировать утечку самостоятельно. Если вы еще не 100% уверены, что вы знаете точно, кто мог увидеть изменения, вы должны немедленно сменить пароли, отменить кредитную карту, или найти другой способ, чтобы убедиться, что информация, с которой произошла утечка, уже бесполезна. Иными словами, предполагайте, что изменение распространится далеко и широко, и что ничего вы не можете сделать.</para>

      <para id="x_6c4">Можно надеяться, что нет механизмов, которые можно использовать для выяснения того, кто видел изменения и удалить изменения сразу во всем мире, но есть веские причины, почему это не представляется возможным.</para>

      <para id="x_6c5">Mercurial не предоставляет аудита, кто вытянул изменения из репозитория, потому что, как правило, либо возможность записи такой информации невозможна или тривиально обманывается. В многопользовательской или сетевой среде, вы должны, таким образом, весьма скептически относится к себе, если вы думаете, что вы определили все места, чувствительные ревизии могут распространится. Не забывайте, что люди могут и будут отправлять разветвления по электронной почте, имеют программное обеспечение резервного копирования данных вне офиса, переносят репозиторий на usb-брелках, и найти другие пути совершенно невинные, чтобы посрамить ваши попытки отследить каждую копию проблемных ревизий.</para>

      <para id="x_6c6">Mercurial также не дает способ сделать файл или набор изменений которые навсегда исчезают из истории, потому что нет возможности реализовать в своей копии удаление, кто-то может легко изменить свою копию Mercurial игнорировав такие директивы. Кроме того, даже если Mercurial обеспечит возможности, запретить  вытягивание файла <quote>отмеченного как удалённый</quote> ревизии не будут затронуты ею, равно как и сканерам, сохраняющими образ жесткого диска или других механизмов. В самом деле, не распределенная система контроля версий может сделать чтобы данные надежно исчезли. Предоставляя иллюзию такого контроля, и могут легко дать ложное чувство безопасности, и это хуже, чем не предоставлять его вовсе.</para>
    </sect2>
  </sect1>

  <sect1 id="sec:undo:bisect">
    <title>Поиск источника ошибки</title>

    <para id="x_126">Конечно, возможность откатить изменение, которое внесло ошибку, это хорошо, но сначала нужно узнать, какой именно набор изменений, нужно откатить. Mercurial предоставляет неоценимую команду <command role="hg-cmd">hg bisect</command>, которая поможет вам эффективно автоматизировать этот процесс.</para>

    <para id="x_127">Идея <command role="hg-cmd">hg bisect</command> в том, что ревизии вводили некоторые изменения в поведении, которые можно определить с помощью некоторых простых бинарных испытаний. Вы не знаете, какая часть кода внесла изменения, но вы знаете, как проверить его на наличие ошибок. Команда <command role="hg-cmd">hg bisect</command> использует ваш тест для прямого поиска ревизии, которая содержит код, вызывающий ошибку.</para>

    <para id="x_128">Вот несколько сценариев, которые помогут вам понять, как можно применить эту команду.</para>
    <itemizedlist>
      <listitem><para id="x_129">Самая последняя версия программного обеспечения имеет ошибку, и Вы помните, что ее не было несколько недель назад, но не знаете, когда она появилась. Тут-то, ваш бинарный тест проверяет [ревизии] на наличие этой ошибки.</para>
      </listitem>
      <listitem><para id="x_12a">Вы исправили ошибку в спешке, и теперь пришло время закрыть запись об ошибке в багтрекере вашей команды. Багтрекер данных требует ID ревизии, когда вы закрываете записи, но вы не помните, в какой ревизии Вы исправили ошибку. Снова, ваш бинарный тест проверяет на наличие ошибки.</para>
      </listitem>
      <listitem><para id="x_12b">Ваше программное обеспечение работает правильно, но работает на 15% медленнее, чем в прошлый раз. Вы хотите знать, какие ревизии внесли уменьшение производительности. В этом случае ваш бинарный тест измеряет производительность вашего программного обеспечения, чтобы показать, что <quote>быстрее</quote> или <quote>медленнее</quote>.</para>
      </listitem>
      <listitem><para id="x_12c">Размеры компонент проекта, который Вы ведете внезапно раздулись, и вы подозреваете, что что-то изменилось во время построения проекта.</para>
      </listitem></itemizedlist>

    <para id="x_12d">Из этих примеров должно быть ясно, что команда <command role="hg-cmd">hg bisect</command> полезна не только для нахождения источников ошибок. С ее помощью можно найти любое <quote>непредвиденное свойство</quote> кодов. То, которое не удаётся найти простым текстовым поиском, но можно отловить бинарным тестом.</para>

    <para id="x_12e">Введем немного терминологии, просто чтобы понять, какая часть процесса поиска ложится на Вас и какая на Mercurial. <emphasis>Тест</emphasis> это то, что выбирает ревизию, когда вы запускаете <command role="hg-cmd">hg bisect</command>. <emphasis>Проверка</emphasis> &emdash; это то, что <command role="hg-cmd">hg bisect</command> запускает чтобы сказать, какая ревизия хороша. Наконец, мы будем использовать слово <quote>bisect</quote>, и как существительное (бисектриса) и глагол (делить пополам), во фразе <quote>поиск с использованием команды <command role="hg-cmd">hg bisect</command></quote>.</para>

    <para id="x_12f">Прямолинейный способ автоматизации процесса поиска &emdash;  просто проверять каждый Changeset. Однако масштабы этого ненормальны. Если тестирование одной ревизии занимает десять минут то полный просмотр 10000 ревизий в вашем хранилище,  потребует в среднем 35 <emphasis>дней</emphasis>. Даже если бы вы знали, что ошибка была внесена в одной из последних 500 ревизий и ограничили поиск этим, вы по-прежнему будете искать более чем 40 часов, чтобы найти эту ревизию.</para>

    <para id="x_130"><command role="hg-cmd">hg bisect</command> использует свои знания <quote>формы</quote> истории вашего проекта и чтобы выполнить поиск по времени пропорционально <emphasis>логарифму</emphasis> числа проверяемых ревизий (вид выполняемого поиска называется дихотомический поиск). При таком подходе, поиск по 10000 ревизий займет менее трех часов, даже при десяти минутах на одно испытание (поиск потребует около 14 проверок). Ограничьте поиск последними ста ревизиями, и это займет всего около часа (примерно семь тестов).</para>

    <para id="x_131">Команде известно о <quote>ветвистом</quote> характере истории  проекта в Mercurial, поэтому у него нет проблем, связанных с ветвлениями, слияниями, или несколькими головами в репозитории. Он может обрезать все ветви истории одной проверкой, который, как она работает так эффективно.</para>

    <sect2>
      <title>Использование команды <command role="hg-cmd">hg bisect</command></title>

      <para id="x_132">Вот пример <command role="hg-cmd">hg bisect</command> в действии.</para>

      <note>
	<para id="x_133">В версии 0.9.5 и более ранних, <command role="hg-cmd">hg bisect</command> не является встроенной командой: она распространялясь с Mercurial как расширение. В этом разделе описана встроенная команды, а не старое расширение.</para>
      </note>

      <para id="x_134">Теперь давайте создадим репозитарий, так что мы сможем попробовать команду <command role="hg-cmd">hg bisect</command> отдельно.</para>

      &interaction.bisect.init;

      <para id="x_135">Мы будем моделировать проект, который содержит ошибку простым образом: создать незначительные изменения в цикле, и назначить одно конкретное изменение, которое будет иметь <quote>ошибку</quote>. Этот цикл создает 35 ревизий, каждое добавление одного файла в хранилище. Мы представляем нашу <quote>ошибку</quote> с файлом, который содержит текст <quote>У меня есть губы</quote>.</para>

      &interaction.bisect.commits;

      <para id="x_136">Следующее, что мы хотели бы сделать, это понять, как использовать команду <command role="hg-cmd">hg bisect</command>. Для этого мы можем использовать встроенная справочная механизмом Mercurial.</para>

      &interaction.bisect.help;

      <para id="x_137">Команда <command role="hg-cmd">hg bisect</command> работает по шагам. Каждый шаг происходит следующим образом.</para>
      <orderedlist>
	<listitem><para id="x_138">Вы запускаете Ваш бинарный тест.</para>
	  <itemizedlist>
	    <listitem><para id="x_139">Если тест успешен, Вы говорите об этом запуская команду <command role="hg-cmd">hg bisect --good</command>.</para>
	    </listitem>
	    <listitem><para id="x_13a">Если неуспешен, запускаете команду <command role="hg-cmd">hg bisect --bad</command></para></listitem></itemizedlist>
	</listitem>
	<listitem><para id="x_13b">Mercurial использует вашу информацию, чтобы решить, какая ревизия для тестирования следующая</para>
	</listitem>
	<listitem><para id="x_13c">Он обновляет рабочий каталог до этой ревизии и процесс повторяется сначала</para>
	</listitem></orderedlist>
      <para id="x_13d">Процесс заканчивается, когда <command role="hg-cmd">hg bisect</command> идентифицирует уникальный набор изменений, который знаменует собой точку, где Ваш тест перешол из <quote>успешног</quote> в <quote>неуспешный</quote>.</para>

      <para id="x_13e">Чтобы начать поиск, должны запустить команду <command role="hg-cmd">hg bisect --reset</command>.</para>

      &interaction.bisect.search.init;

      <para id="x_13f">В нашем случае мы используем очень простой бинарный тест: мы проверим, содержит ли какой-то файл в хранилище строку <quote>У меня есть губы</quote>. Если это так, эта ревизия содержит изменения, которые <quote>вызвали ошибку</quote>. По соглашению, ревизия, которая обладает свойством <quote>плохо</quote>, а не ту, которая не является <quote>хорошим</quote>.</para>

      <para id="x_140">Чаще всего, ревизия с которой синхронизирован рабочий каталог (как правило, 'typ' &emdash; последняя голова), уже столкнулись с проблемой внесенной бажной правкой, поэтому мы помечаем его как <quote>плохое</quote>.</para>

      &interaction.bisect.search.bad-init;

      <para id="x_141">Нашей следующей задачей является назначить ревизию, про которую известно, что она <emphasis>не</emphasis> содержит искомую ошибку; Команда <command role="hg-cmd">hg bisect</command> ограничивает свой поиск между первой парой <quote>хорошая &emdash; плохая</quote> ревизиия. В нашем случае, мы знаем, что 10-я ревизия не имела ошибок. (Я расскажу  несколько слов о выборе первой <quote>хорошей</quote> ревизии позднее).</para>

      &interaction.bisect.search.good-init;

      <para id="x_142">Обратите внимание, эта команда что-то выводит [на экран]</para>
      <itemizedlist>
	<listitem><para id="x_143">Он рассказал нам, как много ревизий он должен рассматривать прежде чем он сможет определить, где введена одна ошибка, и как много тестов, потребуется.</para>
	</listitem>
	<listitem><para id="x_144">Он обновлил рабочий каталог до следующей ревизии для тестирования, и рассказал нам, какую ревизию будем тестировать.</para>
	</listitem></itemizedlist>

      <para id="x_145">Теперь запустим наш тест в рабочием каталоге. Мы используем команду <command>grep</command>, чтобы увидеть, находится ли наш <quote>плохой</quote> файл в рабочей директории. Если это так, эта ревизия является плохой, если нет &emdash; хорошей.</para>
	
      &interaction.bisect.search.step1;

      <para id="x_146">Этот тест выглядит идеальным кандидатом для автоматизации, так что давайте превратим его в функцию shell.</para>
      &interaction.bisect.search.mytest;

      <para id="x_147">Теперь мы можем запустить весь тест одной командой <literal>mytest</literal>.</para>

      &interaction.bisect.search.step2;

      <para id="x_148">Теперь мы можем запустить весь шаг тестирования с одной командой, mytest.</para>

      &interaction.bisect.search.rest;

      <para id="x_149">Хотя у нас было 40 ревизий для поиска, <command role="hg-cmd">hg bisect</command> сумел найти <quote>ошибку</quote> с пяти испытаний. Поскольку количество тестов, для <command role="hg-cmd">hg bisect</command> растет логарифмически с числом ревизий для поиска, то преимущество перед <quote>методом грубой силы</quote>  увеличивается с каждой добавленной ревизией.</para>

    </sect2>
    <sect2>
      <title>Очистка после поиска</title>

      <para id="x_14a">Когда вы закончили работать с <command role="hg-cmd">hg bisect</command>, вы можете использовать <command role="hg-cmd">hg bisect --reset</command> чтобы сбросить информацию, которую он использовал для проведения вашего поиска. Команда не использует много места, поэтому не страшно, если вы забыли запустить эту команду. Тем не менее, <command role="hg-cmd">hg bisect</command> не позволит вам начать новый поиск в этом хранилище, пока вы не cделаете <command role="hg-cmd">hg bisect --reset</command>.</para>

      &interaction.bisect.search.reset;

    </sect2>
  </sect1>
  <sect1>
    <title>Советы для эффективного поиска ошибок</title>

    <sect2>
      <title>Давайте согласованный ввод</title>

      <para id="x_14b">Команда <command role="hg-cmd">hg bisect</command> требует, чтобы вы правильно сообщали о результатах каждого теста, который вы выполняете. Если вы скажете, что это испытание не прошло, когда это действительно удалось, иногда <emphasis>можно</emphasis> обнаружить несоответствие. Если удалось определить несоответствия в Ваших отчетах, Mercurial сообщит Вам, что некоторая ревизия и хорошая и плохая. Однако, он не может делать это всегда, чаще он укажет на неправильную ревизию в качестве источника ошибки.</para>

    </sect2>
    <sect2>
      <title>Автоматизируйте как можно больше</title>

      <para id="x_14c">Когда я начал использовать команду <command role="hg-cmd">hg bisect</command>, я пытался несколько раз выполнить свои тесты вручную, в командной строке. С таким подходом я убил по крайней мере, первую половину дня. После нескольких попыток, я обнаружил, что я делал много ошибок, из-за которых мне приходилось перезапускать поиск несколько раз, чтобы наконец, получить правильные результаты.</para>

      <para id="x_14d">Мои первоначальные проблемы с управлением командой <command role="hg-cmd">hg bisect</command> вручную происходили даже с простым поиском по малым репозиториям, а если проблема, которую вы ищете более тонкая, или количество тестов, которые <command role="hg-cmd">hg bisect</command> необходимо выполнить возрастает, вероятность ошибки оператора испортить поиск гораздо выше. Как только я начал автоматизировать мои тесты, я получал лучше результаты.</para>

      <para id="x_14e">Ключ к автоматизированному тестированию является двойным:</para>
      <itemizedlist>
	<listitem><para id="x_14f">всегда проверяйте одни и те же симптомы, и</para>
	</listitem>
	<listitem><para id="x_150">всегда передавайте согласованный ввод для команды <command role="hg-cmd">hg bisect</command></para>
	</listitem></itemizedlist>
      <para id="x_151">В моем учебном примере приведенном выше, команда <command>grep</command> тестирует симптом, и условие <literal>if</literal> принимает результат этой проверки и гарантирует, что мы всегда передаём тот же самое на вход команды <command role="hg-cmd">hg bisect</command>. Функция <literal>mytest</literal> связывается с этими тегами воспроизводимым образом, чтобы каждый тест являлся однородным и последовательным.</para>

    </sect2>
    <sect2>
      <title>Проверка ваших результатов</title>

      <para id="x_152">Потому что вывод поиска <command role="hg-cmd">hg bisect</command> хороша лишь на входных данных которые вы ему передаёте, не принимайте этот отчёт с набором ревизий, как абсолютную истину. Самым простым способом для перекрестной проверки его отчёта, будет запуск вручную тестов на каждой из следующих ревизий:</para>
      <itemizedlist>
	<listitem><para id="x_153">Ревизия, которая помечена первой плохой ревизией. Ваш тест должен сообщать о ней что она по прежнему плохая.</para>
	</listitem>
	<listitem><para id="x_154">Родителей, этой ревизии (каждого из родителей, если это слияние). Ваш тест должен сообщить об этих ревизиях как хороших.</para>
	</listitem>
	<listitem><para id="x_155">Потомка этой ревизии. Ваш тест должен сообщить об этой ревизии как о плохой.</para>
	</listitem></itemizedlist>

    </sect2>
    <sect2>
      <title>Остерегайтесь интерференции ошибок</title>

      <para id="x_156">Вполне возможно, что ваш поиск одной ошибки может быть нарушен присутствием другой. Например, предположим, что в вашей программе ошибка в ревизии 100, и она работала правильно на ревизии 50. Кто-то неизвестный вам вставил различные ошибки в ревизию 60, и исправил их в ревизии 80. Это может исказить ваш результат одним из нескольких способов.</para>

      <para id="x_157">Вполне возможно, что эта совершенно другая ошибка <quote>маскирует</quote> вашу, и есть шанс, что эта ошибка проявит себя перед вашей ошибкой. Если вы не можете избежать этой другой ошибки (например, она не даёт вашему проекту собраться), и поэтому нельзя сказать есть ли ваша ошибка в конкретной ревизии, команда <command role="hg-cmd">hg bisect</command> не может помочь вам непосредственно. Вместо этого, вы можете пометить непроверяемую ревизию, запустив <command role="hg-cmd">hg bisect --skip</command>.</para>

      <para id="x_158">Другая проблема может возникнуть, если тест на наличие ошибка не является достаточно точным. Если вы проверяете условие <quote>моя программа падает</quote>, то и ваша ошибка и сбой связанный с ошибкой, маскирующей вашу, будет выглядеть одинаково, и введёт в заблуждение <command role="hg-cmd">hg bisect</command>.</para>

      <para id="x_159">Еще одна ситуация, в которой полезно использовать <command role="hg-cmd">hg bisect --skip</command>, если вы не можете проверить ревизию, так как ваш проект был в сломан и, следовательно, нетестируем в той ревизии, возможно, что кто-то уже проверил в изменениях, которые приводили к провалу сборки проекта.</para>

    </sect2>
    <sect2>
      <title>Опора вашего ленивого поиска</title>

      <para id="x_15a">Выбрать первые <quote>хорошую</quote> и <quote>плохую</quote> ревизии, которые означают конечные точки поиска, зачастую нелегко, но тем не менее это приводит к небольшой дискуссии. С точки зрения <command role="hg-cmd">hg bisect</command>, <quote>новейшая</quote> ревизия условно обозначается как <quote>плохая</quote>, а самая старшая ревизия как <quote>хорошая</quote>.</para>

      <para id="x_15b">Если вы не помните, когда была подходящая <quote>хорошая</quote> ревизия, о которой вы можете сказать <command role="hg-cmd">hg bisect</command>, вы можете сделать хуже, чем при тестировании ревизий наугад. Просто помните, для ликвидации ошибок, важны моменты когда ошибка появится не может(возможно, потому что программы с ошибкой ещё не было), и те моменты, когда одна проблема маскирует другую (как я говорил выше).</para>

      <para id="x_15c">Даже если вы в конечном итоге <quote>ранняя</quote> ревизия будет за тысячу ревизий или месяцев истории, вы увидите добавление только нескольких тестов <command role="hg-cmd">hg bisect</command>, которые необходимо выполнить, благодаря логарифмическому поведению.</para>

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

<!--
local variables: 
sgml-parent-document: ("00book.xml" "book" "chapter")
end:
-->