##// END OF EJS Templates
tests: change the fixer commands to use the buffer attribute on stdio objects...
Matt Harbison -
r47862:ea563187 stable
parent child Browse files
Show More
@@ -1,553 +1,555 b''
1 1 A script that implements uppercasing all letters in a file.
2 2
3 3 $ UPPERCASEPY="$TESTTMP/uppercase.py"
4 4 $ cat > $UPPERCASEPY <<EOF
5 5 > import sys
6 6 > from mercurial.utils.procutil import setbinary
7 7 > setbinary(sys.stdin)
8 8 > setbinary(sys.stdout)
9 > sys.stdout.write(sys.stdin.read().upper())
9 > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
10 > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
11 > stdout.write(stdin.read().upper())
10 12 > EOF
11 13 $ TESTLINES="foo\nbar\nbaz\n"
12 14 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY
13 15 FOO
14 16 BAR
15 17 BAZ
16 18
17 19 Tests for the fix extension's behavior around non-trivial history topologies.
18 20 Looks for correct incremental fixing and reproduction of parent/child
19 21 relationships. We indicate fixed file content by uppercasing it.
20 22
21 23 $ cat >> $HGRCPATH <<EOF
22 24 > [extensions]
23 25 > fix =
24 26 > strip =
25 27 > debugdrawdag=$TESTDIR/drawdag.py
26 28 > [fix]
27 29 > uppercase-whole-file:command="$PYTHON" $UPPERCASEPY
28 30 > uppercase-whole-file:pattern=set:**
29 31 > EOF
30 32
31 33 This tests the only behavior that should really be affected by obsolescence, so
32 34 we'll test it with evolution off and on. This only changes the revision
33 35 numbers, if all is well.
34 36
35 37 #testcases obsstore-off obsstore-on
36 38 #if obsstore-on
37 39 $ cat >> $HGRCPATH <<EOF
38 40 > [experimental]
39 41 > evolution.createmarkers=True
40 42 > evolution.allowunstable=True
41 43 > EOF
42 44 #endif
43 45
44 46 Setting up the test topology. Scroll down to see the graph produced. We make it
45 47 clear which files were modified in each revision. It's enough to test at the
46 48 file granularity, because that demonstrates which baserevs were diffed against.
47 49 The computation of changed lines is orthogonal and tested separately.
48 50
49 51 $ hg init repo
50 52 $ cd repo
51 53
52 54 $ printf "aaaa\n" > a
53 55 $ hg commit -Am "change A"
54 56 adding a
55 57 $ printf "bbbb\n" > b
56 58 $ hg commit -Am "change B"
57 59 adding b
58 60 $ printf "cccc\n" > c
59 61 $ hg commit -Am "change C"
60 62 adding c
61 63 $ hg checkout 0
62 64 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
63 65 $ printf "dddd\n" > d
64 66 $ hg commit -Am "change D"
65 67 adding d
66 68 created new head
67 69 $ hg merge -r 2
68 70 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 71 (branch merge, don't forget to commit)
70 72 $ printf "eeee\n" > e
71 73 $ hg commit -Am "change E"
72 74 adding e
73 75 $ hg checkout 0
74 76 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
75 77 $ printf "ffff\n" > f
76 78 $ hg commit -Am "change F"
77 79 adding f
78 80 created new head
79 81 $ hg checkout 0
80 82 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
81 83 $ printf "gggg\n" > g
82 84 $ hg commit -Am "change G"
83 85 adding g
84 86 created new head
85 87 $ hg merge -r 5
86 88 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 89 (branch merge, don't forget to commit)
88 90 $ printf "hhhh\n" > h
89 91 $ hg commit -Am "change H (child of b53d63e816fb and 0e49f92ee6e9)"
90 92 adding h
91 93 $ hg merge -r 4
92 94 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 95 (branch merge, don't forget to commit)
94 96 $ printf "iiii\n" > i
95 97 $ hg commit -Am "change I"
96 98 adding i
97 99 $ hg checkout 2
98 100 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
99 101 $ printf "jjjj\n" > j
100 102 $ hg commit -Am "change J (child of 7f371349286e)"
101 103 adding j
102 104 created new head
103 105 $ hg checkout 7
104 106 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
105 107 $ printf "kkkk\n" > k
106 108 $ hg add
107 109 adding k
108 110
109 111 $ hg log --graph --template '{rev}:{node|short} {desc}\n'
110 112 o 9:884041ccc490 change J (child of 7f371349286e)
111 113 |
112 114 | o 8:b7c772105fd2 change I
113 115 | |\
114 116 | | @ 7:4e7b9312dad2 change H (child of b53d63e816fb and 0e49f92ee6e9)
115 117 | | |\
116 118 | | | o 6:0e49f92ee6e9 change G
117 119 | | | |
118 120 | | o | 5:b53d63e816fb change F
119 121 | | |/
120 122 | o | 4:ddad58af5e51 change E
121 123 |/| |
122 124 | o | 3:c015ebfd2bfe change D
123 125 | |/
124 126 o | 2:7f371349286e change C
125 127 | |
126 128 o | 1:388fdd33fea0 change B
127 129 |/
128 130 o 0:a55a84d97a24 change A
129 131
130 132
131 133 Fix all but the root revision and its four children.
132 134
133 135 $ hg fix -r '2|4|7|8|9' --working-dir
134 136 saved backup bundle to * (glob) (obsstore-off !)
135 137
136 138 The five revisions remain, but the other revisions were fixed and replaced. All
137 139 parent pointers have been accurately set to reproduce the previous topology
138 140 (though it is rendered in a slightly different order now).
139 141
140 142 #if obsstore-on
141 143 $ hg log --graph --template '{rev}:{node|short} {desc}\n'
142 144 o 14:d8d0e7974598 change J (child of 89de0da1d5da)
143 145 |
144 146 | o 13:4fc0b354461e change I
145 147 | |\
146 148 | | @ 12:1c45f3923443 change H (child of b53d63e816fb and 0e49f92ee6e9)
147 149 | | |\
148 150 | o | | 11:d75754455722 change E
149 151 |/| | |
150 152 o | | | 10:89de0da1d5da change C
151 153 | | | |
152 154 | | | o 6:0e49f92ee6e9 change G
153 155 | | | |
154 156 | | o | 5:b53d63e816fb change F
155 157 | | |/
156 158 | o / 3:c015ebfd2bfe change D
157 159 | |/
158 160 o / 1:388fdd33fea0 change B
159 161 |/
160 162 o 0:a55a84d97a24 change A
161 163
162 164 $ C=10
163 165 $ E=11
164 166 $ H=12
165 167 $ I=13
166 168 $ J=14
167 169 #else
168 170 $ hg log --graph --template '{rev}:{node|short} {desc}\n'
169 171 o 9:d8d0e7974598 change J (child of 89de0da1d5da)
170 172 |
171 173 | o 8:4fc0b354461e change I
172 174 | |\
173 175 | | @ 7:1c45f3923443 change H (child of b53d63e816fb and 0e49f92ee6e9)
174 176 | | |\
175 177 | o | | 6:d75754455722 change E
176 178 |/| | |
177 179 o | | | 5:89de0da1d5da change C
178 180 | | | |
179 181 | | | o 4:0e49f92ee6e9 change G
180 182 | | | |
181 183 | | o | 3:b53d63e816fb change F
182 184 | | |/
183 185 | o / 2:c015ebfd2bfe change D
184 186 | |/
185 187 o / 1:388fdd33fea0 change B
186 188 |/
187 189 o 0:a55a84d97a24 change A
188 190
189 191 $ C=5
190 192 $ E=6
191 193 $ H=7
192 194 $ I=8
193 195 $ J=9
194 196 #endif
195 197
196 198 Change C is a root of the set being fixed, so all we fix is what has changed
197 199 since its parent. That parent, change B, is its baserev.
198 200
199 201 $ hg cat -r $C 'set:**'
200 202 aaaa
201 203 bbbb
202 204 CCCC
203 205
204 206 Change E is a merge with only one parent being fixed. Its baserevs are the
205 207 unfixed parent plus the baserevs of the other parent. This evaluates to changes
206 208 B and D. We now have to decide what it means to incrementally fix a merge
207 209 commit. We choose to fix anything that has changed versus any baserev. Only the
208 210 undisturbed content of the common ancestor, change A, is unfixed.
209 211
210 212 $ hg cat -r $E 'set:**'
211 213 aaaa
212 214 BBBB
213 215 CCCC
214 216 DDDD
215 217 EEEE
216 218
217 219 Change H is a merge with neither parent being fixed. This is essentially
218 220 equivalent to the previous case because there is still only one baserev for
219 221 each parent of the merge.
220 222
221 223 $ hg cat -r $H 'set:**'
222 224 aaaa
223 225 FFFF
224 226 GGGG
225 227 HHHH
226 228
227 229 Change I is a merge that has four baserevs; two from each parent. We handle
228 230 multiple baserevs in the same way regardless of how many came from each parent.
229 231 So, fixing change H will fix any files that were not exactly the same in each
230 232 baserev.
231 233
232 234 $ hg cat -r $I 'set:**'
233 235 aaaa
234 236 BBBB
235 237 CCCC
236 238 DDDD
237 239 EEEE
238 240 FFFF
239 241 GGGG
240 242 HHHH
241 243 IIII
242 244
243 245 Change J is a simple case with one baserev, but its baserev is not its parent,
244 246 change C. Its baserev is its grandparent, change B.
245 247
246 248 $ hg cat -r $J 'set:**'
247 249 aaaa
248 250 bbbb
249 251 CCCC
250 252 JJJJ
251 253
252 254 The working copy was dirty, so it is treated much like a revision. The baserevs
253 255 for the working copy are inherited from its parent, change H, because it is
254 256 also being fixed.
255 257
256 258 $ cat *
257 259 aaaa
258 260 FFFF
259 261 GGGG
260 262 HHHH
261 263 KKKK
262 264
263 265 Change A was never a baserev because none of its children were to be fixed.
264 266
265 267 $ cd ..
266 268
267 269
268 270 Test the --source option. We only do this with obsstore on to avoid duplicating
269 271 test code. We rely on the other tests to prove that obsolescence is not an
270 272 important factor here.
271 273
272 274 #if obsstore-on
273 275 $ hg init source-arg
274 276 $ cd source-arg
275 277 $ printf "aaaa\n" > a
276 278 $ hg commit -Am "change A"
277 279 adding a
278 280 $ printf "bbbb\n" > b
279 281 $ hg commit -Am "change B"
280 282 adding b
281 283 $ printf "cccc\n" > c
282 284 $ hg commit -Am "change C"
283 285 adding c
284 286 $ hg checkout 0
285 287 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
286 288 $ printf "dddd\n" > d
287 289 $ hg commit -Am "change D"
288 290 adding d
289 291 created new head
290 292 $ hg log --graph --template '{rev} {desc}\n'
291 293 @ 3 change D
292 294 |
293 295 | o 2 change C
294 296 | |
295 297 | o 1 change B
296 298 |/
297 299 o 0 change A
298 300
299 301
300 302 Test passing 'wdir()' to --source
301 303 $ printf "xxxx\n" > x
302 304 $ hg add x
303 305 $ hg fix -s 'wdir()'
304 306 $ cat *
305 307 aaaa
306 308 dddd
307 309 XXXX
308 310
309 311 Test passing '.' to --source
310 312 $ printf "xxxx\n" > x
311 313 $ hg fix -s .
312 314 $ hg log --graph --template '{rev} {desc}\n'
313 315 @ 4 change D
314 316 |
315 317 | o 2 change C
316 318 | |
317 319 | o 1 change B
318 320 |/
319 321 o 0 change A
320 322
321 323 $ cat *
322 324 aaaa
323 325 DDDD
324 326 XXXX
325 327 $ hg strip -qf 4
326 328 $ hg co -q 3
327 329
328 330 Test passing other branch to --source
329 331 $ printf "xxxx\n" > x
330 332 $ hg add x
331 333 $ hg fix -s 2
332 334 $ hg log --graph --template '{rev} {desc}\n'
333 335 o 4 change C
334 336 |
335 337 | @ 3 change D
336 338 | |
337 339 o | 1 change B
338 340 |/
339 341 o 0 change A
340 342
341 343 $ hg cat -r 4 b c
342 344 bbbb
343 345 CCCC
344 346 $ cat *
345 347 aaaa
346 348 dddd
347 349 xxxx
348 350 $ hg strip -qf 4
349 351
350 352 Test passing multiple revisions to --source
351 353 $ hg fix -s '2 + .'
352 354 $ hg log --graph --template '{rev} {desc}\n'
353 355 @ 5 change D
354 356 |
355 357 | o 4 change C
356 358 | |
357 359 | o 1 change B
358 360 |/
359 361 o 0 change A
360 362
361 363 $ hg cat -r 4 b c
362 364 bbbb
363 365 CCCC
364 366 $ cat *
365 367 aaaa
366 368 DDDD
367 369 XXXX
368 370
369 371 $ cd ..
370 372
371 373 $ hg init exclude-obsolete
372 374 $ cd exclude-obsolete
373 375 $ hg debugdrawdag <<'EOS'
374 376 > E C # prune: C
375 377 > | |
376 378 > D B # prune: B, D
377 379 > |/
378 380 > A
379 381 > EOS
380 382 1 new orphan changesets
381 383 $ hg log --graph --template '{rev} {desc}\n'
382 384 * 4 E
383 385 |
384 386 | x 3 C
385 387 | |
386 388 x | 2 D
387 389 | |
388 390 | x 1 B
389 391 |/
390 392 o 0 A
391 393
392 394 $ hg fix -s A
393 395 $ hg fix -s B
394 396 abort: no changesets specified
395 397 (use --source or --working-dir)
396 398 [255]
397 399 $ hg fix -s D
398 400 $ hg fix -s E
399 401 $ cd ..
400 402
401 403 #endif
402 404
403 405 The --all flag should fix anything that wouldn't cause a problem if you fixed
404 406 it, including the working copy. Obsolete revisions are not fixed because that
405 407 could cause divergence. Public revisions would cause an abort because they are
406 408 immutable. We can fix orphans because their successors are still just orphans
407 409 of the original obsolete parent. When obsolesence is off, we're just fixing and
408 410 replacing anything that isn't public.
409 411
410 412 $ hg init fixall
411 413 $ cd fixall
412 414 $ hg fix --all --working-dir
413 415 abort: cannot specify both --working-dir and --all
414 416 [10]
415 417
416 418 #if obsstore-on
417 419 $ printf "one\n" > foo.whole
418 420 $ hg commit -Aqm "first"
419 421 $ hg phase --public
420 422 $ hg tag --local root
421 423 $ printf "two\n" > foo.whole
422 424 $ hg commit -m "second"
423 425 $ printf "three\n" > foo.whole
424 426 $ hg commit -m "third" --secret
425 427 $ hg tag --local secret
426 428 $ hg checkout root
427 429 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 430 $ printf "four\n" > foo.whole
429 431 $ hg commit -m "fourth"
430 432 created new head
431 433 $ printf "five\n" > foo.whole
432 434 $ hg commit -m "fifth"
433 435 $ hg tag --local replaced
434 436 $ printf "six\n" > foo.whole
435 437 $ hg commit -m "sixth"
436 438 $ hg checkout replaced
437 439 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
438 440 $ printf "seven\n" > foo.whole
439 441 $ hg commit --amend
440 442 1 new orphan changesets
441 443 $ hg checkout secret
442 444 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
443 445 $ printf "uncommitted\n" > foo.whole
444 446
445 447 $ hg log --graph --template '{rev} {desc} {phase}\n'
446 448 o 6 fifth draft
447 449 |
448 450 | * 5 sixth draft
449 451 | |
450 452 | x 4 fifth draft
451 453 |/
452 454 o 3 fourth draft
453 455 |
454 456 | @ 2 third secret
455 457 | |
456 458 | o 1 second draft
457 459 |/
458 460 o 0 first public
459 461
460 462
461 463 $ hg fix --all
462 464
463 465 $ hg log --graph --template '{rev} {desc}\n' -r 'sort(all(), topo)' --hidden
464 466 o 11 fifth
465 467 |
466 468 o 9 fourth
467 469 |
468 470 | @ 8 third
469 471 | |
470 472 | o 7 second
471 473 |/
472 474 | * 10 sixth
473 475 | |
474 476 | | x 5 sixth
475 477 | |/
476 478 | x 4 fifth
477 479 | |
478 480 | | x 6 fifth
479 481 | |/
480 482 | x 3 fourth
481 483 |/
482 484 | x 2 third
483 485 | |
484 486 | x 1 second
485 487 |/
486 488 o 0 first
487 489
488 490
489 491 $ hg cat -r 7 foo.whole
490 492 TWO
491 493 $ hg cat -r 8 foo.whole
492 494 THREE
493 495 $ hg cat -r 9 foo.whole
494 496 FOUR
495 497 $ hg cat -r 10 foo.whole
496 498 SIX
497 499 $ hg cat -r 11 foo.whole
498 500 SEVEN
499 501 $ cat foo.whole
500 502 UNCOMMITTED
501 503 #else
502 504 $ printf "one\n" > foo.whole
503 505 $ hg commit -Aqm "first"
504 506 $ hg phase --public
505 507 $ hg tag --local root
506 508 $ printf "two\n" > foo.whole
507 509 $ hg commit -m "second"
508 510 $ printf "three\n" > foo.whole
509 511 $ hg commit -m "third" --secret
510 512 $ hg tag --local secret
511 513 $ hg checkout root
512 514 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
513 515 $ printf "four\n" > foo.whole
514 516 $ hg commit -m "fourth"
515 517 created new head
516 518 $ printf "uncommitted\n" > foo.whole
517 519
518 520 $ hg log --graph --template '{rev} {desc} {phase}\n'
519 521 @ 3 fourth draft
520 522 |
521 523 | o 2 third secret
522 524 | |
523 525 | o 1 second draft
524 526 |/
525 527 o 0 first public
526 528
527 529
528 530 $ hg fix --all
529 531 saved backup bundle to * (glob)
530 532
531 533 $ hg log --graph --template '{rev} {desc} {phase}\n'
532 534 @ 3 fourth draft
533 535 |
534 536 | o 2 third secret
535 537 | |
536 538 | o 1 second draft
537 539 |/
538 540 o 0 first public
539 541
540 542 $ hg cat -r 0 foo.whole
541 543 one
542 544 $ hg cat -r 1 foo.whole
543 545 TWO
544 546 $ hg cat -r 2 foo.whole
545 547 THREE
546 548 $ hg cat -r 3 foo.whole
547 549 FOUR
548 550 $ cat foo.whole
549 551 UNCOMMITTED
550 552 #endif
551 553
552 554 $ cd ..
553 555
@@ -1,1692 +1,1694 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 > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
11 > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
10 12 > lines = set()
11 13 > for arg in sys.argv[1:]:
12 14 > if arg == 'all':
13 > sys.stdout.write(sys.stdin.read().upper())
15 > stdout.write(stdin.read().upper())
14 16 > sys.exit(0)
15 17 > else:
16 18 > first, last = arg.split('-')
17 19 > lines.update(range(int(first), int(last) + 1))
18 > for i, line in enumerate(sys.stdin.readlines()):
20 > for i, line in enumerate(stdin.readlines()):
19 21 > if i + 1 in lines:
20 > sys.stdout.write(line.upper())
22 > stdout.write(line.upper())
21 23 > else:
22 > sys.stdout.write(line)
24 > stdout.write(line)
23 25 > EOF
24 26 $ TESTLINES="foo\nbar\nbaz\nqux\n"
25 27 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY
26 28 foo
27 29 bar
28 30 baz
29 31 qux
30 32 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY all
31 33 FOO
32 34 BAR
33 35 BAZ
34 36 QUX
35 37 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 1-1
36 38 FOO
37 39 bar
38 40 baz
39 41 qux
40 42 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 1-2
41 43 FOO
42 44 BAR
43 45 baz
44 46 qux
45 47 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 2-3
46 48 foo
47 49 BAR
48 50 BAZ
49 51 qux
50 52 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 2-2 4-4
51 53 foo
52 54 BAR
53 55 baz
54 56 QUX
55 57
56 58 Set up the config with two simple fixers: one that fixes specific line ranges,
57 59 and one that always fixes the whole file. They both "fix" files by converting
58 60 letters to uppercase. They use different file extensions, so each test case can
59 61 choose which behavior to use by naming files.
60 62
61 63 $ cat >> $HGRCPATH <<EOF
62 64 > [extensions]
63 65 > fix =
64 66 > [experimental]
65 67 > evolution.createmarkers=True
66 68 > evolution.allowunstable=True
67 69 > [fix]
68 70 > uppercase-whole-file:command="$PYTHON" $UPPERCASEPY all
69 71 > uppercase-whole-file:pattern=set:**.whole
70 72 > uppercase-changed-lines:command="$PYTHON" $UPPERCASEPY
71 73 > uppercase-changed-lines:linerange={first}-{last}
72 74 > uppercase-changed-lines:pattern=set:**.changed
73 75 > EOF
74 76
75 77 Help text for fix.
76 78
77 79 $ hg help fix
78 80 hg fix [OPTION]... [FILE]...
79 81
80 82 rewrite file content in changesets or working directory
81 83
82 84 Runs any configured tools to fix the content of files. Only affects files
83 85 with changes, unless file arguments are provided. Only affects changed
84 86 lines of files, unless the --whole flag is used. Some tools may always
85 87 affect the whole file regardless of --whole.
86 88
87 89 If --working-dir is used, files with uncommitted changes in the working
88 90 copy will be fixed. Note that no backup are made.
89 91
90 92 If revisions are specified with --source, those revisions and their
91 93 descendants will be checked, and they may be replaced with new revisions
92 94 that have fixed file content. By automatically including the descendants,
93 95 no merging, rebasing, or evolution will be required. If an ancestor of the
94 96 working copy is included, then the working copy itself will also be fixed,
95 97 and the working copy will be updated to the fixed parent.
96 98
97 99 When determining what lines of each file to fix at each revision, the
98 100 whole set of revisions being fixed is considered, so that fixes to earlier
99 101 revisions are not forgotten in later ones. The --base flag can be used to
100 102 override this default behavior, though it is not usually desirable to do
101 103 so.
102 104
103 105 (use 'hg help -e fix' to show help for the fix extension)
104 106
105 107 options ([+] can be repeated):
106 108
107 109 --all fix all non-public non-obsolete revisions
108 110 --base REV [+] revisions to diff against (overrides automatic selection,
109 111 and applies to every revision being fixed)
110 112 -s --source REV [+] fix the specified revisions and their descendants
111 113 -w --working-dir fix the working directory
112 114 --whole always fix every line of a file
113 115
114 116 (some details hidden, use --verbose to show complete help)
115 117
116 118 $ hg help -e fix
117 119 fix extension - rewrite file content in changesets or working copy
118 120 (EXPERIMENTAL)
119 121
120 122 Provides a command that runs configured tools on the contents of modified
121 123 files, writing back any fixes to the working copy or replacing changesets.
122 124
123 125 Here is an example configuration that causes 'hg fix' to apply automatic
124 126 formatting fixes to modified lines in C++ code:
125 127
126 128 [fix]
127 129 clang-format:command=clang-format --assume-filename={rootpath}
128 130 clang-format:linerange=--lines={first}:{last}
129 131 clang-format:pattern=set:**.cpp or **.hpp
130 132
131 133 The :command suboption forms the first part of the shell command that will be
132 134 used to fix a file. The content of the file is passed on standard input, and
133 135 the fixed file content is expected on standard output. Any output on standard
134 136 error will be displayed as a warning. If the exit status is not zero, the file
135 137 will not be affected. A placeholder warning is displayed if there is a non-
136 138 zero exit status but no standard error output. Some values may be substituted
137 139 into the command:
138 140
139 141 {rootpath} The path of the file being fixed, relative to the repo root
140 142 {basename} The name of the file being fixed, without the directory path
141 143
142 144 If the :linerange suboption is set, the tool will only be run if there are
143 145 changed lines in a file. The value of this suboption is appended to the shell
144 146 command once for every range of changed lines in the file. Some values may be
145 147 substituted into the command:
146 148
147 149 {first} The 1-based line number of the first line in the modified range
148 150 {last} The 1-based line number of the last line in the modified range
149 151
150 152 Deleted sections of a file will be ignored by :linerange, because there is no
151 153 corresponding line range in the version being fixed.
152 154
153 155 By default, tools that set :linerange will only be executed if there is at
154 156 least one changed line range. This is meant to prevent accidents like running
155 157 a code formatter in such a way that it unexpectedly reformats the whole file.
156 158 If such a tool needs to operate on unchanged files, it should set the
157 159 :skipclean suboption to false.
158 160
159 161 The :pattern suboption determines which files will be passed through each
160 162 configured tool. See 'hg help patterns' for possible values. However, all
161 163 patterns are relative to the repo root, even if that text says they are
162 164 relative to the current working directory. If there are file arguments to 'hg
163 165 fix', the intersection of these patterns is used.
164 166
165 167 There is also a configurable limit for the maximum size of file that will be
166 168 processed by 'hg fix':
167 169
168 170 [fix]
169 171 maxfilesize = 2MB
170 172
171 173 Normally, execution of configured tools will continue after a failure
172 174 (indicated by a non-zero exit status). It can also be configured to abort
173 175 after the first such failure, so that no files will be affected if any tool
174 176 fails. This abort will also cause 'hg fix' to exit with a non-zero status:
175 177
176 178 [fix]
177 179 failure = abort
178 180
179 181 When multiple tools are configured to affect a file, they execute in an order
180 182 defined by the :priority suboption. The priority suboption has a default value
181 183 of zero for each tool. Tools are executed in order of descending priority. The
182 184 execution order of tools with equal priority is unspecified. For example, you
183 185 could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers
184 186 in a text file by ensuring that 'sort' runs before 'head':
185 187
186 188 [fix]
187 189 sort:command = sort -n
188 190 head:command = head -n 10
189 191 sort:pattern = numbers.txt
190 192 head:pattern = numbers.txt
191 193 sort:priority = 2
192 194 head:priority = 1
193 195
194 196 To account for changes made by each tool, the line numbers used for
195 197 incremental formatting are recomputed before executing the next tool. So, each
196 198 tool may see different values for the arguments added by the :linerange
197 199 suboption.
198 200
199 201 Each fixer tool is allowed to return some metadata in addition to the fixed
200 202 file content. The metadata must be placed before the file content on stdout,
201 203 separated from the file content by a zero byte. The metadata is parsed as a
202 204 JSON value (so, it should be UTF-8 encoded and contain no zero bytes). A fixer
203 205 tool is expected to produce this metadata encoding if and only if the
204 206 :metadata suboption is true:
205 207
206 208 [fix]
207 209 tool:command = tool --prepend-json-metadata
208 210 tool:metadata = true
209 211
210 212 The metadata values are passed to hooks, which can be used to print summaries
211 213 or perform other post-fixing work. The supported hooks are:
212 214
213 215 "postfixfile"
214 216 Run once for each file in each revision where any fixer tools made changes
215 217 to the file content. Provides "$HG_REV" and "$HG_PATH" to identify the file,
216 218 and "$HG_METADATA" with a map of fixer names to metadata values from fixer
217 219 tools that affected the file. Fixer tools that didn't affect the file have a
218 220 value of None. Only fixer tools that executed are present in the metadata.
219 221
220 222 "postfix"
221 223 Run once after all files and revisions have been handled. Provides
222 224 "$HG_REPLACEMENTS" with information about what revisions were created and
223 225 made obsolete. Provides a boolean "$HG_WDIRWRITTEN" to indicate whether any
224 226 files in the working copy were updated. Provides a list "$HG_METADATA"
225 227 mapping fixer tool names to lists of metadata values returned from
226 228 executions that modified a file. This aggregates the same metadata
227 229 previously passed to the "postfixfile" hook.
228 230
229 231 Fixer tools are run in the repository's root directory. This allows them to
230 232 read configuration files from the working copy, or even write to the working
231 233 copy. The working copy is not updated to match the revision being fixed. In
232 234 fact, several revisions may be fixed in parallel. Writes to the working copy
233 235 are not amended into the revision being fixed; fixer tools should always write
234 236 fixed file content back to stdout as documented above.
235 237
236 238 list of commands:
237 239
238 240 fix rewrite file content in changesets or working directory
239 241
240 242 (use 'hg help -v -e fix' to show built-in aliases and global options)
241 243
242 244 There is no default behavior in the absence of --rev and --working-dir.
243 245
244 246 $ hg init badusage
245 247 $ cd badusage
246 248
247 249 $ hg fix
248 250 abort: no changesets specified
249 251 (use --source or --working-dir)
250 252 [255]
251 253 $ hg fix --whole
252 254 abort: no changesets specified
253 255 (use --source or --working-dir)
254 256 [255]
255 257 $ hg fix --base 0
256 258 abort: no changesets specified
257 259 (use --source or --working-dir)
258 260 [255]
259 261
260 262 Fixing a public revision isn't allowed. It should abort early enough that
261 263 nothing happens, even to the working directory.
262 264
263 265 $ printf "hello\n" > hello.whole
264 266 $ hg commit -Aqm "hello"
265 267 $ hg phase -r 0 --public
266 268 $ hg fix -r 0
267 269 abort: cannot fix public changesets
268 270 (see 'hg help phases' for details)
269 271 [10]
270 272 $ hg fix -r 0 --working-dir
271 273 abort: cannot fix public changesets
272 274 (see 'hg help phases' for details)
273 275 [10]
274 276 $ hg cat -r tip hello.whole
275 277 hello
276 278 $ cat hello.whole
277 279 hello
278 280
279 281 $ cd ..
280 282
281 283 Fixing a clean working directory should do nothing. Even the --whole flag
282 284 shouldn't cause any clean files to be fixed. Specifying a clean file explicitly
283 285 should only fix it if the fixer always fixes the whole file. The combination of
284 286 an explicit filename and --whole should format the entire file regardless.
285 287
286 288 $ hg init fixcleanwdir
287 289 $ cd fixcleanwdir
288 290
289 291 $ printf "hello\n" > hello.changed
290 292 $ printf "world\n" > hello.whole
291 293 $ hg commit -Aqm "foo"
292 294 $ hg fix --working-dir
293 295 $ hg diff
294 296 $ hg fix --working-dir --whole
295 297 $ hg diff
296 298 $ hg fix --working-dir *
297 299 $ cat *
298 300 hello
299 301 WORLD
300 302 $ hg revert --all --no-backup
301 303 reverting hello.whole
302 304 $ hg fix --working-dir * --whole
303 305 $ cat *
304 306 HELLO
305 307 WORLD
306 308
307 309 The same ideas apply to fixing a revision, so we create a revision that doesn't
308 310 modify either of the files in question and try fixing it. This also tests that
309 311 we ignore a file that doesn't match any configured fixer.
310 312
311 313 $ hg revert --all --no-backup
312 314 reverting hello.changed
313 315 reverting hello.whole
314 316 $ printf "unimportant\n" > some.file
315 317 $ hg commit -Aqm "some other file"
316 318
317 319 $ hg fix -r .
318 320 $ hg cat -r tip *
319 321 hello
320 322 world
321 323 unimportant
322 324 $ hg fix -r . --whole
323 325 $ hg cat -r tip *
324 326 hello
325 327 world
326 328 unimportant
327 329 $ hg fix -r . *
328 330 $ hg cat -r tip *
329 331 hello
330 332 WORLD
331 333 unimportant
332 334 $ hg fix -r . * --whole --config experimental.evolution.allowdivergence=true
333 335 2 new content-divergent changesets
334 336 $ hg cat -r tip *
335 337 HELLO
336 338 WORLD
337 339 unimportant
338 340
339 341 $ cd ..
340 342
341 343 Fixing the working directory should still work if there are no revisions.
342 344
343 345 $ hg init norevisions
344 346 $ cd norevisions
345 347
346 348 $ printf "something\n" > something.whole
347 349 $ hg add
348 350 adding something.whole
349 351 $ hg fix --working-dir
350 352 $ cat something.whole
351 353 SOMETHING
352 354
353 355 $ cd ..
354 356
355 357 Test the effect of fixing the working directory for each possible status, with
356 358 and without providing explicit file arguments.
357 359
358 360 $ hg init implicitlyfixstatus
359 361 $ cd implicitlyfixstatus
360 362
361 363 $ printf "modified\n" > modified.whole
362 364 $ printf "removed\n" > removed.whole
363 365 $ printf "deleted\n" > deleted.whole
364 366 $ printf "clean\n" > clean.whole
365 367 $ printf "ignored.whole" > .hgignore
366 368 $ hg commit -Aqm "stuff"
367 369
368 370 $ printf "modified!!!\n" > modified.whole
369 371 $ printf "unknown\n" > unknown.whole
370 372 $ printf "ignored\n" > ignored.whole
371 373 $ printf "added\n" > added.whole
372 374 $ hg add added.whole
373 375 $ hg remove removed.whole
374 376 $ rm deleted.whole
375 377
376 378 $ hg status --all
377 379 M modified.whole
378 380 A added.whole
379 381 R removed.whole
380 382 ! deleted.whole
381 383 ? unknown.whole
382 384 I ignored.whole
383 385 C .hgignore
384 386 C clean.whole
385 387
386 388 $ hg fix --working-dir
387 389
388 390 $ hg status --all
389 391 M modified.whole
390 392 A added.whole
391 393 R removed.whole
392 394 ! deleted.whole
393 395 ? unknown.whole
394 396 I ignored.whole
395 397 C .hgignore
396 398 C clean.whole
397 399
398 400 $ cat *.whole
399 401 ADDED
400 402 clean
401 403 ignored
402 404 MODIFIED!!!
403 405 unknown
404 406
405 407 $ printf "modified!!!\n" > modified.whole
406 408 $ printf "added\n" > added.whole
407 409
408 410 Listing the files explicitly causes untracked files to also be fixed, but
409 411 ignored files are still unaffected.
410 412
411 413 $ hg fix --working-dir *.whole
412 414
413 415 $ hg status --all
414 416 M clean.whole
415 417 M modified.whole
416 418 A added.whole
417 419 R removed.whole
418 420 ! deleted.whole
419 421 ? unknown.whole
420 422 I ignored.whole
421 423 C .hgignore
422 424
423 425 $ cat *.whole
424 426 ADDED
425 427 CLEAN
426 428 ignored
427 429 MODIFIED!!!
428 430 UNKNOWN
429 431
430 432 $ cd ..
431 433
432 434 Test that incremental fixing works on files with additions, deletions, and
433 435 changes in multiple line ranges. Note that deletions do not generally cause
434 436 neighboring lines to be fixed, so we don't return a line range for purely
435 437 deleted sections. In the future we should support a :deletion config that
436 438 allows fixers to know where deletions are located.
437 439
438 440 $ hg init incrementalfixedlines
439 441 $ cd incrementalfixedlines
440 442
441 443 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.txt
442 444 $ hg commit -Aqm "foo"
443 445 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.txt
444 446
445 447 $ hg --config "fix.fail:command=echo" \
446 448 > --config "fix.fail:linerange={first}:{last}" \
447 449 > --config "fix.fail:pattern=foo.txt" \
448 450 > fix --working-dir
449 451 $ cat foo.txt
450 452 1:1 4:6 8:8
451 453
452 454 $ cd ..
453 455
454 456 Test that --whole fixes all lines regardless of the diffs present.
455 457
456 458 $ hg init wholeignoresdiffs
457 459 $ cd wholeignoresdiffs
458 460
459 461 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.changed
460 462 $ hg commit -Aqm "foo"
461 463 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.changed
462 464
463 465 $ hg fix --working-dir
464 466 $ cat foo.changed
465 467 ZZ
466 468 a
467 469 c
468 470 DD
469 471 EE
470 472 FF
471 473 f
472 474 GG
473 475
474 476 $ hg fix --working-dir --whole
475 477 $ cat foo.changed
476 478 ZZ
477 479 A
478 480 C
479 481 DD
480 482 EE
481 483 FF
482 484 F
483 485 GG
484 486
485 487 $ cd ..
486 488
487 489 We should do nothing with symlinks, and their targets should be unaffected. Any
488 490 other behavior would be more complicated to implement and harder to document.
489 491
490 492 #if symlink
491 493 $ hg init dontmesswithsymlinks
492 494 $ cd dontmesswithsymlinks
493 495
494 496 $ printf "hello\n" > hello.whole
495 497 $ ln -s hello.whole hellolink
496 498 $ hg add
497 499 adding hello.whole
498 500 adding hellolink
499 501 $ hg fix --working-dir hellolink
500 502 $ hg status
501 503 A hello.whole
502 504 A hellolink
503 505
504 506 $ cd ..
505 507 #endif
506 508
507 509 We should allow fixers to run on binary files, even though this doesn't sound
508 510 like a common use case. There's not much benefit to disallowing it, and users
509 511 can add "and not binary()" to their filesets if needed. The Mercurial
510 512 philosophy is generally to not handle binary files specially anyway.
511 513
512 514 $ hg init cantouchbinaryfiles
513 515 $ cd cantouchbinaryfiles
514 516
515 517 $ printf "hello\0\n" > hello.whole
516 518 $ hg add
517 519 adding hello.whole
518 520 $ hg fix --working-dir 'set:binary()'
519 521 $ cat hello.whole
520 522 HELLO\x00 (esc)
521 523
522 524 $ cd ..
523 525
524 526 We have a config for the maximum size of file we will attempt to fix. This can
525 527 be helpful to avoid running unsuspecting fixer tools on huge inputs, which
526 528 could happen by accident without a well considered configuration. A more
527 529 precise configuration could use the size() fileset function if one global limit
528 530 is undesired.
529 531
530 532 $ hg init maxfilesize
531 533 $ cd maxfilesize
532 534
533 535 $ printf "this file is huge\n" > hello.whole
534 536 $ hg add
535 537 adding hello.whole
536 538 $ hg --config fix.maxfilesize=10 fix --working-dir
537 539 ignoring file larger than 10 bytes: hello.whole
538 540 $ cat hello.whole
539 541 this file is huge
540 542
541 543 $ cd ..
542 544
543 545 If we specify a file to fix, other files should be left alone, even if they
544 546 have changes.
545 547
546 548 $ hg init fixonlywhatitellyouto
547 549 $ cd fixonlywhatitellyouto
548 550
549 551 $ printf "fix me!\n" > fixme.whole
550 552 $ printf "not me.\n" > notme.whole
551 553 $ hg add
552 554 adding fixme.whole
553 555 adding notme.whole
554 556 $ hg fix --working-dir fixme.whole
555 557 $ cat *.whole
556 558 FIX ME!
557 559 not me.
558 560
559 561 $ cd ..
560 562
561 563 If we try to fix a missing file, we still fix other files.
562 564
563 565 $ hg init fixmissingfile
564 566 $ cd fixmissingfile
565 567
566 568 $ printf "fix me!\n" > foo.whole
567 569 $ hg add
568 570 adding foo.whole
569 571 $ hg fix --working-dir foo.whole bar.whole
570 572 bar.whole: $ENOENT$
571 573 $ cat *.whole
572 574 FIX ME!
573 575
574 576 $ cd ..
575 577
576 578 Specifying a directory name should fix all its files and subdirectories.
577 579
578 580 $ hg init fixdirectory
579 581 $ cd fixdirectory
580 582
581 583 $ mkdir -p dir1/dir2
582 584 $ printf "foo\n" > foo.whole
583 585 $ printf "bar\n" > dir1/bar.whole
584 586 $ printf "baz\n" > dir1/dir2/baz.whole
585 587 $ hg add
586 588 adding dir1/bar.whole
587 589 adding dir1/dir2/baz.whole
588 590 adding foo.whole
589 591 $ hg fix --working-dir dir1
590 592 $ cat foo.whole dir1/bar.whole dir1/dir2/baz.whole
591 593 foo
592 594 BAR
593 595 BAZ
594 596
595 597 $ cd ..
596 598
597 599 Fixing a file in the working directory that needs no fixes should not actually
598 600 write back to the file, so for example the mtime shouldn't change.
599 601
600 602 $ hg init donttouchunfixedfiles
601 603 $ cd donttouchunfixedfiles
602 604
603 605 $ printf "NO FIX NEEDED\n" > foo.whole
604 606 $ hg add
605 607 adding foo.whole
606 608 $ cp -p foo.whole foo.whole.orig
607 609 $ cp -p foo.whole.orig foo.whole
608 610 $ sleep 2 # mtime has a resolution of one or two seconds.
609 611 $ hg fix --working-dir
610 612 $ f foo.whole.orig --newer foo.whole
611 613 foo.whole.orig: newer than foo.whole
612 614
613 615 $ cd ..
614 616
615 617 When a fixer prints to stderr, we don't assume that it has failed. We show the
616 618 error messages to the user, and we still let the fixer affect the file it was
617 619 fixing if its exit code is zero. Some code formatters might emit error messages
618 620 on stderr and nothing on stdout, which would cause us the clear the file,
619 621 except that they also exit with a non-zero code. We show the user which fixer
620 622 emitted the stderr, and which revision, but we assume that the fixer will print
621 623 the filename if it is relevant (since the issue may be non-specific). There is
622 624 also a config to abort (without affecting any files whatsoever) if we see any
623 625 tool with a non-zero exit status.
624 626
625 627 $ hg init showstderr
626 628 $ cd showstderr
627 629
628 630 $ printf "hello\n" > hello.txt
629 631 $ hg add
630 632 adding hello.txt
631 633 $ cat > $TESTTMP/work.sh <<'EOF'
632 634 > printf 'HELLO\n'
633 635 > printf "$@: some\nerror that didn't stop the tool" >&2
634 636 > exit 0 # success despite the stderr output
635 637 > EOF
636 638 $ hg --config "fix.work:command=sh $TESTTMP/work.sh {rootpath}" \
637 639 > --config "fix.work:pattern=hello.txt" \
638 640 > fix --working-dir
639 641 [wdir] work: hello.txt: some
640 642 [wdir] work: error that didn't stop the tool
641 643 $ cat hello.txt
642 644 HELLO
643 645
644 646 $ printf "goodbye\n" > hello.txt
645 647 $ printf "foo\n" > foo.whole
646 648 $ hg add
647 649 adding foo.whole
648 650 $ cat > $TESTTMP/fail.sh <<'EOF'
649 651 > printf 'GOODBYE\n'
650 652 > printf "$@: some\nerror that did stop the tool\n" >&2
651 653 > exit 42 # success despite the stdout output
652 654 > EOF
653 655 $ hg --config "fix.fail:command=sh $TESTTMP/fail.sh {rootpath}" \
654 656 > --config "fix.fail:pattern=hello.txt" \
655 657 > --config "fix.failure=abort" \
656 658 > fix --working-dir
657 659 [wdir] fail: hello.txt: some
658 660 [wdir] fail: error that did stop the tool
659 661 abort: no fixes will be applied
660 662 (use --config fix.failure=continue to apply any successful fixes anyway)
661 663 [255]
662 664 $ cat hello.txt
663 665 goodbye
664 666 $ cat foo.whole
665 667 foo
666 668
667 669 $ hg --config "fix.fail:command=sh $TESTTMP/fail.sh {rootpath}" \
668 670 > --config "fix.fail:pattern=hello.txt" \
669 671 > fix --working-dir
670 672 [wdir] fail: hello.txt: some
671 673 [wdir] fail: error that did stop the tool
672 674 $ cat hello.txt
673 675 goodbye
674 676 $ cat foo.whole
675 677 FOO
676 678
677 679 $ hg --config "fix.fail:command=exit 42" \
678 680 > --config "fix.fail:pattern=hello.txt" \
679 681 > fix --working-dir
680 682 [wdir] fail: exited with status 42
681 683
682 684 $ cd ..
683 685
684 686 Fixing the working directory and its parent revision at the same time should
685 687 check out the replacement revision for the parent. This prevents any new
686 688 uncommitted changes from appearing. We test this for a clean working directory
687 689 and a dirty one. In both cases, all lines/files changed since the grandparent
688 690 will be fixed. The grandparent is the "baserev" for both the parent and the
689 691 working copy.
690 692
691 693 $ hg init fixdotandcleanwdir
692 694 $ cd fixdotandcleanwdir
693 695
694 696 $ printf "hello\n" > hello.whole
695 697 $ printf "world\n" > world.whole
696 698 $ hg commit -Aqm "the parent commit"
697 699
698 700 $ hg parents --template '{rev} {desc}\n'
699 701 0 the parent commit
700 702 $ hg fix --working-dir -r .
701 703 $ hg parents --template '{rev} {desc}\n'
702 704 1 the parent commit
703 705 $ hg cat -r . *.whole
704 706 HELLO
705 707 WORLD
706 708 $ cat *.whole
707 709 HELLO
708 710 WORLD
709 711 $ hg status
710 712
711 713 $ cd ..
712 714
713 715 Same test with a dirty working copy.
714 716
715 717 $ hg init fixdotanddirtywdir
716 718 $ cd fixdotanddirtywdir
717 719
718 720 $ printf "hello\n" > hello.whole
719 721 $ printf "world\n" > world.whole
720 722 $ hg commit -Aqm "the parent commit"
721 723
722 724 $ printf "hello,\n" > hello.whole
723 725 $ printf "world!\n" > world.whole
724 726
725 727 $ hg parents --template '{rev} {desc}\n'
726 728 0 the parent commit
727 729 $ hg fix --working-dir -r .
728 730 $ hg parents --template '{rev} {desc}\n'
729 731 1 the parent commit
730 732 $ hg cat -r . *.whole
731 733 HELLO
732 734 WORLD
733 735 $ cat *.whole
734 736 HELLO,
735 737 WORLD!
736 738 $ hg status
737 739 M hello.whole
738 740 M world.whole
739 741
740 742 $ cd ..
741 743
742 744 When we have a chain of commits that change mutually exclusive lines of code,
743 745 we should be able to do incremental fixing that causes each commit in the chain
744 746 to include fixes made to the previous commits. This prevents children from
745 747 backing out the fixes made in their parents. A dirty working directory is
746 748 conceptually similar to another commit in the chain.
747 749
748 750 $ hg init incrementallyfixchain
749 751 $ cd incrementallyfixchain
750 752
751 753 $ cat > file.changed <<EOF
752 754 > first
753 755 > second
754 756 > third
755 757 > fourth
756 758 > fifth
757 759 > EOF
758 760 $ hg commit -Aqm "the common ancestor (the baserev)"
759 761 $ cat > file.changed <<EOF
760 762 > first (changed)
761 763 > second
762 764 > third
763 765 > fourth
764 766 > fifth
765 767 > EOF
766 768 $ hg commit -Aqm "the first commit to fix"
767 769 $ cat > file.changed <<EOF
768 770 > first (changed)
769 771 > second
770 772 > third (changed)
771 773 > fourth
772 774 > fifth
773 775 > EOF
774 776 $ hg commit -Aqm "the second commit to fix"
775 777 $ cat > file.changed <<EOF
776 778 > first (changed)
777 779 > second
778 780 > third (changed)
779 781 > fourth
780 782 > fifth (changed)
781 783 > EOF
782 784
783 785 $ hg fix -r . -r '.^' --working-dir
784 786
785 787 $ hg parents --template '{rev}\n'
786 788 4
787 789 $ hg cat -r '.^^' file.changed
788 790 first
789 791 second
790 792 third
791 793 fourth
792 794 fifth
793 795 $ hg cat -r '.^' file.changed
794 796 FIRST (CHANGED)
795 797 second
796 798 third
797 799 fourth
798 800 fifth
799 801 $ hg cat -r . file.changed
800 802 FIRST (CHANGED)
801 803 second
802 804 THIRD (CHANGED)
803 805 fourth
804 806 fifth
805 807 $ cat file.changed
806 808 FIRST (CHANGED)
807 809 second
808 810 THIRD (CHANGED)
809 811 fourth
810 812 FIFTH (CHANGED)
811 813
812 814 $ cd ..
813 815
814 816 If we incrementally fix a merge commit, we should fix any lines that changed
815 817 versus either parent. You could imagine only fixing the intersection or some
816 818 other subset, but this is necessary if either parent is being fixed. It
817 819 prevents us from forgetting fixes made in either parent.
818 820
819 821 $ hg init incrementallyfixmergecommit
820 822 $ cd incrementallyfixmergecommit
821 823
822 824 $ printf "a\nb\nc\n" > file.changed
823 825 $ hg commit -Aqm "ancestor"
824 826
825 827 $ printf "aa\nb\nc\n" > file.changed
826 828 $ hg commit -m "change a"
827 829
828 830 $ hg checkout '.^'
829 831 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
830 832 $ printf "a\nb\ncc\n" > file.changed
831 833 $ hg commit -m "change c"
832 834 created new head
833 835
834 836 $ hg merge
835 837 merging file.changed
836 838 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
837 839 (branch merge, don't forget to commit)
838 840 $ hg commit -m "merge"
839 841 $ hg cat -r . file.changed
840 842 aa
841 843 b
842 844 cc
843 845
844 846 $ hg fix -r . --working-dir
845 847 $ hg cat -r . file.changed
846 848 AA
847 849 b
848 850 CC
849 851
850 852 $ cd ..
851 853
852 854 Abort fixing revisions if there is an unfinished operation. We don't want to
853 855 make things worse by editing files or stripping/obsoleting things. Also abort
854 856 fixing the working directory if there are unresolved merge conflicts.
855 857
856 858 $ hg init abortunresolved
857 859 $ cd abortunresolved
858 860
859 861 $ echo "foo1" > foo.whole
860 862 $ hg commit -Aqm "foo 1"
861 863
862 864 $ hg update null
863 865 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
864 866 $ echo "foo2" > foo.whole
865 867 $ hg commit -Aqm "foo 2"
866 868
867 869 $ hg --config extensions.rebase= rebase -r 1 -d 0
868 870 rebasing 1:c3b6dc0e177a tip "foo 2"
869 871 merging foo.whole
870 872 warning: conflicts while merging foo.whole! (edit, then use 'hg resolve --mark')
871 873 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
872 874 [240]
873 875
874 876 $ hg --config extensions.rebase= fix --working-dir
875 877 abort: unresolved conflicts
876 878 (use 'hg resolve')
877 879 [255]
878 880
879 881 $ hg --config extensions.rebase= fix -r .
880 882 abort: rebase in progress
881 883 (use 'hg rebase --continue', 'hg rebase --abort', or 'hg rebase --stop')
882 884 [20]
883 885
884 886 $ cd ..
885 887
886 888 When fixing a file that was renamed, we should diff against the source of the
887 889 rename for incremental fixing and we should correctly reproduce the rename in
888 890 the replacement revision.
889 891
890 892 $ hg init fixrenamecommit
891 893 $ cd fixrenamecommit
892 894
893 895 $ printf "a\nb\nc\n" > source.changed
894 896 $ hg commit -Aqm "source revision"
895 897 $ hg move source.changed dest.changed
896 898 $ printf "a\nb\ncc\n" > dest.changed
897 899 $ hg commit -m "dest revision"
898 900
899 901 $ hg fix -r .
900 902 $ hg log -r tip --copies --template "{file_copies}\n"
901 903 dest.changed (source.changed)
902 904 $ hg cat -r tip dest.changed
903 905 a
904 906 b
905 907 CC
906 908
907 909 $ cd ..
908 910
909 911 When fixing revisions that remove files we must ensure that the replacement
910 912 actually removes the file, whereas it could accidentally leave it unchanged or
911 913 write an empty string to it.
912 914
913 915 $ hg init fixremovedfile
914 916 $ cd fixremovedfile
915 917
916 918 $ printf "foo\n" > foo.whole
917 919 $ printf "bar\n" > bar.whole
918 920 $ hg commit -Aqm "add files"
919 921 $ hg remove bar.whole
920 922 $ hg commit -m "remove file"
921 923 $ hg status --change .
922 924 R bar.whole
923 925 $ hg fix -r . foo.whole
924 926 $ hg status --change tip
925 927 M foo.whole
926 928 R bar.whole
927 929
928 930 $ cd ..
929 931
930 932 If fixing a revision finds no fixes to make, no replacement revision should be
931 933 created.
932 934
933 935 $ hg init nofixesneeded
934 936 $ cd nofixesneeded
935 937
936 938 $ printf "FOO\n" > foo.whole
937 939 $ hg commit -Aqm "add file"
938 940 $ hg log --template '{rev}\n'
939 941 0
940 942 $ hg fix -r .
941 943 $ hg log --template '{rev}\n'
942 944 0
943 945
944 946 $ cd ..
945 947
946 948 If fixing a commit reverts all the changes in the commit, we replace it with a
947 949 commit that changes no files.
948 950
949 951 $ hg init nochangesleft
950 952 $ cd nochangesleft
951 953
952 954 $ printf "FOO\n" > foo.whole
953 955 $ hg commit -Aqm "add file"
954 956 $ printf "foo\n" > foo.whole
955 957 $ hg commit -m "edit file"
956 958 $ hg status --change .
957 959 M foo.whole
958 960 $ hg fix -r .
959 961 $ hg status --change tip
960 962
961 963 $ cd ..
962 964
963 965 If we fix a parent and child revision together, the child revision must be
964 966 replaced if the parent is replaced, even if the diffs of the child needed no
965 967 fixes. However, we're free to not replace revisions that need no fixes and have
966 968 no ancestors that are replaced.
967 969
968 970 $ hg init mustreplacechild
969 971 $ cd mustreplacechild
970 972
971 973 $ printf "FOO\n" > foo.whole
972 974 $ hg commit -Aqm "add foo"
973 975 $ printf "foo\n" > foo.whole
974 976 $ hg commit -m "edit foo"
975 977 $ printf "BAR\n" > bar.whole
976 978 $ hg commit -Aqm "add bar"
977 979
978 980 $ hg log --graph --template '{rev} {files}'
979 981 @ 2 bar.whole
980 982 |
981 983 o 1 foo.whole
982 984 |
983 985 o 0 foo.whole
984 986
985 987 $ hg fix -r 0:2
986 988 $ hg log --graph --template '{rev} {files}'
987 989 o 4 bar.whole
988 990 |
989 991 o 3
990 992 |
991 993 | @ 2 bar.whole
992 994 | |
993 995 | x 1 foo.whole
994 996 |/
995 997 o 0 foo.whole
996 998
997 999
998 1000 $ cd ..
999 1001
1000 1002 It's also possible that the child needs absolutely no changes, but we still
1001 1003 need to replace it to update its parent. If we skipped replacing the child
1002 1004 because it had no file content changes, it would become an orphan for no good
1003 1005 reason.
1004 1006
1005 1007 $ hg init mustreplacechildevenifnop
1006 1008 $ cd mustreplacechildevenifnop
1007 1009
1008 1010 $ printf "Foo\n" > foo.whole
1009 1011 $ hg commit -Aqm "add a bad foo"
1010 1012 $ printf "FOO\n" > foo.whole
1011 1013 $ hg commit -m "add a good foo"
1012 1014 $ hg fix -r . -r '.^'
1013 1015 $ hg log --graph --template '{rev} {desc}'
1014 1016 o 3 add a good foo
1015 1017 |
1016 1018 o 2 add a bad foo
1017 1019
1018 1020 @ 1 add a good foo
1019 1021 |
1020 1022 x 0 add a bad foo
1021 1023
1022 1024
1023 1025 $ cd ..
1024 1026
1025 1027 Similar to the case above, the child revision may become empty as a result of
1026 1028 fixing its parent. We should still create an empty replacement child.
1027 1029 TODO: determine how this should interact with ui.allowemptycommit given that
1028 1030 the empty replacement could have children.
1029 1031
1030 1032 $ hg init mustreplacechildevenifempty
1031 1033 $ cd mustreplacechildevenifempty
1032 1034
1033 1035 $ printf "foo\n" > foo.whole
1034 1036 $ hg commit -Aqm "add foo"
1035 1037 $ printf "Foo\n" > foo.whole
1036 1038 $ hg commit -m "edit foo"
1037 1039 $ hg fix -r . -r '.^'
1038 1040 $ hg log --graph --template '{rev} {desc}\n' --stat
1039 1041 o 3 edit foo
1040 1042 |
1041 1043 o 2 add foo
1042 1044 foo.whole | 1 +
1043 1045 1 files changed, 1 insertions(+), 0 deletions(-)
1044 1046
1045 1047 @ 1 edit foo
1046 1048 | foo.whole | 2 +-
1047 1049 | 1 files changed, 1 insertions(+), 1 deletions(-)
1048 1050 |
1049 1051 x 0 add foo
1050 1052 foo.whole | 1 +
1051 1053 1 files changed, 1 insertions(+), 0 deletions(-)
1052 1054
1053 1055
1054 1056 $ cd ..
1055 1057
1056 1058 Fixing a secret commit should replace it with another secret commit.
1057 1059
1058 1060 $ hg init fixsecretcommit
1059 1061 $ cd fixsecretcommit
1060 1062
1061 1063 $ printf "foo\n" > foo.whole
1062 1064 $ hg commit -Aqm "add foo" --secret
1063 1065 $ hg fix -r .
1064 1066 $ hg log --template '{rev} {phase}\n'
1065 1067 1 secret
1066 1068 0 secret
1067 1069
1068 1070 $ cd ..
1069 1071
1070 1072 We should also preserve phase when fixing a draft commit while the user has
1071 1073 their default set to secret.
1072 1074
1073 1075 $ hg init respectphasesnewcommit
1074 1076 $ cd respectphasesnewcommit
1075 1077
1076 1078 $ printf "foo\n" > foo.whole
1077 1079 $ hg commit -Aqm "add foo"
1078 1080 $ hg --config phases.newcommit=secret fix -r .
1079 1081 $ hg log --template '{rev} {phase}\n'
1080 1082 1 draft
1081 1083 0 draft
1082 1084
1083 1085 $ cd ..
1084 1086
1085 1087 Debug output should show what fixer commands are being subprocessed, which is
1086 1088 useful for anyone trying to set up a new config.
1087 1089
1088 1090 $ hg init debugoutput
1089 1091 $ cd debugoutput
1090 1092
1091 1093 $ printf "foo\nbar\nbaz\n" > foo.changed
1092 1094 $ hg commit -Aqm "foo"
1093 1095 $ printf "Foo\nbar\nBaz\n" > foo.changed
1094 1096 $ hg --debug fix --working-dir
1095 1097 subprocess: * $TESTTMP/uppercase.py 1-1 3-3 (glob)
1096 1098
1097 1099 $ cd ..
1098 1100
1099 1101 Fixing an obsolete revision can cause divergence, so we abort unless the user
1100 1102 configures to allow it. This is not yet smart enough to know whether there is a
1101 1103 successor, but even then it is not likely intentional or idiomatic to fix an
1102 1104 obsolete revision.
1103 1105
1104 1106 $ hg init abortobsoleterev
1105 1107 $ cd abortobsoleterev
1106 1108
1107 1109 $ printf "foo\n" > foo.changed
1108 1110 $ hg commit -Aqm "foo"
1109 1111 $ hg ci --amend -m rewritten
1110 1112 $ hg --hidden fix -r 0
1111 1113 abort: fixing obsolete revision could cause divergence
1112 1114 [255]
1113 1115
1114 1116 $ hg --hidden fix -r 0 --config experimental.evolution.allowdivergence=true
1115 1117 2 new content-divergent changesets
1116 1118 $ hg cat -r tip foo.changed
1117 1119 FOO
1118 1120
1119 1121 $ cd ..
1120 1122
1121 1123 Test all of the available substitution values for fixer commands.
1122 1124
1123 1125 $ hg init substitution
1124 1126 $ cd substitution
1125 1127
1126 1128 $ mkdir foo
1127 1129 $ printf "hello\ngoodbye\n" > foo/bar
1128 1130 $ hg add
1129 1131 adding foo/bar
1130 1132 $ hg --config "fix.fail:command=printf '%s\n' '{rootpath}' '{basename}'" \
1131 1133 > --config "fix.fail:linerange='{first}' '{last}'" \
1132 1134 > --config "fix.fail:pattern=foo/bar" \
1133 1135 > fix --working-dir
1134 1136 $ cat foo/bar
1135 1137 foo/bar
1136 1138 bar
1137 1139 1
1138 1140 2
1139 1141
1140 1142 $ cd ..
1141 1143
1142 1144 The --base flag should allow picking the revisions to diff against for changed
1143 1145 files and incremental line formatting.
1144 1146
1145 1147 $ hg init baseflag
1146 1148 $ cd baseflag
1147 1149
1148 1150 $ printf "one\ntwo\n" > foo.changed
1149 1151 $ printf "bar\n" > bar.changed
1150 1152 $ hg commit -Aqm "first"
1151 1153 $ printf "one\nTwo\n" > foo.changed
1152 1154 $ hg commit -m "second"
1153 1155 $ hg fix -w --base .
1154 1156 $ hg status
1155 1157 $ hg fix -w --base null
1156 1158 $ cat foo.changed
1157 1159 ONE
1158 1160 TWO
1159 1161 $ cat bar.changed
1160 1162 BAR
1161 1163
1162 1164 $ cd ..
1163 1165
1164 1166 If the user asks to fix the parent of another commit, they are asking to create
1165 1167 an orphan. We must respect experimental.evolution.allowunstable.
1166 1168
1167 1169 $ hg init allowunstable
1168 1170 $ cd allowunstable
1169 1171
1170 1172 $ printf "one\n" > foo.whole
1171 1173 $ hg commit -Aqm "first"
1172 1174 $ printf "two\n" > foo.whole
1173 1175 $ hg commit -m "second"
1174 1176 $ hg --config experimental.evolution.allowunstable=False fix -r '.^'
1175 1177 abort: cannot fix changeset with children
1176 1178 [10]
1177 1179 $ hg fix -r '.^'
1178 1180 1 new orphan changesets
1179 1181 $ hg cat -r 2 foo.whole
1180 1182 ONE
1181 1183
1182 1184 $ cd ..
1183 1185
1184 1186 The --base flag affects the set of files being fixed. So while the --whole flag
1185 1187 makes the base irrelevant for changed line ranges, it still changes the
1186 1188 meaning and effect of the command. In this example, no files or lines are fixed
1187 1189 until we specify the base, but then we do fix unchanged lines.
1188 1190
1189 1191 $ hg init basewhole
1190 1192 $ cd basewhole
1191 1193 $ printf "foo1\n" > foo.changed
1192 1194 $ hg commit -Aqm "first"
1193 1195 $ printf "foo2\n" >> foo.changed
1194 1196 $ printf "bar\n" > bar.changed
1195 1197 $ hg commit -Aqm "second"
1196 1198
1197 1199 $ hg fix --working-dir --whole
1198 1200 $ cat *.changed
1199 1201 bar
1200 1202 foo1
1201 1203 foo2
1202 1204
1203 1205 $ hg fix --working-dir --base 0 --whole
1204 1206 $ cat *.changed
1205 1207 BAR
1206 1208 FOO1
1207 1209 FOO2
1208 1210
1209 1211 $ cd ..
1210 1212
1211 1213 The execution order of tools can be controlled. This example doesn't work if
1212 1214 you sort after truncating, but the config defines the correct order while the
1213 1215 definitions are out of order (which might imply the incorrect order given the
1214 1216 implementation of fix). The goal is to use multiple tools to select the lowest
1215 1217 5 numbers in the file.
1216 1218
1217 1219 $ hg init priorityexample
1218 1220 $ cd priorityexample
1219 1221
1220 1222 $ cat >> .hg/hgrc <<EOF
1221 1223 > [fix]
1222 1224 > head:command = head -n 5
1223 1225 > head:pattern = numbers.txt
1224 1226 > head:priority = 1
1225 1227 > sort:command = sort -n
1226 1228 > sort:pattern = numbers.txt
1227 1229 > sort:priority = 2
1228 1230 > EOF
1229 1231
1230 1232 $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
1231 1233 $ hg add -q
1232 1234 $ hg fix -w
1233 1235 $ cat numbers.txt
1234 1236 0
1235 1237 1
1236 1238 2
1237 1239 3
1238 1240 4
1239 1241
1240 1242 And of course we should be able to break this by reversing the execution order.
1241 1243 Test negative priorities while we're at it.
1242 1244
1243 1245 $ cat >> .hg/hgrc <<EOF
1244 1246 > [fix]
1245 1247 > head:priority = -1
1246 1248 > sort:priority = -2
1247 1249 > EOF
1248 1250 $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
1249 1251 $ hg fix -w
1250 1252 $ cat numbers.txt
1251 1253 2
1252 1254 3
1253 1255 6
1254 1256 7
1255 1257 8
1256 1258
1257 1259 $ cd ..
1258 1260
1259 1261 It's possible for repeated applications of a fixer tool to create cycles in the
1260 1262 generated content of a file. For example, two users with different versions of
1261 1263 a code formatter might fight over the formatting when they run hg fix. In the
1262 1264 absence of other changes, this means we could produce commits with the same
1263 1265 hash in subsequent runs of hg fix. This is a problem unless we support
1264 1266 obsolescence cycles well. We avoid this by adding an extra field to the
1265 1267 successor which forces it to have a new hash. That's why this test creates
1266 1268 three revisions instead of two.
1267 1269
1268 1270 $ hg init cyclictool
1269 1271 $ cd cyclictool
1270 1272
1271 1273 $ cat >> .hg/hgrc <<EOF
1272 1274 > [fix]
1273 1275 > swapletters:command = tr ab ba
1274 1276 > swapletters:pattern = foo
1275 1277 > EOF
1276 1278
1277 1279 $ echo ab > foo
1278 1280 $ hg commit -Aqm foo
1279 1281
1280 1282 $ hg fix -r 0
1281 1283 $ hg fix -r 1
1282 1284
1283 1285 $ hg cat -r 0 foo --hidden
1284 1286 ab
1285 1287 $ hg cat -r 1 foo --hidden
1286 1288 ba
1287 1289 $ hg cat -r 2 foo
1288 1290 ab
1289 1291
1290 1292 $ cd ..
1291 1293
1292 1294 We run fixer tools in the repo root so they can look for config files or other
1293 1295 important things in the working directory. This does NOT mean we are
1294 1296 reconstructing a working copy of every revision being fixed; we're just giving
1295 1297 the tool knowledge of the repo's location in case it can do something
1296 1298 reasonable with that.
1297 1299
1298 1300 $ hg init subprocesscwd
1299 1301 $ cd subprocesscwd
1300 1302
1301 1303 $ cat >> .hg/hgrc <<EOF
1302 1304 > [fix]
1303 1305 > printcwd:command = "$PYTHON" -c "import os; print(os.getcwd())"
1304 1306 > printcwd:pattern = relpath:foo/bar
1305 1307 > filesetpwd:command = "$PYTHON" -c "import os; print('fs: ' + os.getcwd())"
1306 1308 > filesetpwd:pattern = set:**quux
1307 1309 > EOF
1308 1310
1309 1311 $ mkdir foo
1310 1312 $ printf "bar\n" > foo/bar
1311 1313 $ printf "quux\n" > quux
1312 1314 $ hg commit -Aqm blah
1313 1315
1314 1316 $ hg fix -w -r . foo/bar
1315 1317 $ hg cat -r tip foo/bar
1316 1318 $TESTTMP/subprocesscwd
1317 1319 $ cat foo/bar
1318 1320 $TESTTMP/subprocesscwd
1319 1321
1320 1322 $ cd foo
1321 1323
1322 1324 $ hg fix -w -r . bar
1323 1325 $ hg cat -r tip bar ../quux
1324 1326 $TESTTMP/subprocesscwd
1325 1327 quux
1326 1328 $ cat bar ../quux
1327 1329 $TESTTMP/subprocesscwd
1328 1330 quux
1329 1331 $ echo modified > bar
1330 1332 $ hg fix -w bar
1331 1333 $ cat bar
1332 1334 $TESTTMP/subprocesscwd
1333 1335
1334 1336 Apparently fixing p1() and its descendants doesn't include wdir() unless
1335 1337 explicitly stated.
1336 1338
1337 1339 $ hg fix -r '.::'
1338 1340 $ hg cat -r . ../quux
1339 1341 quux
1340 1342 $ hg cat -r tip ../quux
1341 1343 fs: $TESTTMP/subprocesscwd
1342 1344 $ cat ../quux
1343 1345 quux
1344 1346
1345 1347 Clean files are not fixed unless explicitly named
1346 1348 $ echo 'dirty' > ../quux
1347 1349
1348 1350 $ hg fix --working-dir
1349 1351 $ cat ../quux
1350 1352 fs: $TESTTMP/subprocesscwd
1351 1353
1352 1354 $ cd ../..
1353 1355
1354 1356 Tools configured without a pattern are ignored. It would be too dangerous to
1355 1357 run them on all files, because this might happen while testing a configuration
1356 1358 that also deletes all of the file content. There is no reasonable subset of the
1357 1359 files to use as a default. Users should be explicit about what files are
1358 1360 affected by a tool. This test also confirms that we don't crash when the
1359 1361 pattern config is missing, and that we only warn about it once.
1360 1362
1361 1363 $ hg init nopatternconfigured
1362 1364 $ cd nopatternconfigured
1363 1365
1364 1366 $ printf "foo" > foo
1365 1367 $ printf "bar" > bar
1366 1368 $ hg add -q
1367 1369 $ hg fix --debug --working-dir --config "fix.nopattern:command=echo fixed"
1368 1370 fixer tool has no pattern configuration: nopattern
1369 1371 $ cat foo bar
1370 1372 foobar (no-eol)
1371 1373 $ hg fix --debug --working-dir --config "fix.nocommand:pattern=foo.bar"
1372 1374 fixer tool has no command configuration: nocommand
1373 1375
1374 1376 $ cd ..
1375 1377
1376 1378 Tools can be disabled. Disabled tools do nothing but print a debug message.
1377 1379
1378 1380 $ hg init disabled
1379 1381 $ cd disabled
1380 1382
1381 1383 $ printf "foo\n" > foo
1382 1384 $ hg add -q
1383 1385 $ hg fix --debug --working-dir --config "fix.disabled:command=echo fixed" \
1384 1386 > --config "fix.disabled:pattern=foo" \
1385 1387 > --config "fix.disabled:enabled=false"
1386 1388 ignoring disabled fixer tool: disabled
1387 1389 $ cat foo
1388 1390 foo
1389 1391
1390 1392 $ cd ..
1391 1393
1392 1394 Test that we can configure a fixer to affect all files regardless of the cwd.
1393 1395 The way we invoke matching must not prohibit this.
1394 1396
1395 1397 $ hg init affectallfiles
1396 1398 $ cd affectallfiles
1397 1399
1398 1400 $ mkdir foo bar
1399 1401 $ printf "foo" > foo/file
1400 1402 $ printf "bar" > bar/file
1401 1403 $ printf "baz" > baz_file
1402 1404 $ hg add -q
1403 1405
1404 1406 $ cd bar
1405 1407 $ hg fix --working-dir --config "fix.cooltool:command=echo fixed" \
1406 1408 > --config "fix.cooltool:pattern=glob:**"
1407 1409 $ cd ..
1408 1410
1409 1411 $ cat foo/file
1410 1412 fixed
1411 1413 $ cat bar/file
1412 1414 fixed
1413 1415 $ cat baz_file
1414 1416 fixed
1415 1417
1416 1418 $ cd ..
1417 1419
1418 1420 Tools should be able to run on unchanged files, even if they set :linerange.
1419 1421 This includes a corner case where deleted chunks of a file are not considered
1420 1422 changes.
1421 1423
1422 1424 $ hg init skipclean
1423 1425 $ cd skipclean
1424 1426
1425 1427 $ printf "a\nb\nc\n" > foo
1426 1428 $ printf "a\nb\nc\n" > bar
1427 1429 $ printf "a\nb\nc\n" > baz
1428 1430 $ hg commit -Aqm "base"
1429 1431
1430 1432 $ printf "a\nc\n" > foo
1431 1433 $ printf "a\nx\nc\n" > baz
1432 1434
1433 1435 $ cat >> print.py <<EOF
1434 1436 > import sys
1435 1437 > for a in sys.argv[1:]:
1436 1438 > print(a)
1437 1439 > EOF
1438 1440
1439 1441 $ hg fix --working-dir foo bar baz \
1440 1442 > --config "fix.changedlines:command=\"$PYTHON\" print.py \"Line ranges:\"" \
1441 1443 > --config 'fix.changedlines:linerange="{first} through {last}"' \
1442 1444 > --config 'fix.changedlines:pattern=glob:**' \
1443 1445 > --config 'fix.changedlines:skipclean=false'
1444 1446
1445 1447 $ cat foo
1446 1448 Line ranges:
1447 1449 $ cat bar
1448 1450 Line ranges:
1449 1451 $ cat baz
1450 1452 Line ranges:
1451 1453 2 through 2
1452 1454
1453 1455 $ cd ..
1454 1456
1455 1457 Test various cases around merges. We were previously dropping files if they were
1456 1458 created on only the p2 side of the merge, so let's test permutations of:
1457 1459 * added, was fixed
1458 1460 * added, considered for fixing but was already good
1459 1461 * added, not considered for fixing
1460 1462 * modified, was fixed
1461 1463 * modified, considered for fixing but was already good
1462 1464 * modified, not considered for fixing
1463 1465
1464 1466 Before the bug was fixed where we would drop files, this test demonstrated the
1465 1467 following issues:
1466 1468 * new_in_r1.ignored, new_in_r1_already_good.changed, and
1467 1469 > mod_in_r1_already_good.changed were NOT in the manifest for the merge commit
1468 1470 * mod_in_r1.ignored had its contents from r0, NOT r1.
1469 1471
1470 1472 We're also setting a named branch for every commit to demonstrate that the
1471 1473 branch is kept intact and there aren't issues updating to another branch in the
1472 1474 middle of fix.
1473 1475
1474 1476 $ hg init merge_keeps_files
1475 1477 $ cd merge_keeps_files
1476 1478 $ for f in r0 mod_in_r1 mod_in_r2 mod_in_merge mod_in_child; do
1477 1479 > for c in changed whole ignored; do
1478 1480 > printf "hello\n" > $f.$c
1479 1481 > done
1480 1482 > printf "HELLO\n" > "mod_in_${f}_already_good.changed"
1481 1483 > done
1482 1484 $ hg branch -q r0
1483 1485 $ hg ci -Aqm 'r0'
1484 1486 $ hg phase -p
1485 1487 $ make_test_files() {
1486 1488 > printf "world\n" >> "mod_in_$1.changed"
1487 1489 > printf "world\n" >> "mod_in_$1.whole"
1488 1490 > printf "world\n" >> "mod_in_$1.ignored"
1489 1491 > printf "WORLD\n" >> "mod_in_$1_already_good.changed"
1490 1492 > printf "new in $1\n" > "new_in_$1.changed"
1491 1493 > printf "new in $1\n" > "new_in_$1.whole"
1492 1494 > printf "new in $1\n" > "new_in_$1.ignored"
1493 1495 > printf "ALREADY GOOD, NEW IN THIS REV\n" > "new_in_$1_already_good.changed"
1494 1496 > }
1495 1497 $ make_test_commit() {
1496 1498 > make_test_files "$1"
1497 1499 > hg branch -q "$1"
1498 1500 > hg ci -Aqm "$2"
1499 1501 > }
1500 1502 $ make_test_commit r1 "merge me, pt1"
1501 1503 $ hg co -q ".^"
1502 1504 $ make_test_commit r2 "merge me, pt2"
1503 1505 $ hg merge -qr 1
1504 1506 $ make_test_commit merge "evil merge"
1505 1507 $ make_test_commit child "child of merge"
1506 1508 $ make_test_files wdir
1507 1509 $ hg fix -r 'not public()' -w
1508 1510 $ hg log -G -T'{rev}:{shortest(node,8)}: branch:{branch} desc:{desc}'
1509 1511 @ 8:c22ce900: branch:child desc:child of merge
1510 1512 |
1511 1513 o 7:5a30615a: branch:merge desc:evil merge
1512 1514 |\
1513 1515 | o 6:4e5acdc4: branch:r2 desc:merge me, pt2
1514 1516 | |
1515 1517 o | 5:eea01878: branch:r1 desc:merge me, pt1
1516 1518 |/
1517 1519 o 0:0c548d87: branch:r0 desc:r0
1518 1520
1519 1521 $ hg files -r tip
1520 1522 mod_in_child.changed
1521 1523 mod_in_child.ignored
1522 1524 mod_in_child.whole
1523 1525 mod_in_child_already_good.changed
1524 1526 mod_in_merge.changed
1525 1527 mod_in_merge.ignored
1526 1528 mod_in_merge.whole
1527 1529 mod_in_merge_already_good.changed
1528 1530 mod_in_mod_in_child_already_good.changed
1529 1531 mod_in_mod_in_merge_already_good.changed
1530 1532 mod_in_mod_in_r1_already_good.changed
1531 1533 mod_in_mod_in_r2_already_good.changed
1532 1534 mod_in_r0_already_good.changed
1533 1535 mod_in_r1.changed
1534 1536 mod_in_r1.ignored
1535 1537 mod_in_r1.whole
1536 1538 mod_in_r1_already_good.changed
1537 1539 mod_in_r2.changed
1538 1540 mod_in_r2.ignored
1539 1541 mod_in_r2.whole
1540 1542 mod_in_r2_already_good.changed
1541 1543 new_in_child.changed
1542 1544 new_in_child.ignored
1543 1545 new_in_child.whole
1544 1546 new_in_child_already_good.changed
1545 1547 new_in_merge.changed
1546 1548 new_in_merge.ignored
1547 1549 new_in_merge.whole
1548 1550 new_in_merge_already_good.changed
1549 1551 new_in_r1.changed
1550 1552 new_in_r1.ignored
1551 1553 new_in_r1.whole
1552 1554 new_in_r1_already_good.changed
1553 1555 new_in_r2.changed
1554 1556 new_in_r2.ignored
1555 1557 new_in_r2.whole
1556 1558 new_in_r2_already_good.changed
1557 1559 r0.changed
1558 1560 r0.ignored
1559 1561 r0.whole
1560 1562 $ for f in "$(hg files -r tip)"; do hg cat -r tip $f -T'{path}:\n{data}\n'; done
1561 1563 mod_in_child.changed:
1562 1564 hello
1563 1565 WORLD
1564 1566
1565 1567 mod_in_child.ignored:
1566 1568 hello
1567 1569 world
1568 1570
1569 1571 mod_in_child.whole:
1570 1572 HELLO
1571 1573 WORLD
1572 1574
1573 1575 mod_in_child_already_good.changed:
1574 1576 WORLD
1575 1577
1576 1578 mod_in_merge.changed:
1577 1579 hello
1578 1580 WORLD
1579 1581
1580 1582 mod_in_merge.ignored:
1581 1583 hello
1582 1584 world
1583 1585
1584 1586 mod_in_merge.whole:
1585 1587 HELLO
1586 1588 WORLD
1587 1589
1588 1590 mod_in_merge_already_good.changed:
1589 1591 WORLD
1590 1592
1591 1593 mod_in_mod_in_child_already_good.changed:
1592 1594 HELLO
1593 1595
1594 1596 mod_in_mod_in_merge_already_good.changed:
1595 1597 HELLO
1596 1598
1597 1599 mod_in_mod_in_r1_already_good.changed:
1598 1600 HELLO
1599 1601
1600 1602 mod_in_mod_in_r2_already_good.changed:
1601 1603 HELLO
1602 1604
1603 1605 mod_in_r0_already_good.changed:
1604 1606 HELLO
1605 1607
1606 1608 mod_in_r1.changed:
1607 1609 hello
1608 1610 WORLD
1609 1611
1610 1612 mod_in_r1.ignored:
1611 1613 hello
1612 1614 world
1613 1615
1614 1616 mod_in_r1.whole:
1615 1617 HELLO
1616 1618 WORLD
1617 1619
1618 1620 mod_in_r1_already_good.changed:
1619 1621 WORLD
1620 1622
1621 1623 mod_in_r2.changed:
1622 1624 hello
1623 1625 WORLD
1624 1626
1625 1627 mod_in_r2.ignored:
1626 1628 hello
1627 1629 world
1628 1630
1629 1631 mod_in_r2.whole:
1630 1632 HELLO
1631 1633 WORLD
1632 1634
1633 1635 mod_in_r2_already_good.changed:
1634 1636 WORLD
1635 1637
1636 1638 new_in_child.changed:
1637 1639 NEW IN CHILD
1638 1640
1639 1641 new_in_child.ignored:
1640 1642 new in child
1641 1643
1642 1644 new_in_child.whole:
1643 1645 NEW IN CHILD
1644 1646
1645 1647 new_in_child_already_good.changed:
1646 1648 ALREADY GOOD, NEW IN THIS REV
1647 1649
1648 1650 new_in_merge.changed:
1649 1651 NEW IN MERGE
1650 1652
1651 1653 new_in_merge.ignored:
1652 1654 new in merge
1653 1655
1654 1656 new_in_merge.whole:
1655 1657 NEW IN MERGE
1656 1658
1657 1659 new_in_merge_already_good.changed:
1658 1660 ALREADY GOOD, NEW IN THIS REV
1659 1661
1660 1662 new_in_r1.changed:
1661 1663 NEW IN R1
1662 1664
1663 1665 new_in_r1.ignored:
1664 1666 new in r1
1665 1667
1666 1668 new_in_r1.whole:
1667 1669 NEW IN R1
1668 1670
1669 1671 new_in_r1_already_good.changed:
1670 1672 ALREADY GOOD, NEW IN THIS REV
1671 1673
1672 1674 new_in_r2.changed:
1673 1675 NEW IN R2
1674 1676
1675 1677 new_in_r2.ignored:
1676 1678 new in r2
1677 1679
1678 1680 new_in_r2.whole:
1679 1681 NEW IN R2
1680 1682
1681 1683 new_in_r2_already_good.changed:
1682 1684 ALREADY GOOD, NEW IN THIS REV
1683 1685
1684 1686 r0.changed:
1685 1687 hello
1686 1688
1687 1689 r0.ignored:
1688 1690 hello
1689 1691
1690 1692 r0.whole:
1691 1693 hello
1692 1694
General Comments 0
You need to be logged in to leave comments. Login now