##// END OF EJS Templates
cleanup: use revision numbers instead of hashes in test output...
Danny Hooper -
r40603:19e1c262 default
parent child Browse files
Show More
@@ -1,1197 +1,1197 b''
1 1 A script that implements uppercasing of specific lines in a file. This
2 2 approximates the behavior of code formatters well enough for our tests.
3 3
4 4 $ UPPERCASEPY="$TESTTMP/uppercase.py"
5 5 $ cat > $UPPERCASEPY <<EOF
6 6 > import sys
7 7 > from mercurial.utils.procutil import setbinary
8 8 > setbinary(sys.stdin)
9 9 > setbinary(sys.stdout)
10 10 > lines = set()
11 11 > for arg in sys.argv[1:]:
12 12 > if arg == 'all':
13 13 > sys.stdout.write(sys.stdin.read().upper())
14 14 > sys.exit(0)
15 15 > else:
16 16 > first, last = arg.split('-')
17 17 > lines.update(range(int(first), int(last) + 1))
18 18 > for i, line in enumerate(sys.stdin.readlines()):
19 19 > if i + 1 in lines:
20 20 > sys.stdout.write(line.upper())
21 21 > else:
22 22 > sys.stdout.write(line)
23 23 > EOF
24 24 $ TESTLINES="foo\nbar\nbaz\nqux\n"
25 25 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY
26 26 foo
27 27 bar
28 28 baz
29 29 qux
30 30 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY all
31 31 FOO
32 32 BAR
33 33 BAZ
34 34 QUX
35 35 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 1-1
36 36 FOO
37 37 bar
38 38 baz
39 39 qux
40 40 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 1-2
41 41 FOO
42 42 BAR
43 43 baz
44 44 qux
45 45 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 2-3
46 46 foo
47 47 BAR
48 48 BAZ
49 49 qux
50 50 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 2-2 4-4
51 51 foo
52 52 BAR
53 53 baz
54 54 QUX
55 55
56 56 Set up the config with two simple fixers: one that fixes specific line ranges,
57 57 and one that always fixes the whole file. They both "fix" files by converting
58 58 letters to uppercase. They use different file extensions, so each test case can
59 59 choose which behavior to use by naming files.
60 60
61 61 $ cat >> $HGRCPATH <<EOF
62 62 > [extensions]
63 63 > fix =
64 64 > [experimental]
65 65 > evolution.createmarkers=True
66 66 > evolution.allowunstable=True
67 67 > [fix]
68 68 > uppercase-whole-file:command="$PYTHON" $UPPERCASEPY all
69 69 > uppercase-whole-file:pattern=set:**.whole
70 70 > uppercase-changed-lines:command="$PYTHON" $UPPERCASEPY
71 71 > uppercase-changed-lines:linerange={first}-{last}
72 72 > uppercase-changed-lines:pattern=set:**.changed
73 73 > EOF
74 74
75 75 Help text for fix.
76 76
77 77 $ hg help fix
78 78 hg fix [OPTION]... [FILE]...
79 79
80 80 rewrite file content in changesets or working directory
81 81
82 82 Runs any configured tools to fix the content of files. Only affects files
83 83 with changes, unless file arguments are provided. Only affects changed
84 84 lines of files, unless the --whole flag is used. Some tools may always
85 85 affect the whole file regardless of --whole.
86 86
87 87 If revisions are specified with --rev, those revisions will be checked,
88 88 and they may be replaced with new revisions that have fixed file content.
89 89 It is desirable to specify all descendants of each specified revision, so
90 90 that the fixes propagate to the descendants. If all descendants are fixed
91 91 at the same time, no merging, rebasing, or evolution will be required.
92 92
93 93 If --working-dir is used, files with uncommitted changes in the working
94 94 copy will be fixed. If the checked-out revision is also fixed, the working
95 95 directory will update to the replacement revision.
96 96
97 97 When determining what lines of each file to fix at each revision, the
98 98 whole set of revisions being fixed is considered, so that fixes to earlier
99 99 revisions are not forgotten in later ones. The --base flag can be used to
100 100 override this default behavior, though it is not usually desirable to do
101 101 so.
102 102
103 103 (use 'hg help -e fix' to show help for the fix extension)
104 104
105 105 options ([+] can be repeated):
106 106
107 107 --all fix all non-public non-obsolete revisions
108 108 --base REV [+] revisions to diff against (overrides automatic selection,
109 109 and applies to every revision being fixed)
110 110 -r --rev REV [+] revisions to fix
111 111 -w --working-dir fix the working directory
112 112 --whole always fix every line of a file
113 113
114 114 (some details hidden, use --verbose to show complete help)
115 115
116 116 $ hg help -e fix
117 117 fix extension - rewrite file content in changesets or working copy
118 118 (EXPERIMENTAL)
119 119
120 120 Provides a command that runs configured tools on the contents of modified
121 121 files, writing back any fixes to the working copy or replacing changesets.
122 122
123 123 Here is an example configuration that causes 'hg fix' to apply automatic
124 124 formatting fixes to modified lines in C++ code:
125 125
126 126 [fix]
127 127 clang-format:command=clang-format --assume-filename={rootpath}
128 128 clang-format:linerange=--lines={first}:{last}
129 129 clang-format:pattern=set:**.cpp or **.hpp
130 130
131 131 The :command suboption forms the first part of the shell command that will be
132 132 used to fix a file. The content of the file is passed on standard input, and
133 133 the fixed file content is expected on standard output. Any output on standard
134 134 error will be displayed as a warning. If the exit status is not zero, the file
135 135 will not be affected. A placeholder warning is displayed if there is a non-
136 136 zero exit status but no standard error output. Some values may be substituted
137 137 into the command:
138 138
139 139 {rootpath} The path of the file being fixed, relative to the repo root
140 140 {basename} The name of the file being fixed, without the directory path
141 141
142 142 If the :linerange suboption is set, the tool will only be run if there are
143 143 changed lines in a file. The value of this suboption is appended to the shell
144 144 command once for every range of changed lines in the file. Some values may be
145 145 substituted into the command:
146 146
147 147 {first} The 1-based line number of the first line in the modified range
148 148 {last} The 1-based line number of the last line in the modified range
149 149
150 150 The :pattern suboption determines which files will be passed through each
151 151 configured tool. See 'hg help patterns' for possible values. If there are file
152 152 arguments to 'hg fix', the intersection of these patterns is used.
153 153
154 154 There is also a configurable limit for the maximum size of file that will be
155 155 processed by 'hg fix':
156 156
157 157 [fix]
158 158 maxfilesize = 2MB
159 159
160 160 Normally, execution of configured tools will continue after a failure
161 161 (indicated by a non-zero exit status). It can also be configured to abort
162 162 after the first such failure, so that no files will be affected if any tool
163 163 fails. This abort will also cause 'hg fix' to exit with a non-zero status:
164 164
165 165 [fix]
166 166 failure = abort
167 167
168 168 When multiple tools are configured to affect a file, they execute in an order
169 169 defined by the :priority suboption. The priority suboption has a default value
170 170 of zero for each tool. Tools are executed in order of descending priority. The
171 171 execution order of tools with equal priority is unspecified. For example, you
172 172 could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers
173 173 in a text file by ensuring that 'sort' runs before 'head':
174 174
175 175 [fix]
176 176 sort:command = sort --numeric-sort
177 177 head:command = head --lines=10
178 178 sort:pattern = numbers.txt
179 179 head:pattern = numbers.txt
180 180 sort:priority = 2
181 181 head:priority = 1
182 182
183 183 To account for changes made by each tool, the line numbers used for
184 184 incremental formatting are recomputed before executing the next tool. So, each
185 185 tool may see different values for the arguments added by the :linerange
186 186 suboption.
187 187
188 188 list of commands:
189 189
190 190 fix rewrite file content in changesets or working directory
191 191
192 192 (use 'hg help -v -e fix' to show built-in aliases and global options)
193 193
194 194 There is no default behavior in the absence of --rev and --working-dir.
195 195
196 196 $ hg init badusage
197 197 $ cd badusage
198 198
199 199 $ hg fix
200 200 abort: no changesets specified
201 201 (use --rev or --working-dir)
202 202 [255]
203 203 $ hg fix --whole
204 204 abort: no changesets specified
205 205 (use --rev or --working-dir)
206 206 [255]
207 207 $ hg fix --base 0
208 208 abort: no changesets specified
209 209 (use --rev or --working-dir)
210 210 [255]
211 211
212 212 Fixing a public revision isn't allowed. It should abort early enough that
213 213 nothing happens, even to the working directory.
214 214
215 215 $ printf "hello\n" > hello.whole
216 216 $ hg commit -Aqm "hello"
217 217 $ hg phase -r 0 --public
218 218 $ hg fix -r 0
219 219 abort: can't fix immutable changeset 0:6470986d2e7b
220 220 [255]
221 221 $ hg fix -r 0 --working-dir
222 222 abort: can't fix immutable changeset 0:6470986d2e7b
223 223 [255]
224 224 $ hg cat -r tip hello.whole
225 225 hello
226 226 $ cat hello.whole
227 227 hello
228 228
229 229 $ cd ..
230 230
231 231 Fixing a clean working directory should do nothing. Even the --whole flag
232 232 shouldn't cause any clean files to be fixed. Specifying a clean file explicitly
233 233 should only fix it if the fixer always fixes the whole file. The combination of
234 234 an explicit filename and --whole should format the entire file regardless.
235 235
236 236 $ hg init fixcleanwdir
237 237 $ cd fixcleanwdir
238 238
239 239 $ printf "hello\n" > hello.changed
240 240 $ printf "world\n" > hello.whole
241 241 $ hg commit -Aqm "foo"
242 242 $ hg fix --working-dir
243 243 $ hg diff
244 244 $ hg fix --working-dir --whole
245 245 $ hg diff
246 246 $ hg fix --working-dir *
247 247 $ cat *
248 248 hello
249 249 WORLD
250 250 $ hg revert --all --no-backup
251 251 reverting hello.whole
252 252 $ hg fix --working-dir * --whole
253 253 $ cat *
254 254 HELLO
255 255 WORLD
256 256
257 257 The same ideas apply to fixing a revision, so we create a revision that doesn't
258 258 modify either of the files in question and try fixing it. This also tests that
259 259 we ignore a file that doesn't match any configured fixer.
260 260
261 261 $ hg revert --all --no-backup
262 262 reverting hello.changed
263 263 reverting hello.whole
264 264 $ printf "unimportant\n" > some.file
265 265 $ hg commit -Aqm "some other file"
266 266
267 267 $ hg fix -r .
268 268 $ hg cat -r tip *
269 269 hello
270 270 world
271 271 unimportant
272 272 $ hg fix -r . --whole
273 273 $ hg cat -r tip *
274 274 hello
275 275 world
276 276 unimportant
277 277 $ hg fix -r . *
278 278 $ hg cat -r tip *
279 279 hello
280 280 WORLD
281 281 unimportant
282 282 $ hg fix -r . * --whole --config experimental.evolution.allowdivergence=true
283 283 2 new content-divergent changesets
284 284 $ hg cat -r tip *
285 285 HELLO
286 286 WORLD
287 287 unimportant
288 288
289 289 $ cd ..
290 290
291 291 Fixing the working directory should still work if there are no revisions.
292 292
293 293 $ hg init norevisions
294 294 $ cd norevisions
295 295
296 296 $ printf "something\n" > something.whole
297 297 $ hg add
298 298 adding something.whole
299 299 $ hg fix --working-dir
300 300 $ cat something.whole
301 301 SOMETHING
302 302
303 303 $ cd ..
304 304
305 305 Test the effect of fixing the working directory for each possible status, with
306 306 and without providing explicit file arguments.
307 307
308 308 $ hg init implicitlyfixstatus
309 309 $ cd implicitlyfixstatus
310 310
311 311 $ printf "modified\n" > modified.whole
312 312 $ printf "removed\n" > removed.whole
313 313 $ printf "deleted\n" > deleted.whole
314 314 $ printf "clean\n" > clean.whole
315 315 $ printf "ignored.whole" > .hgignore
316 316 $ hg commit -Aqm "stuff"
317 317
318 318 $ printf "modified!!!\n" > modified.whole
319 319 $ printf "unknown\n" > unknown.whole
320 320 $ printf "ignored\n" > ignored.whole
321 321 $ printf "added\n" > added.whole
322 322 $ hg add added.whole
323 323 $ hg remove removed.whole
324 324 $ rm deleted.whole
325 325
326 326 $ hg status --all
327 327 M modified.whole
328 328 A added.whole
329 329 R removed.whole
330 330 ! deleted.whole
331 331 ? unknown.whole
332 332 I ignored.whole
333 333 C .hgignore
334 334 C clean.whole
335 335
336 336 $ hg fix --working-dir
337 337
338 338 $ hg status --all
339 339 M modified.whole
340 340 A added.whole
341 341 R removed.whole
342 342 ! deleted.whole
343 343 ? unknown.whole
344 344 I ignored.whole
345 345 C .hgignore
346 346 C clean.whole
347 347
348 348 $ cat *.whole
349 349 ADDED
350 350 clean
351 351 ignored
352 352 MODIFIED!!!
353 353 unknown
354 354
355 355 $ printf "modified!!!\n" > modified.whole
356 356 $ printf "added\n" > added.whole
357 357 $ hg fix --working-dir *.whole
358 358
359 359 $ hg status --all
360 360 M clean.whole
361 361 M modified.whole
362 362 A added.whole
363 363 R removed.whole
364 364 ! deleted.whole
365 365 ? unknown.whole
366 366 I ignored.whole
367 367 C .hgignore
368 368
369 369 It would be better if this also fixed the unknown file.
370 370 $ cat *.whole
371 371 ADDED
372 372 CLEAN
373 373 ignored
374 374 MODIFIED!!!
375 375 unknown
376 376
377 377 $ cd ..
378 378
379 379 Test that incremental fixing works on files with additions, deletions, and
380 380 changes in multiple line ranges. Note that deletions do not generally cause
381 381 neighboring lines to be fixed, so we don't return a line range for purely
382 382 deleted sections. In the future we should support a :deletion config that
383 383 allows fixers to know where deletions are located.
384 384
385 385 $ hg init incrementalfixedlines
386 386 $ cd incrementalfixedlines
387 387
388 388 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.txt
389 389 $ hg commit -Aqm "foo"
390 390 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.txt
391 391
392 392 $ hg --config "fix.fail:command=echo" \
393 393 > --config "fix.fail:linerange={first}:{last}" \
394 394 > --config "fix.fail:pattern=foo.txt" \
395 395 > fix --working-dir
396 396 $ cat foo.txt
397 397 1:1 4:6 8:8
398 398
399 399 $ cd ..
400 400
401 401 Test that --whole fixes all lines regardless of the diffs present.
402 402
403 403 $ hg init wholeignoresdiffs
404 404 $ cd wholeignoresdiffs
405 405
406 406 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.changed
407 407 $ hg commit -Aqm "foo"
408 408 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.changed
409 409 $ hg fix --working-dir --whole
410 410 $ cat foo.changed
411 411 ZZ
412 412 A
413 413 C
414 414 DD
415 415 EE
416 416 FF
417 417 F
418 418 GG
419 419
420 420 $ cd ..
421 421
422 422 We should do nothing with symlinks, and their targets should be unaffected. Any
423 423 other behavior would be more complicated to implement and harder to document.
424 424
425 425 #if symlink
426 426 $ hg init dontmesswithsymlinks
427 427 $ cd dontmesswithsymlinks
428 428
429 429 $ printf "hello\n" > hello.whole
430 430 $ ln -s hello.whole hellolink
431 431 $ hg add
432 432 adding hello.whole
433 433 adding hellolink
434 434 $ hg fix --working-dir hellolink
435 435 $ hg status
436 436 A hello.whole
437 437 A hellolink
438 438
439 439 $ cd ..
440 440 #endif
441 441
442 442 We should allow fixers to run on binary files, even though this doesn't sound
443 443 like a common use case. There's not much benefit to disallowing it, and users
444 444 can add "and not binary()" to their filesets if needed. The Mercurial
445 445 philosophy is generally to not handle binary files specially anyway.
446 446
447 447 $ hg init cantouchbinaryfiles
448 448 $ cd cantouchbinaryfiles
449 449
450 450 $ printf "hello\0\n" > hello.whole
451 451 $ hg add
452 452 adding hello.whole
453 453 $ hg fix --working-dir 'set:binary()'
454 454 $ cat hello.whole
455 455 HELLO\x00 (esc)
456 456
457 457 $ cd ..
458 458
459 459 We have a config for the maximum size of file we will attempt to fix. This can
460 460 be helpful to avoid running unsuspecting fixer tools on huge inputs, which
461 461 could happen by accident without a well considered configuration. A more
462 462 precise configuration could use the size() fileset function if one global limit
463 463 is undesired.
464 464
465 465 $ hg init maxfilesize
466 466 $ cd maxfilesize
467 467
468 468 $ printf "this file is huge\n" > hello.whole
469 469 $ hg add
470 470 adding hello.whole
471 471 $ hg --config fix.maxfilesize=10 fix --working-dir
472 472 ignoring file larger than 10 bytes: hello.whole
473 473 $ cat hello.whole
474 474 this file is huge
475 475
476 476 $ cd ..
477 477
478 478 If we specify a file to fix, other files should be left alone, even if they
479 479 have changes.
480 480
481 481 $ hg init fixonlywhatitellyouto
482 482 $ cd fixonlywhatitellyouto
483 483
484 484 $ printf "fix me!\n" > fixme.whole
485 485 $ printf "not me.\n" > notme.whole
486 486 $ hg add
487 487 adding fixme.whole
488 488 adding notme.whole
489 489 $ hg fix --working-dir fixme.whole
490 490 $ cat *.whole
491 491 FIX ME!
492 492 not me.
493 493
494 494 $ cd ..
495 495
496 496 Specifying a directory name should fix all its files and subdirectories.
497 497
498 498 $ hg init fixdirectory
499 499 $ cd fixdirectory
500 500
501 501 $ mkdir -p dir1/dir2
502 502 $ printf "foo\n" > foo.whole
503 503 $ printf "bar\n" > dir1/bar.whole
504 504 $ printf "baz\n" > dir1/dir2/baz.whole
505 505 $ hg add
506 506 adding dir1/bar.whole
507 507 adding dir1/dir2/baz.whole
508 508 adding foo.whole
509 509 $ hg fix --working-dir dir1
510 510 $ cat foo.whole dir1/bar.whole dir1/dir2/baz.whole
511 511 foo
512 512 BAR
513 513 BAZ
514 514
515 515 $ cd ..
516 516
517 517 Fixing a file in the working directory that needs no fixes should not actually
518 518 write back to the file, so for example the mtime shouldn't change.
519 519
520 520 $ hg init donttouchunfixedfiles
521 521 $ cd donttouchunfixedfiles
522 522
523 523 $ printf "NO FIX NEEDED\n" > foo.whole
524 524 $ hg add
525 525 adding foo.whole
526 526 $ cp -p foo.whole foo.whole.orig
527 527 $ cp -p foo.whole.orig foo.whole
528 528 $ sleep 2 # mtime has a resolution of one or two seconds.
529 529 $ hg fix --working-dir
530 530 $ f foo.whole.orig --newer foo.whole
531 531 foo.whole.orig: newer than foo.whole
532 532
533 533 $ cd ..
534 534
535 535 When a fixer prints to stderr, we don't assume that it has failed. We show the
536 536 error messages to the user, and we still let the fixer affect the file it was
537 537 fixing if its exit code is zero. Some code formatters might emit error messages
538 538 on stderr and nothing on stdout, which would cause us the clear the file,
539 539 except that they also exit with a non-zero code. We show the user which fixer
540 540 emitted the stderr, and which revision, but we assume that the fixer will print
541 541 the filename if it is relevant (since the issue may be non-specific). There is
542 542 also a config to abort (without affecting any files whatsoever) if we see any
543 543 tool with a non-zero exit status.
544 544
545 545 $ hg init showstderr
546 546 $ cd showstderr
547 547
548 548 $ printf "hello\n" > hello.txt
549 549 $ hg add
550 550 adding hello.txt
551 551 $ cat > $TESTTMP/work.sh <<'EOF'
552 552 > printf 'HELLO\n'
553 553 > printf "$@: some\nerror that didn't stop the tool" >&2
554 554 > exit 0 # success despite the stderr output
555 555 > EOF
556 556 $ hg --config "fix.work:command=sh $TESTTMP/work.sh {rootpath}" \
557 557 > --config "fix.work:pattern=hello.txt" \
558 558 > fix --working-dir
559 559 [wdir] work: hello.txt: some
560 560 [wdir] work: error that didn't stop the tool
561 561 $ cat hello.txt
562 562 HELLO
563 563
564 564 $ printf "goodbye\n" > hello.txt
565 565 $ printf "foo\n" > foo.whole
566 566 $ hg add
567 567 adding foo.whole
568 568 $ cat > $TESTTMP/fail.sh <<'EOF'
569 569 > printf 'GOODBYE\n'
570 570 > printf "$@: some\nerror that did stop the tool\n" >&2
571 571 > exit 42 # success despite the stdout output
572 572 > EOF
573 573 $ hg --config "fix.fail:command=sh $TESTTMP/fail.sh {rootpath}" \
574 574 > --config "fix.fail:pattern=hello.txt" \
575 575 > --config "fix.failure=abort" \
576 576 > fix --working-dir
577 577 [wdir] fail: hello.txt: some
578 578 [wdir] fail: error that did stop the tool
579 579 abort: no fixes will be applied
580 580 (use --config fix.failure=continue to apply any successful fixes anyway)
581 581 [255]
582 582 $ cat hello.txt
583 583 goodbye
584 584 $ cat foo.whole
585 585 foo
586 586
587 587 $ hg --config "fix.fail:command=sh $TESTTMP/fail.sh {rootpath}" \
588 588 > --config "fix.fail:pattern=hello.txt" \
589 589 > fix --working-dir
590 590 [wdir] fail: hello.txt: some
591 591 [wdir] fail: error that did stop the tool
592 592 $ cat hello.txt
593 593 goodbye
594 594 $ cat foo.whole
595 595 FOO
596 596
597 597 $ hg --config "fix.fail:command=exit 42" \
598 598 > --config "fix.fail:pattern=hello.txt" \
599 599 > fix --working-dir
600 600 [wdir] fail: exited with status 42
601 601
602 602 $ cd ..
603 603
604 604 Fixing the working directory and its parent revision at the same time should
605 605 check out the replacement revision for the parent. This prevents any new
606 606 uncommitted changes from appearing. We test this for a clean working directory
607 607 and a dirty one. In both cases, all lines/files changed since the grandparent
608 608 will be fixed. The grandparent is the "baserev" for both the parent and the
609 609 working copy.
610 610
611 611 $ hg init fixdotandcleanwdir
612 612 $ cd fixdotandcleanwdir
613 613
614 614 $ printf "hello\n" > hello.whole
615 615 $ printf "world\n" > world.whole
616 616 $ hg commit -Aqm "the parent commit"
617 617
618 618 $ hg parents --template '{rev} {desc}\n'
619 619 0 the parent commit
620 620 $ hg fix --working-dir -r .
621 621 $ hg parents --template '{rev} {desc}\n'
622 622 1 the parent commit
623 623 $ hg cat -r . *.whole
624 624 HELLO
625 625 WORLD
626 626 $ cat *.whole
627 627 HELLO
628 628 WORLD
629 629 $ hg status
630 630
631 631 $ cd ..
632 632
633 633 Same test with a dirty working copy.
634 634
635 635 $ hg init fixdotanddirtywdir
636 636 $ cd fixdotanddirtywdir
637 637
638 638 $ printf "hello\n" > hello.whole
639 639 $ printf "world\n" > world.whole
640 640 $ hg commit -Aqm "the parent commit"
641 641
642 642 $ printf "hello,\n" > hello.whole
643 643 $ printf "world!\n" > world.whole
644 644
645 645 $ hg parents --template '{rev} {desc}\n'
646 646 0 the parent commit
647 647 $ hg fix --working-dir -r .
648 648 $ hg parents --template '{rev} {desc}\n'
649 649 1 the parent commit
650 650 $ hg cat -r . *.whole
651 651 HELLO
652 652 WORLD
653 653 $ cat *.whole
654 654 HELLO,
655 655 WORLD!
656 656 $ hg status
657 657 M hello.whole
658 658 M world.whole
659 659
660 660 $ cd ..
661 661
662 662 When we have a chain of commits that change mutually exclusive lines of code,
663 663 we should be able to do incremental fixing that causes each commit in the chain
664 664 to include fixes made to the previous commits. This prevents children from
665 665 backing out the fixes made in their parents. A dirty working directory is
666 666 conceptually similar to another commit in the chain.
667 667
668 668 $ hg init incrementallyfixchain
669 669 $ cd incrementallyfixchain
670 670
671 671 $ cat > file.changed <<EOF
672 672 > first
673 673 > second
674 674 > third
675 675 > fourth
676 676 > fifth
677 677 > EOF
678 678 $ hg commit -Aqm "the common ancestor (the baserev)"
679 679 $ cat > file.changed <<EOF
680 680 > first (changed)
681 681 > second
682 682 > third
683 683 > fourth
684 684 > fifth
685 685 > EOF
686 686 $ hg commit -Aqm "the first commit to fix"
687 687 $ cat > file.changed <<EOF
688 688 > first (changed)
689 689 > second
690 690 > third (changed)
691 691 > fourth
692 692 > fifth
693 693 > EOF
694 694 $ hg commit -Aqm "the second commit to fix"
695 695 $ cat > file.changed <<EOF
696 696 > first (changed)
697 697 > second
698 698 > third (changed)
699 699 > fourth
700 700 > fifth (changed)
701 701 > EOF
702 702
703 703 $ hg fix -r . -r '.^' --working-dir
704 704
705 705 $ hg parents --template '{rev}\n'
706 706 4
707 707 $ hg cat -r '.^^' file.changed
708 708 first
709 709 second
710 710 third
711 711 fourth
712 712 fifth
713 713 $ hg cat -r '.^' file.changed
714 714 FIRST (CHANGED)
715 715 second
716 716 third
717 717 fourth
718 718 fifth
719 719 $ hg cat -r . file.changed
720 720 FIRST (CHANGED)
721 721 second
722 722 THIRD (CHANGED)
723 723 fourth
724 724 fifth
725 725 $ cat file.changed
726 726 FIRST (CHANGED)
727 727 second
728 728 THIRD (CHANGED)
729 729 fourth
730 730 FIFTH (CHANGED)
731 731
732 732 $ cd ..
733 733
734 734 If we incrementally fix a merge commit, we should fix any lines that changed
735 735 versus either parent. You could imagine only fixing the intersection or some
736 736 other subset, but this is necessary if either parent is being fixed. It
737 737 prevents us from forgetting fixes made in either parent.
738 738
739 739 $ hg init incrementallyfixmergecommit
740 740 $ cd incrementallyfixmergecommit
741 741
742 742 $ printf "a\nb\nc\n" > file.changed
743 743 $ hg commit -Aqm "ancestor"
744 744
745 745 $ printf "aa\nb\nc\n" > file.changed
746 746 $ hg commit -m "change a"
747 747
748 748 $ hg checkout '.^'
749 749 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
750 750 $ printf "a\nb\ncc\n" > file.changed
751 751 $ hg commit -m "change c"
752 752 created new head
753 753
754 754 $ hg merge
755 755 merging file.changed
756 756 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
757 757 (branch merge, don't forget to commit)
758 758 $ hg commit -m "merge"
759 759 $ hg cat -r . file.changed
760 760 aa
761 761 b
762 762 cc
763 763
764 764 $ hg fix -r . --working-dir
765 765 $ hg cat -r . file.changed
766 766 AA
767 767 b
768 768 CC
769 769
770 770 $ cd ..
771 771
772 772 Abort fixing revisions if there is an unfinished operation. We don't want to
773 773 make things worse by editing files or stripping/obsoleting things. Also abort
774 774 fixing the working directory if there are unresolved merge conflicts.
775 775
776 776 $ hg init abortunresolved
777 777 $ cd abortunresolved
778 778
779 779 $ echo "foo1" > foo.whole
780 780 $ hg commit -Aqm "foo 1"
781 781
782 782 $ hg update null
783 783 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
784 784 $ echo "foo2" > foo.whole
785 785 $ hg commit -Aqm "foo 2"
786 786
787 787 $ hg --config extensions.rebase= rebase -r 1 -d 0
788 788 rebasing 1:c3b6dc0e177a "foo 2" (tip)
789 789 merging foo.whole
790 790 warning: conflicts while merging foo.whole! (edit, then use 'hg resolve --mark')
791 791 unresolved conflicts (see hg resolve, then hg rebase --continue)
792 792 [1]
793 793
794 794 $ hg --config extensions.rebase= fix --working-dir
795 795 abort: unresolved conflicts
796 796 (use 'hg resolve')
797 797 [255]
798 798
799 799 $ hg --config extensions.rebase= fix -r .
800 800 abort: rebase in progress
801 801 (use 'hg rebase --continue' or 'hg rebase --abort')
802 802 [255]
803 803
804 804 When fixing a file that was renamed, we should diff against the source of the
805 805 rename for incremental fixing and we should correctly reproduce the rename in
806 806 the replacement revision.
807 807
808 808 $ hg init fixrenamecommit
809 809 $ cd fixrenamecommit
810 810
811 811 $ printf "a\nb\nc\n" > source.changed
812 812 $ hg commit -Aqm "source revision"
813 813 $ hg move source.changed dest.changed
814 814 $ printf "a\nb\ncc\n" > dest.changed
815 815 $ hg commit -m "dest revision"
816 816
817 817 $ hg fix -r .
818 818 $ hg log -r tip --copies --template "{file_copies}\n"
819 819 dest.changed (source.changed)
820 820 $ hg cat -r tip dest.changed
821 821 a
822 822 b
823 823 CC
824 824
825 825 $ cd ..
826 826
827 827 When fixing revisions that remove files we must ensure that the replacement
828 828 actually removes the file, whereas it could accidentally leave it unchanged or
829 829 write an empty string to it.
830 830
831 831 $ hg init fixremovedfile
832 832 $ cd fixremovedfile
833 833
834 834 $ printf "foo\n" > foo.whole
835 835 $ printf "bar\n" > bar.whole
836 836 $ hg commit -Aqm "add files"
837 837 $ hg remove bar.whole
838 838 $ hg commit -m "remove file"
839 839 $ hg status --change .
840 840 R bar.whole
841 841 $ hg fix -r . foo.whole
842 842 $ hg status --change tip
843 843 M foo.whole
844 844 R bar.whole
845 845
846 846 $ cd ..
847 847
848 848 If fixing a revision finds no fixes to make, no replacement revision should be
849 849 created.
850 850
851 851 $ hg init nofixesneeded
852 852 $ cd nofixesneeded
853 853
854 854 $ printf "FOO\n" > foo.whole
855 855 $ hg commit -Aqm "add file"
856 856 $ hg log --template '{rev}\n'
857 857 0
858 858 $ hg fix -r .
859 859 $ hg log --template '{rev}\n'
860 860 0
861 861
862 862 $ cd ..
863 863
864 864 If fixing a commit reverts all the changes in the commit, we replace it with a
865 865 commit that changes no files.
866 866
867 867 $ hg init nochangesleft
868 868 $ cd nochangesleft
869 869
870 870 $ printf "FOO\n" > foo.whole
871 871 $ hg commit -Aqm "add file"
872 872 $ printf "foo\n" > foo.whole
873 873 $ hg commit -m "edit file"
874 874 $ hg status --change .
875 875 M foo.whole
876 876 $ hg fix -r .
877 877 $ hg status --change tip
878 878
879 879 $ cd ..
880 880
881 881 If we fix a parent and child revision together, the child revision must be
882 882 replaced if the parent is replaced, even if the diffs of the child needed no
883 883 fixes. However, we're free to not replace revisions that need no fixes and have
884 884 no ancestors that are replaced.
885 885
886 886 $ hg init mustreplacechild
887 887 $ cd mustreplacechild
888 888
889 889 $ printf "FOO\n" > foo.whole
890 890 $ hg commit -Aqm "add foo"
891 891 $ printf "foo\n" > foo.whole
892 892 $ hg commit -m "edit foo"
893 893 $ printf "BAR\n" > bar.whole
894 894 $ hg commit -Aqm "add bar"
895 895
896 $ hg log --graph --template '{node|shortest} {files}'
897 @ bc05 bar.whole
896 $ hg log --graph --template '{rev} {files}'
897 @ 2 bar.whole
898 898 |
899 o 4fd2 foo.whole
899 o 1 foo.whole
900 900 |
901 o f9ac foo.whole
901 o 0 foo.whole
902 902
903 903 $ hg fix -r 0:2
904 $ hg log --graph --template '{node|shortest} {files}'
905 o b4e2 bar.whole
904 $ hg log --graph --template '{rev} {files}'
905 o 4 bar.whole
906 906 |
907 o 59f4
907 o 3
908 908 |
909 | @ bc05 bar.whole
909 | @ 2 bar.whole
910 910 | |
911 | x 4fd2 foo.whole
911 | x 1 foo.whole
912 912 |/
913 o f9ac foo.whole
913 o 0 foo.whole
914 914
915 915
916 916 $ cd ..
917 917
918 918 It's also possible that the child needs absolutely no changes, but we still
919 919 need to replace it to update its parent. If we skipped replacing the child
920 920 because it had no file content changes, it would become an orphan for no good
921 921 reason.
922 922
923 923 $ hg init mustreplacechildevenifnop
924 924 $ cd mustreplacechildevenifnop
925 925
926 926 $ printf "Foo\n" > foo.whole
927 927 $ hg commit -Aqm "add a bad foo"
928 928 $ printf "FOO\n" > foo.whole
929 929 $ hg commit -m "add a good foo"
930 930 $ hg fix -r . -r '.^'
931 931 $ hg log --graph --template '{rev} {desc}'
932 932 o 3 add a good foo
933 933 |
934 934 o 2 add a bad foo
935 935
936 936 @ 1 add a good foo
937 937 |
938 938 x 0 add a bad foo
939 939
940 940
941 941 $ cd ..
942 942
943 943 Similar to the case above, the child revision may become empty as a result of
944 944 fixing its parent. We should still create an empty replacement child.
945 945 TODO: determine how this should interact with ui.allowemptycommit given that
946 946 the empty replacement could have children.
947 947
948 948 $ hg init mustreplacechildevenifempty
949 949 $ cd mustreplacechildevenifempty
950 950
951 951 $ printf "foo\n" > foo.whole
952 952 $ hg commit -Aqm "add foo"
953 953 $ printf "Foo\n" > foo.whole
954 954 $ hg commit -m "edit foo"
955 955 $ hg fix -r . -r '.^'
956 956 $ hg log --graph --template '{rev} {desc}\n' --stat
957 957 o 3 edit foo
958 958 |
959 959 o 2 add foo
960 960 foo.whole | 1 +
961 961 1 files changed, 1 insertions(+), 0 deletions(-)
962 962
963 963 @ 1 edit foo
964 964 | foo.whole | 2 +-
965 965 | 1 files changed, 1 insertions(+), 1 deletions(-)
966 966 |
967 967 x 0 add foo
968 968 foo.whole | 1 +
969 969 1 files changed, 1 insertions(+), 0 deletions(-)
970 970
971 971
972 972 $ cd ..
973 973
974 974 Fixing a secret commit should replace it with another secret commit.
975 975
976 976 $ hg init fixsecretcommit
977 977 $ cd fixsecretcommit
978 978
979 979 $ printf "foo\n" > foo.whole
980 980 $ hg commit -Aqm "add foo" --secret
981 981 $ hg fix -r .
982 982 $ hg log --template '{rev} {phase}\n'
983 983 1 secret
984 984 0 secret
985 985
986 986 $ cd ..
987 987
988 988 We should also preserve phase when fixing a draft commit while the user has
989 989 their default set to secret.
990 990
991 991 $ hg init respectphasesnewcommit
992 992 $ cd respectphasesnewcommit
993 993
994 994 $ printf "foo\n" > foo.whole
995 995 $ hg commit -Aqm "add foo"
996 996 $ hg --config phases.newcommit=secret fix -r .
997 997 $ hg log --template '{rev} {phase}\n'
998 998 1 draft
999 999 0 draft
1000 1000
1001 1001 $ cd ..
1002 1002
1003 1003 Debug output should show what fixer commands are being subprocessed, which is
1004 1004 useful for anyone trying to set up a new config.
1005 1005
1006 1006 $ hg init debugoutput
1007 1007 $ cd debugoutput
1008 1008
1009 1009 $ printf "foo\nbar\nbaz\n" > foo.changed
1010 1010 $ hg commit -Aqm "foo"
1011 1011 $ printf "Foo\nbar\nBaz\n" > foo.changed
1012 1012 $ hg --debug fix --working-dir
1013 1013 subprocess: * $TESTTMP/uppercase.py 1-1 3-3 (glob)
1014 1014
1015 1015 $ cd ..
1016 1016
1017 1017 Fixing an obsolete revision can cause divergence, so we abort unless the user
1018 1018 configures to allow it. This is not yet smart enough to know whether there is a
1019 1019 successor, but even then it is not likely intentional or idiomatic to fix an
1020 1020 obsolete revision.
1021 1021
1022 1022 $ hg init abortobsoleterev
1023 1023 $ cd abortobsoleterev
1024 1024
1025 1025 $ printf "foo\n" > foo.changed
1026 1026 $ hg commit -Aqm "foo"
1027 1027 $ hg debugobsolete `hg parents --template '{node}'`
1028 1028 obsoleted 1 changesets
1029 1029 $ hg --hidden fix -r 0
1030 1030 abort: fixing obsolete revision could cause divergence
1031 1031 [255]
1032 1032
1033 1033 $ hg --hidden fix -r 0 --config experimental.evolution.allowdivergence=true
1034 1034 $ hg cat -r tip foo.changed
1035 1035 FOO
1036 1036
1037 1037 $ cd ..
1038 1038
1039 1039 Test all of the available substitution values for fixer commands.
1040 1040
1041 1041 $ hg init substitution
1042 1042 $ cd substitution
1043 1043
1044 1044 $ mkdir foo
1045 1045 $ printf "hello\ngoodbye\n" > foo/bar
1046 1046 $ hg add
1047 1047 adding foo/bar
1048 1048 $ hg --config "fix.fail:command=printf '%s\n' '{rootpath}' '{basename}'" \
1049 1049 > --config "fix.fail:linerange='{first}' '{last}'" \
1050 1050 > --config "fix.fail:pattern=foo/bar" \
1051 1051 > fix --working-dir
1052 1052 $ cat foo/bar
1053 1053 foo/bar
1054 1054 bar
1055 1055 1
1056 1056 2
1057 1057
1058 1058 $ cd ..
1059 1059
1060 1060 The --base flag should allow picking the revisions to diff against for changed
1061 1061 files and incremental line formatting.
1062 1062
1063 1063 $ hg init baseflag
1064 1064 $ cd baseflag
1065 1065
1066 1066 $ printf "one\ntwo\n" > foo.changed
1067 1067 $ printf "bar\n" > bar.changed
1068 1068 $ hg commit -Aqm "first"
1069 1069 $ printf "one\nTwo\n" > foo.changed
1070 1070 $ hg commit -m "second"
1071 1071 $ hg fix -w --base .
1072 1072 $ hg status
1073 1073 $ hg fix -w --base null
1074 1074 $ cat foo.changed
1075 1075 ONE
1076 1076 TWO
1077 1077 $ cat bar.changed
1078 1078 BAR
1079 1079
1080 1080 $ cd ..
1081 1081
1082 1082 If the user asks to fix the parent of another commit, they are asking to create
1083 1083 an orphan. We must respect experimental.evolution.allowunstable.
1084 1084
1085 1085 $ hg init allowunstable
1086 1086 $ cd allowunstable
1087 1087
1088 1088 $ printf "one\n" > foo.whole
1089 1089 $ hg commit -Aqm "first"
1090 1090 $ printf "two\n" > foo.whole
1091 1091 $ hg commit -m "second"
1092 1092 $ hg --config experimental.evolution.allowunstable=False fix -r '.^'
1093 1093 abort: can only fix a changeset together with all its descendants
1094 1094 [255]
1095 1095 $ hg fix -r '.^'
1096 1096 1 new orphan changesets
1097 1097 $ hg cat -r 2 foo.whole
1098 1098 ONE
1099 1099
1100 1100 $ cd ..
1101 1101
1102 1102 The --base flag affects the set of files being fixed. So while the --whole flag
1103 1103 makes the base irrelevant for changed line ranges, it still changes the
1104 1104 meaning and effect of the command. In this example, no files or lines are fixed
1105 1105 until we specify the base, but then we do fix unchanged lines.
1106 1106
1107 1107 $ hg init basewhole
1108 1108 $ cd basewhole
1109 1109 $ printf "foo1\n" > foo.changed
1110 1110 $ hg commit -Aqm "first"
1111 1111 $ printf "foo2\n" >> foo.changed
1112 1112 $ printf "bar\n" > bar.changed
1113 1113 $ hg commit -Aqm "second"
1114 1114
1115 1115 $ hg fix --working-dir --whole
1116 1116 $ cat *.changed
1117 1117 bar
1118 1118 foo1
1119 1119 foo2
1120 1120
1121 1121 $ hg fix --working-dir --base 0 --whole
1122 1122 $ cat *.changed
1123 1123 BAR
1124 1124 FOO1
1125 1125 FOO2
1126 1126
1127 1127 $ cd ..
1128 1128
1129 1129 The :fileset subconfig was a misnomer, so we renamed it to :pattern. We will
1130 1130 still accept :fileset by itself as if it were :pattern, but this will issue a
1131 1131 warning.
1132 1132
1133 1133 $ hg init filesetispattern
1134 1134 $ cd filesetispattern
1135 1135
1136 1136 $ printf "foo\n" > foo.whole
1137 1137 $ printf "first\nsecond\n" > bar.txt
1138 1138 $ hg add -q
1139 1139 $ hg fix -w --config fix.sometool:fileset=bar.txt \
1140 1140 > --config fix.sometool:command="sort -r"
1141 1141 the fix.tool:fileset config name is deprecated; please rename it to fix.tool:pattern
1142 1142
1143 1143 $ cat foo.whole
1144 1144 FOO
1145 1145 $ cat bar.txt
1146 1146 second
1147 1147 first
1148 1148
1149 1149 $ cd ..
1150 1150
1151 1151 The execution order of tools can be controlled. This example doesn't work if
1152 1152 you sort after truncating, but the config defines the correct order while the
1153 1153 definitions are out of order (which might imply the incorrect order given the
1154 1154 implementation of fix). The goal is to use multiple tools to select the lowest
1155 1155 5 numbers in the file.
1156 1156
1157 1157 $ hg init priorityexample
1158 1158 $ cd priorityexample
1159 1159
1160 1160 $ cat >> .hg/hgrc <<EOF
1161 1161 > [fix]
1162 1162 > head:command = head --lines=5
1163 1163 > head:pattern = numbers.txt
1164 1164 > head:priority = 1
1165 1165 > sort:command = sort --numeric-sort
1166 1166 > sort:pattern = numbers.txt
1167 1167 > sort:priority = 2
1168 1168 > EOF
1169 1169
1170 1170 $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
1171 1171 $ hg add -q
1172 1172 $ hg fix -w
1173 1173 $ cat numbers.txt
1174 1174 0
1175 1175 1
1176 1176 2
1177 1177 3
1178 1178 4
1179 1179
1180 1180 And of course we should be able to break this by reversing the execution order.
1181 1181 Test negative priorities while we're at it.
1182 1182
1183 1183 $ cat >> .hg/hgrc <<EOF
1184 1184 > [fix]
1185 1185 > head:priority = -1
1186 1186 > sort:priority = -2
1187 1187 > EOF
1188 1188 $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
1189 1189 $ hg fix -w
1190 1190 $ cat numbers.txt
1191 1191 2
1192 1192 3
1193 1193 6
1194 1194 7
1195 1195 8
1196 1196
1197 1197 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now