##// END OF EJS Templates
tests: use `f --newer` instead of `stat -c` in test-fix.t...
Augie Fackler -
r37611:314f39e5 default
parent child Browse files
Show More
@@ -1,1024 +1,1024 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:fileset=set:**.whole
70 70 > uppercase-changed-lines:command=$PYTHON $UPPERCASEPY
71 71 > uppercase-changed-lines:linerange={first}-{last}
72 72 > uppercase-changed-lines:fileset=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 --base REV [+] revisions to diff against (overrides automatic selection,
108 108 and applies to every revision being fixed)
109 109 -r --rev REV [+] revisions to fix
110 110 -w --working-dir fix the working directory
111 111 --whole always fix every line of a file
112 112
113 113 (some details hidden, use --verbose to show complete help)
114 114
115 115 $ hg help -e fix
116 116 fix extension - rewrite file content in changesets or working copy
117 117 (EXPERIMENTAL)
118 118
119 119 Provides a command that runs configured tools on the contents of modified
120 120 files, writing back any fixes to the working copy or replacing changesets.
121 121
122 122 Here is an example configuration that causes 'hg fix' to apply automatic
123 123 formatting fixes to modified lines in C++ code:
124 124
125 125 [fix]
126 126 clang-format:command=clang-format --assume-filename={rootpath}
127 127 clang-format:linerange=--lines={first}:{last}
128 128 clang-format:fileset=set:**.cpp or **.hpp
129 129
130 130 The :command suboption forms the first part of the shell command that will be
131 131 used to fix a file. The content of the file is passed on standard input, and
132 132 the fixed file content is expected on standard output. If there is any output
133 133 on standard error, the file will not be affected. Some values may be
134 134 substituted into the command:
135 135
136 136 {rootpath} The path of the file being fixed, relative to the repo root
137 137 {basename} The name of the file being fixed, without the directory path
138 138
139 139 If the :linerange suboption is set, the tool will only be run if there are
140 140 changed lines in a file. The value of this suboption is appended to the shell
141 141 command once for every range of changed lines in the file. Some values may be
142 142 substituted into the command:
143 143
144 144 {first} The 1-based line number of the first line in the modified range
145 145 {last} The 1-based line number of the last line in the modified range
146 146
147 147 The :fileset suboption determines which files will be passed through each
148 148 configured tool. See 'hg help fileset' for possible values. If there are file
149 149 arguments to 'hg fix', the intersection of these filesets is used.
150 150
151 151 There is also a configurable limit for the maximum size of file that will be
152 152 processed by 'hg fix':
153 153
154 154 [fix]
155 155 maxfilesize=2MB
156 156
157 157 list of commands:
158 158
159 159 fix rewrite file content in changesets or working directory
160 160
161 161 (use 'hg help -v -e fix' to show built-in aliases and global options)
162 162
163 163 There is no default behavior in the absence of --rev and --working-dir.
164 164
165 165 $ hg init badusage
166 166 $ cd badusage
167 167
168 168 $ hg fix
169 169 abort: no changesets specified
170 170 (use --rev or --working-dir)
171 171 [255]
172 172 $ hg fix --whole
173 173 abort: no changesets specified
174 174 (use --rev or --working-dir)
175 175 [255]
176 176 $ hg fix --base 0
177 177 abort: no changesets specified
178 178 (use --rev or --working-dir)
179 179 [255]
180 180
181 181 Fixing a public revision isn't allowed. It should abort early enough that
182 182 nothing happens, even to the working directory.
183 183
184 184 $ printf "hello\n" > hello.whole
185 185 $ hg commit -Aqm "hello"
186 186 $ hg phase -r 0 --public
187 187 $ hg fix -r 0
188 188 abort: can't fix immutable changeset 0:6470986d2e7b
189 189 [255]
190 190 $ hg fix -r 0 --working-dir
191 191 abort: can't fix immutable changeset 0:6470986d2e7b
192 192 [255]
193 193 $ hg cat -r tip hello.whole
194 194 hello
195 195 $ cat hello.whole
196 196 hello
197 197
198 198 $ cd ..
199 199
200 200 Fixing a clean working directory should do nothing. Even the --whole flag
201 201 shouldn't cause any clean files to be fixed. Specifying a clean file explicitly
202 202 should only fix it if the fixer always fixes the whole file. The combination of
203 203 an explicit filename and --whole should format the entire file regardless.
204 204
205 205 $ hg init fixcleanwdir
206 206 $ cd fixcleanwdir
207 207
208 208 $ printf "hello\n" > hello.changed
209 209 $ printf "world\n" > hello.whole
210 210 $ hg commit -Aqm "foo"
211 211 $ hg fix --working-dir
212 212 $ hg diff
213 213 $ hg fix --working-dir --whole
214 214 $ hg diff
215 215 $ hg fix --working-dir *
216 216 $ cat *
217 217 hello
218 218 WORLD
219 219 $ hg revert --all --no-backup
220 220 reverting hello.whole
221 221 $ hg fix --working-dir * --whole
222 222 $ cat *
223 223 HELLO
224 224 WORLD
225 225
226 226 The same ideas apply to fixing a revision, so we create a revision that doesn't
227 227 modify either of the files in question and try fixing it. This also tests that
228 228 we ignore a file that doesn't match any configured fixer.
229 229
230 230 $ hg revert --all --no-backup
231 231 reverting hello.changed
232 232 reverting hello.whole
233 233 $ printf "unimportant\n" > some.file
234 234 $ hg commit -Aqm "some other file"
235 235
236 236 $ hg fix -r .
237 237 $ hg cat -r tip *
238 238 hello
239 239 world
240 240 unimportant
241 241 $ hg fix -r . --whole
242 242 $ hg cat -r tip *
243 243 hello
244 244 world
245 245 unimportant
246 246 $ hg fix -r . *
247 247 $ hg cat -r tip *
248 248 hello
249 249 WORLD
250 250 unimportant
251 251 $ hg fix -r . * --whole --config experimental.evolution.allowdivergence=true
252 252 2 new content-divergent changesets
253 253 $ hg cat -r tip *
254 254 HELLO
255 255 WORLD
256 256 unimportant
257 257
258 258 $ cd ..
259 259
260 260 Fixing the working directory should still work if there are no revisions.
261 261
262 262 $ hg init norevisions
263 263 $ cd norevisions
264 264
265 265 $ printf "something\n" > something.whole
266 266 $ hg add
267 267 adding something.whole
268 268 $ hg fix --working-dir
269 269 $ cat something.whole
270 270 SOMETHING
271 271
272 272 $ cd ..
273 273
274 274 Test the effect of fixing the working directory for each possible status, with
275 275 and without providing explicit file arguments.
276 276
277 277 $ hg init implicitlyfixstatus
278 278 $ cd implicitlyfixstatus
279 279
280 280 $ printf "modified\n" > modified.whole
281 281 $ printf "removed\n" > removed.whole
282 282 $ printf "deleted\n" > deleted.whole
283 283 $ printf "clean\n" > clean.whole
284 284 $ printf "ignored.whole" > .hgignore
285 285 $ hg commit -Aqm "stuff"
286 286
287 287 $ printf "modified!!!\n" > modified.whole
288 288 $ printf "unknown\n" > unknown.whole
289 289 $ printf "ignored\n" > ignored.whole
290 290 $ printf "added\n" > added.whole
291 291 $ hg add added.whole
292 292 $ hg remove removed.whole
293 293 $ rm deleted.whole
294 294
295 295 $ hg status --all
296 296 M modified.whole
297 297 A added.whole
298 298 R removed.whole
299 299 ! deleted.whole
300 300 ? unknown.whole
301 301 I ignored.whole
302 302 C .hgignore
303 303 C clean.whole
304 304
305 305 $ hg fix --working-dir
306 306
307 307 $ hg status --all
308 308 M modified.whole
309 309 A added.whole
310 310 R removed.whole
311 311 ! deleted.whole
312 312 ? unknown.whole
313 313 I ignored.whole
314 314 C .hgignore
315 315 C clean.whole
316 316
317 317 $ cat *.whole
318 318 ADDED
319 319 clean
320 320 ignored
321 321 MODIFIED!!!
322 322 unknown
323 323
324 324 $ printf "modified!!!\n" > modified.whole
325 325 $ printf "added\n" > added.whole
326 326 $ hg fix --working-dir *.whole
327 327
328 328 $ hg status --all
329 329 M clean.whole
330 330 M modified.whole
331 331 A added.whole
332 332 R removed.whole
333 333 ! deleted.whole
334 334 ? unknown.whole
335 335 I ignored.whole
336 336 C .hgignore
337 337
338 338 It would be better if this also fixed the unknown file.
339 339 $ cat *.whole
340 340 ADDED
341 341 CLEAN
342 342 ignored
343 343 MODIFIED!!!
344 344 unknown
345 345
346 346 $ cd ..
347 347
348 348 Test that incremental fixing works on files with additions, deletions, and
349 349 changes in multiple line ranges. Note that deletions do not generally cause
350 350 neighboring lines to be fixed, so we don't return a line range for purely
351 351 deleted sections. In the future we should support a :deletion config that
352 352 allows fixers to know where deletions are located.
353 353
354 354 $ hg init incrementalfixedlines
355 355 $ cd incrementalfixedlines
356 356
357 357 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.txt
358 358 $ hg commit -Aqm "foo"
359 359 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.txt
360 360
361 361 $ hg --config "fix.fail:command=echo" \
362 362 > --config "fix.fail:linerange={first}:{last}" \
363 363 > --config "fix.fail:fileset=foo.txt" \
364 364 > fix --working-dir
365 365 $ cat foo.txt
366 366 1:1 4:6 8:8
367 367
368 368 $ cd ..
369 369
370 370 Test that --whole fixes all lines regardless of the diffs present.
371 371
372 372 $ hg init wholeignoresdiffs
373 373 $ cd wholeignoresdiffs
374 374
375 375 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.changed
376 376 $ hg commit -Aqm "foo"
377 377 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.changed
378 378 $ hg fix --working-dir --whole
379 379 $ cat foo.changed
380 380 ZZ
381 381 A
382 382 C
383 383 DD
384 384 EE
385 385 FF
386 386 F
387 387 GG
388 388
389 389 $ cd ..
390 390
391 391 We should do nothing with symlinks, and their targets should be unaffected. Any
392 392 other behavior would be more complicated to implement and harder to document.
393 393
394 394 #if symlink
395 395 $ hg init dontmesswithsymlinks
396 396 $ cd dontmesswithsymlinks
397 397
398 398 $ printf "hello\n" > hello.whole
399 399 $ ln -s hello.whole hellolink
400 400 $ hg add
401 401 adding hello.whole
402 402 adding hellolink
403 403 $ hg fix --working-dir hellolink
404 404 $ hg status
405 405 A hello.whole
406 406 A hellolink
407 407
408 408 $ cd ..
409 409 #endif
410 410
411 411 We should allow fixers to run on binary files, even though this doesn't sound
412 412 like a common use case. There's not much benefit to disallowing it, and users
413 413 can add "and not binary()" to their filesets if needed. The Mercurial
414 414 philosophy is generally to not handle binary files specially anyway.
415 415
416 416 $ hg init cantouchbinaryfiles
417 417 $ cd cantouchbinaryfiles
418 418
419 419 $ printf "hello\0\n" > hello.whole
420 420 $ hg add
421 421 adding hello.whole
422 422 $ hg fix --working-dir 'set:binary()'
423 423 $ cat hello.whole
424 424 HELLO\x00 (esc)
425 425
426 426 $ cd ..
427 427
428 428 We have a config for the maximum size of file we will attempt to fix. This can
429 429 be helpful to avoid running unsuspecting fixer tools on huge inputs, which
430 430 could happen by accident without a well considered configuration. A more
431 431 precise configuration could use the size() fileset function if one global limit
432 432 is undesired.
433 433
434 434 $ hg init maxfilesize
435 435 $ cd maxfilesize
436 436
437 437 $ printf "this file is huge\n" > hello.whole
438 438 $ hg add
439 439 adding hello.whole
440 440 $ hg --config fix.maxfilesize=10 fix --working-dir
441 441 ignoring file larger than 10 bytes: hello.whole
442 442 $ cat hello.whole
443 443 this file is huge
444 444
445 445 $ cd ..
446 446
447 447 If we specify a file to fix, other files should be left alone, even if they
448 448 have changes.
449 449
450 450 $ hg init fixonlywhatitellyouto
451 451 $ cd fixonlywhatitellyouto
452 452
453 453 $ printf "fix me!\n" > fixme.whole
454 454 $ printf "not me.\n" > notme.whole
455 455 $ hg add
456 456 adding fixme.whole
457 457 adding notme.whole
458 458 $ hg fix --working-dir fixme.whole
459 459 $ cat *.whole
460 460 FIX ME!
461 461 not me.
462 462
463 463 $ cd ..
464 464
465 465 Specifying a directory name should fix all its files and subdirectories.
466 466
467 467 $ hg init fixdirectory
468 468 $ cd fixdirectory
469 469
470 470 $ mkdir -p dir1/dir2
471 471 $ printf "foo\n" > foo.whole
472 472 $ printf "bar\n" > dir1/bar.whole
473 473 $ printf "baz\n" > dir1/dir2/baz.whole
474 474 $ hg add
475 475 adding dir1/bar.whole
476 476 adding dir1/dir2/baz.whole
477 477 adding foo.whole
478 478 $ hg fix --working-dir dir1
479 479 $ cat foo.whole dir1/bar.whole dir1/dir2/baz.whole
480 480 foo
481 481 BAR
482 482 BAZ
483 483
484 484 $ cd ..
485 485
486 486 Fixing a file in the working directory that needs no fixes should not actually
487 487 write back to the file, so for example the mtime shouldn't change.
488 488
489 489 $ hg init donttouchunfixedfiles
490 490 $ cd donttouchunfixedfiles
491 491
492 492 $ printf "NO FIX NEEDED\n" > foo.whole
493 493 $ hg add
494 494 adding foo.whole
495 $ OLD_MTIME=`stat -c %Y foo.whole`
496 $ sleep 1 # mtime has a resolution of one second.
495 $ cp foo.whole foo.whole.orig
496 $ sleep 2 # mtime has a resolution of one or two seconds.
497 497 $ hg fix --working-dir
498 $ NEW_MTIME=`stat -c %Y foo.whole`
499 $ test $OLD_MTIME = $NEW_MTIME
498 $ f foo.whole --newer foo.whole.orig
499 foo.whole: older than foo.whole.orig
500 500
501 501 $ cd ..
502 502
503 503 When a fixer prints to stderr, we assume that it has failed. We should show the
504 504 error messages to the user, and we should not let the failing fixer affect the
505 505 file it was fixing (many code formatters might emit error messages on stderr
506 506 and nothing on stdout, which would cause us the clear the file). We show the
507 507 user which fixer failed and which revision, but we assume that the fixer will
508 508 print the filename if it is relevant.
509 509
510 510 $ hg init showstderr
511 511 $ cd showstderr
512 512
513 513 $ printf "hello\n" > hello.txt
514 514 $ hg add
515 515 adding hello.txt
516 516 $ hg --config "fix.fail:command=printf 'HELLO\n' ; \
517 517 > printf '{rootpath}: some\nerror' >&2" \
518 518 > --config "fix.fail:fileset=hello.txt" \
519 519 > fix --working-dir
520 520 [wdir] fail: hello.txt: some
521 521 [wdir] fail: error
522 522 $ cat hello.txt
523 523 hello
524 524
525 525 $ cd ..
526 526
527 527 Fixing the working directory and its parent revision at the same time should
528 528 check out the replacement revision for the parent. This prevents any new
529 529 uncommitted changes from appearing. We test this for a clean working directory
530 530 and a dirty one. In both cases, all lines/files changed since the grandparent
531 531 will be fixed. The grandparent is the "baserev" for both the parent and the
532 532 working copy.
533 533
534 534 $ hg init fixdotandcleanwdir
535 535 $ cd fixdotandcleanwdir
536 536
537 537 $ printf "hello\n" > hello.whole
538 538 $ printf "world\n" > world.whole
539 539 $ hg commit -Aqm "the parent commit"
540 540
541 541 $ hg parents --template '{rev} {desc}\n'
542 542 0 the parent commit
543 543 $ hg fix --working-dir -r .
544 544 $ hg parents --template '{rev} {desc}\n'
545 545 1 the parent commit
546 546 $ hg cat -r . *.whole
547 547 HELLO
548 548 WORLD
549 549 $ cat *.whole
550 550 HELLO
551 551 WORLD
552 552 $ hg status
553 553
554 554 $ cd ..
555 555
556 556 Same test with a dirty working copy.
557 557
558 558 $ hg init fixdotanddirtywdir
559 559 $ cd fixdotanddirtywdir
560 560
561 561 $ printf "hello\n" > hello.whole
562 562 $ printf "world\n" > world.whole
563 563 $ hg commit -Aqm "the parent commit"
564 564
565 565 $ printf "hello,\n" > hello.whole
566 566 $ printf "world!\n" > world.whole
567 567
568 568 $ hg parents --template '{rev} {desc}\n'
569 569 0 the parent commit
570 570 $ hg fix --working-dir -r .
571 571 $ hg parents --template '{rev} {desc}\n'
572 572 1 the parent commit
573 573 $ hg cat -r . *.whole
574 574 HELLO
575 575 WORLD
576 576 $ cat *.whole
577 577 HELLO,
578 578 WORLD!
579 579 $ hg status
580 580 M hello.whole
581 581 M world.whole
582 582
583 583 $ cd ..
584 584
585 585 When we have a chain of commits that change mutually exclusive lines of code,
586 586 we should be able to do incremental fixing that causes each commit in the chain
587 587 to include fixes made to the previous commits. This prevents children from
588 588 backing out the fixes made in their parents. A dirty working directory is
589 589 conceptually similar to another commit in the chain.
590 590
591 591 $ hg init incrementallyfixchain
592 592 $ cd incrementallyfixchain
593 593
594 594 $ cat > file.changed <<EOF
595 595 > first
596 596 > second
597 597 > third
598 598 > fourth
599 599 > fifth
600 600 > EOF
601 601 $ hg commit -Aqm "the common ancestor (the baserev)"
602 602 $ cat > file.changed <<EOF
603 603 > first (changed)
604 604 > second
605 605 > third
606 606 > fourth
607 607 > fifth
608 608 > EOF
609 609 $ hg commit -Aqm "the first commit to fix"
610 610 $ cat > file.changed <<EOF
611 611 > first (changed)
612 612 > second
613 613 > third (changed)
614 614 > fourth
615 615 > fifth
616 616 > EOF
617 617 $ hg commit -Aqm "the second commit to fix"
618 618 $ cat > file.changed <<EOF
619 619 > first (changed)
620 620 > second
621 621 > third (changed)
622 622 > fourth
623 623 > fifth (changed)
624 624 > EOF
625 625
626 626 $ hg fix -r . -r '.^' --working-dir
627 627
628 628 $ hg parents --template '{rev}\n'
629 629 4
630 630 $ hg cat -r '.^^' file.changed
631 631 first
632 632 second
633 633 third
634 634 fourth
635 635 fifth
636 636 $ hg cat -r '.^' file.changed
637 637 FIRST (CHANGED)
638 638 second
639 639 third
640 640 fourth
641 641 fifth
642 642 $ hg cat -r . file.changed
643 643 FIRST (CHANGED)
644 644 second
645 645 THIRD (CHANGED)
646 646 fourth
647 647 fifth
648 648 $ cat file.changed
649 649 FIRST (CHANGED)
650 650 second
651 651 THIRD (CHANGED)
652 652 fourth
653 653 FIFTH (CHANGED)
654 654
655 655 $ cd ..
656 656
657 657 If we incrementally fix a merge commit, we should fix any lines that changed
658 658 versus either parent. You could imagine only fixing the intersection or some
659 659 other subset, but this is necessary if either parent is being fixed. It
660 660 prevents us from forgetting fixes made in either parent.
661 661
662 662 $ hg init incrementallyfixmergecommit
663 663 $ cd incrementallyfixmergecommit
664 664
665 665 $ printf "a\nb\nc\n" > file.changed
666 666 $ hg commit -Aqm "ancestor"
667 667
668 668 $ printf "aa\nb\nc\n" > file.changed
669 669 $ hg commit -m "change a"
670 670
671 671 $ hg checkout '.^'
672 672 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
673 673 $ printf "a\nb\ncc\n" > file.changed
674 674 $ hg commit -m "change c"
675 675 created new head
676 676
677 677 $ hg merge
678 678 merging file.changed
679 679 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
680 680 (branch merge, don't forget to commit)
681 681 $ hg commit -m "merge"
682 682 $ hg cat -r . file.changed
683 683 aa
684 684 b
685 685 cc
686 686
687 687 $ hg fix -r . --working-dir
688 688 $ hg cat -r . file.changed
689 689 AA
690 690 b
691 691 CC
692 692
693 693 $ cd ..
694 694
695 695 Abort fixing revisions if there is an unfinished operation. We don't want to
696 696 make things worse by editing files or stripping/obsoleting things. Also abort
697 697 fixing the working directory if there are unresolved merge conflicts.
698 698
699 699 $ hg init abortunresolved
700 700 $ cd abortunresolved
701 701
702 702 $ echo "foo1" > foo.whole
703 703 $ hg commit -Aqm "foo 1"
704 704
705 705 $ hg update null
706 706 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
707 707 $ echo "foo2" > foo.whole
708 708 $ hg commit -Aqm "foo 2"
709 709
710 710 $ hg --config extensions.rebase= rebase -r 1 -d 0
711 711 rebasing 1:c3b6dc0e177a "foo 2" (tip)
712 712 merging foo.whole
713 713 warning: conflicts while merging foo.whole! (edit, then use 'hg resolve --mark')
714 714 unresolved conflicts (see hg resolve, then hg rebase --continue)
715 715 [1]
716 716
717 717 $ hg --config extensions.rebase= fix --working-dir
718 718 abort: unresolved conflicts
719 719 (use 'hg resolve')
720 720 [255]
721 721
722 722 $ hg --config extensions.rebase= fix -r .
723 723 abort: rebase in progress
724 724 (use 'hg rebase --continue' or 'hg rebase --abort')
725 725 [255]
726 726
727 727 When fixing a file that was renamed, we should diff against the source of the
728 728 rename for incremental fixing and we should correctly reproduce the rename in
729 729 the replacement revision.
730 730
731 731 $ hg init fixrenamecommit
732 732 $ cd fixrenamecommit
733 733
734 734 $ printf "a\nb\nc\n" > source.changed
735 735 $ hg commit -Aqm "source revision"
736 736 $ hg move source.changed dest.changed
737 737 $ printf "a\nb\ncc\n" > dest.changed
738 738 $ hg commit -m "dest revision"
739 739
740 740 $ hg fix -r .
741 741 $ hg log -r tip --copies --template "{file_copies}\n"
742 742 dest.changed (source.changed)
743 743 $ hg cat -r tip dest.changed
744 744 a
745 745 b
746 746 CC
747 747
748 748 $ cd ..
749 749
750 750 When fixing revisions that remove files we must ensure that the replacement
751 751 actually removes the file, whereas it could accidentally leave it unchanged or
752 752 write an empty string to it.
753 753
754 754 $ hg init fixremovedfile
755 755 $ cd fixremovedfile
756 756
757 757 $ printf "foo\n" > foo.whole
758 758 $ printf "bar\n" > bar.whole
759 759 $ hg commit -Aqm "add files"
760 760 $ hg remove bar.whole
761 761 $ hg commit -m "remove file"
762 762 $ hg status --change .
763 763 R bar.whole
764 764 $ hg fix -r . foo.whole
765 765 $ hg status --change tip
766 766 M foo.whole
767 767 R bar.whole
768 768
769 769 $ cd ..
770 770
771 771 If fixing a revision finds no fixes to make, no replacement revision should be
772 772 created.
773 773
774 774 $ hg init nofixesneeded
775 775 $ cd nofixesneeded
776 776
777 777 $ printf "FOO\n" > foo.whole
778 778 $ hg commit -Aqm "add file"
779 779 $ hg log --template '{rev}\n'
780 780 0
781 781 $ hg fix -r .
782 782 $ hg log --template '{rev}\n'
783 783 0
784 784
785 785 $ cd ..
786 786
787 787 If fixing a commit reverts all the changes in the commit, we replace it with a
788 788 commit that changes no files.
789 789
790 790 $ hg init nochangesleft
791 791 $ cd nochangesleft
792 792
793 793 $ printf "FOO\n" > foo.whole
794 794 $ hg commit -Aqm "add file"
795 795 $ printf "foo\n" > foo.whole
796 796 $ hg commit -m "edit file"
797 797 $ hg status --change .
798 798 M foo.whole
799 799 $ hg fix -r .
800 800 $ hg status --change tip
801 801
802 802 $ cd ..
803 803
804 804 If we fix a parent and child revision together, the child revision must be
805 805 replaced if the parent is replaced, even if the diffs of the child needed no
806 806 fixes. However, we're free to not replace revisions that need no fixes and have
807 807 no ancestors that are replaced.
808 808
809 809 $ hg init mustreplacechild
810 810 $ cd mustreplacechild
811 811
812 812 $ printf "FOO\n" > foo.whole
813 813 $ hg commit -Aqm "add foo"
814 814 $ printf "foo\n" > foo.whole
815 815 $ hg commit -m "edit foo"
816 816 $ printf "BAR\n" > bar.whole
817 817 $ hg commit -Aqm "add bar"
818 818
819 819 $ hg log --graph --template '{node|shortest} {files}'
820 820 @ bc05 bar.whole
821 821 |
822 822 o 4fd2 foo.whole
823 823 |
824 824 o f9ac foo.whole
825 825
826 826 $ hg fix -r 0:2
827 827 $ hg log --graph --template '{node|shortest} {files}'
828 828 o 3801 bar.whole
829 829 |
830 830 o 38cc
831 831 |
832 832 | @ bc05 bar.whole
833 833 | |
834 834 | x 4fd2 foo.whole
835 835 |/
836 836 o f9ac foo.whole
837 837
838 838
839 839 $ cd ..
840 840
841 841 It's also possible that the child needs absolutely no changes, but we still
842 842 need to replace it to update its parent. If we skipped replacing the child
843 843 because it had no file content changes, it would become an orphan for no good
844 844 reason.
845 845
846 846 $ hg init mustreplacechildevenifnop
847 847 $ cd mustreplacechildevenifnop
848 848
849 849 $ printf "Foo\n" > foo.whole
850 850 $ hg commit -Aqm "add a bad foo"
851 851 $ printf "FOO\n" > foo.whole
852 852 $ hg commit -m "add a good foo"
853 853 $ hg fix -r . -r '.^'
854 854 $ hg log --graph --template '{rev} {desc}'
855 855 o 3 add a good foo
856 856 |
857 857 o 2 add a bad foo
858 858
859 859 @ 1 add a good foo
860 860 |
861 861 x 0 add a bad foo
862 862
863 863
864 864 $ cd ..
865 865
866 866 Similar to the case above, the child revision may become empty as a result of
867 867 fixing its parent. We should still create an empty replacement child.
868 868 TODO: determine how this should interact with ui.allowemptycommit given that
869 869 the empty replacement could have children.
870 870
871 871 $ hg init mustreplacechildevenifempty
872 872 $ cd mustreplacechildevenifempty
873 873
874 874 $ printf "foo\n" > foo.whole
875 875 $ hg commit -Aqm "add foo"
876 876 $ printf "Foo\n" > foo.whole
877 877 $ hg commit -m "edit foo"
878 878 $ hg fix -r . -r '.^'
879 879 $ hg log --graph --template '{rev} {desc}\n' --stat
880 880 o 3 edit foo
881 881 |
882 882 o 2 add foo
883 883 foo.whole | 1 +
884 884 1 files changed, 1 insertions(+), 0 deletions(-)
885 885
886 886 @ 1 edit foo
887 887 | foo.whole | 2 +-
888 888 | 1 files changed, 1 insertions(+), 1 deletions(-)
889 889 |
890 890 x 0 add foo
891 891 foo.whole | 1 +
892 892 1 files changed, 1 insertions(+), 0 deletions(-)
893 893
894 894
895 895 $ cd ..
896 896
897 897 Fixing a secret commit should replace it with another secret commit.
898 898
899 899 $ hg init fixsecretcommit
900 900 $ cd fixsecretcommit
901 901
902 902 $ printf "foo\n" > foo.whole
903 903 $ hg commit -Aqm "add foo" --secret
904 904 $ hg fix -r .
905 905 $ hg log --template '{rev} {phase}\n'
906 906 1 secret
907 907 0 secret
908 908
909 909 $ cd ..
910 910
911 911 We should also preserve phase when fixing a draft commit while the user has
912 912 their default set to secret.
913 913
914 914 $ hg init respectphasesnewcommit
915 915 $ cd respectphasesnewcommit
916 916
917 917 $ printf "foo\n" > foo.whole
918 918 $ hg commit -Aqm "add foo"
919 919 $ hg --config phases.newcommit=secret fix -r .
920 920 $ hg log --template '{rev} {phase}\n'
921 921 1 draft
922 922 0 draft
923 923
924 924 $ cd ..
925 925
926 926 Debug output should show what fixer commands are being subprocessed, which is
927 927 useful for anyone trying to set up a new config.
928 928
929 929 $ hg init debugoutput
930 930 $ cd debugoutput
931 931
932 932 $ printf "foo\nbar\nbaz\n" > foo.changed
933 933 $ hg commit -Aqm "foo"
934 934 $ printf "Foo\nbar\nBaz\n" > foo.changed
935 935 $ hg --debug fix --working-dir
936 936 subprocess: * $TESTTMP/uppercase.py 1-1 3-3 (glob)
937 937
938 938 $ cd ..
939 939
940 940 Fixing an obsolete revision can cause divergence, so we abort unless the user
941 941 configures to allow it. This is not yet smart enough to know whether there is a
942 942 successor, but even then it is not likely intentional or idiomatic to fix an
943 943 obsolete revision.
944 944
945 945 $ hg init abortobsoleterev
946 946 $ cd abortobsoleterev
947 947
948 948 $ printf "foo\n" > foo.changed
949 949 $ hg commit -Aqm "foo"
950 950 $ hg debugobsolete `hg parents --template '{node}'`
951 951 obsoleted 1 changesets
952 952 $ hg --hidden fix -r 0
953 953 abort: fixing obsolete revision could cause divergence
954 954 [255]
955 955
956 956 $ hg --hidden fix -r 0 --config experimental.evolution.allowdivergence=true
957 957 $ hg cat -r tip foo.changed
958 958 FOO
959 959
960 960 $ cd ..
961 961
962 962 Test all of the available substitution values for fixer commands.
963 963
964 964 $ hg init substitution
965 965 $ cd substitution
966 966
967 967 $ mkdir foo
968 968 $ printf "hello\ngoodbye\n" > foo/bar
969 969 $ hg add
970 970 adding foo/bar
971 971 $ hg --config "fix.fail:command=printf '%s\n' '{rootpath}' '{basename}'" \
972 972 > --config "fix.fail:linerange='{first}' '{last}'" \
973 973 > --config "fix.fail:fileset=foo/bar" \
974 974 > fix --working-dir
975 975 $ cat foo/bar
976 976 foo/bar
977 977 bar
978 978 1
979 979 2
980 980
981 981 $ cd ..
982 982
983 983 The --base flag should allow picking the revisions to diff against for changed
984 984 files and incremental line formatting.
985 985
986 986 $ hg init baseflag
987 987 $ cd baseflag
988 988
989 989 $ printf "one\ntwo\n" > foo.changed
990 990 $ printf "bar\n" > bar.changed
991 991 $ hg commit -Aqm "first"
992 992 $ printf "one\nTwo\n" > foo.changed
993 993 $ hg commit -m "second"
994 994 $ hg fix -w --base .
995 995 $ hg status
996 996 $ hg fix -w --base null
997 997 $ cat foo.changed
998 998 ONE
999 999 TWO
1000 1000 $ cat bar.changed
1001 1001 BAR
1002 1002
1003 1003 $ cd ..
1004 1004
1005 1005 If the user asks to fix the parent of another commit, they are asking to create
1006 1006 an orphan. We must respect experimental.evolution.allowunstable.
1007 1007
1008 1008 $ hg init allowunstable
1009 1009 $ cd allowunstable
1010 1010
1011 1011 $ printf "one\n" > foo.whole
1012 1012 $ hg commit -Aqm "first"
1013 1013 $ printf "two\n" > foo.whole
1014 1014 $ hg commit -m "second"
1015 1015 $ hg --config experimental.evolution.allowunstable=False fix -r '.^'
1016 1016 abort: can only fix a changeset together with all its descendants
1017 1017 [255]
1018 1018 $ hg fix -r '.^'
1019 1019 1 new orphan changesets
1020 1020 $ hg cat -r 2 foo.whole
1021 1021 ONE
1022 1022
1023 1023 $ cd ..
1024 1024
General Comments 0
You need to be logged in to leave comments. Login now