##// END OF EJS Templates
visibility: improve the message when accessing filtered obsolete rev...
Boris Feld -
r35612:265cd9e1 default
parent child Browse files
Show More
This diff has been collapsed as it changes many lines, (551 lines changed) Show them Hide them
@@ -0,0 +1,551 b''
1 This test file test the various messages when accessing obsolete
2 revisions.
3
4 Global setup
5 ============
6
7 $ . $TESTDIR/testlib/obsmarker-common.sh
8 $ cat >> $HGRCPATH <<EOF
9 > [ui]
10 > interactive = true
11 > [phases]
12 > publish=False
13 > [experimental]
14 > evolution.createmarkers = yes
15 > evolution.effect-flags = yes
16 > EOF
17
18 Test output on amended commit
19 =============================
20
21 Test setup
22 ----------
23
24 $ hg init $TESTTMP/local-amend
25 $ cd $TESTTMP/local-amend
26 $ mkcommit ROOT
27 $ mkcommit A0
28 $ echo 42 >> A0
29 $ hg commit --amend -m "A1
30 >
31 > Better commit message"
32 $ hg log --hidden -G
33 @ changeset: 2:4ae3a4151de9
34 | tag: tip
35 | parent: 0:ea207398892e
36 | user: test
37 | date: Thu Jan 01 00:00:00 1970 +0000
38 | summary: A1
39 |
40 | x changeset: 1:471f378eab4c
41 |/ user: test
42 | date: Thu Jan 01 00:00:00 1970 +0000
43 | obsolete: rewritten using amend as 2:4ae3a4151de9
44 | summary: A0
45 |
46 o changeset: 0:ea207398892e
47 user: test
48 date: Thu Jan 01 00:00:00 1970 +0000
49 summary: ROOT
50
51 Actual test
52 -----------
53 $ hg update 471f378eab4c
54 abort: hidden revision '471f378eab4c' was rewritten as: 4ae3a4151de9!
55 (use --hidden to access hidden revisions)
56 [255]
57 $ hg update --hidden "desc(A0)"
58 updating to a hidden changeset 471f378eab4c
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60
61 Test output with pruned commit
62 ==============================
63
64 Test setup
65 ----------
66
67 $ hg init $TESTTMP/local-prune
68 $ cd $TESTTMP/local-prune
69 $ mkcommit ROOT
70 $ mkcommit A0 # 0
71 $ mkcommit B0 # 1
72 $ hg log --hidden -G
73 @ changeset: 2:0dec01379d3b
74 | tag: tip
75 | user: test
76 | date: Thu Jan 01 00:00:00 1970 +0000
77 | summary: B0
78 |
79 o changeset: 1:471f378eab4c
80 | user: test
81 | date: Thu Jan 01 00:00:00 1970 +0000
82 | summary: A0
83 |
84 o changeset: 0:ea207398892e
85 user: test
86 date: Thu Jan 01 00:00:00 1970 +0000
87 summary: ROOT
88
89 $ hg debugobsolete --record-parents `getid 'desc(B0)'`
90 obsoleted 1 changesets
91
92 $ hg log --hidden -G
93 @ changeset: 2:0dec01379d3b
94 | tag: tip
95 | user: test
96 | date: Thu Jan 01 00:00:00 1970 +0000
97 | obsolete: pruned
98 | summary: B0
99 |
100 o changeset: 1:471f378eab4c
101 | user: test
102 | date: Thu Jan 01 00:00:00 1970 +0000
103 | summary: A0
104 |
105 o changeset: 0:ea207398892e
106 user: test
107 date: Thu Jan 01 00:00:00 1970 +0000
108 summary: ROOT
109
110
111 Actual test
112 -----------
113 $ hg up 1
114 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
115 $ hg up 0dec01379d3b
116 abort: hidden revision '0dec01379d3b' is pruned!
117 (use --hidden to access hidden revisions)
118 [255]
119 $ hg up --hidden -r 'desc(B0)'
120 updating to a hidden changeset 0dec01379d3b
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122
123 Test output with splitted commit
124 ================================
125
126 Test setup
127 ----------
128
129 $ hg init $TESTTMP/local-split
130 $ cd $TESTTMP/local-split
131 $ mkcommit ROOT
132 $ echo 42 >> a
133 $ echo 43 >> b
134 $ hg commit -A -m "A0"
135 adding a
136 adding b
137 $ hg log --hidden -G
138 @ changeset: 1:471597cad322
139 | tag: tip
140 | user: test
141 | date: Thu Jan 01 00:00:00 1970 +0000
142 | summary: A0
143 |
144 o changeset: 0:ea207398892e
145 user: test
146 date: Thu Jan 01 00:00:00 1970 +0000
147 summary: ROOT
148
149 # Simulate a split
150 $ hg up 0
151 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
152
153 $ echo 42 >> a
154 $ hg commit -A -m "A0"
155 adding a
156 created new head
157
158 $ echo 43 >> b
159 $ hg commit -A -m "A0"
160 adding b
161
162 $ hg debugobsolete `getid '1'` `getid '2'` `getid '3'`
163 obsoleted 1 changesets
164
165 $ hg log --hidden -G
166 @ changeset: 3:f257fde29c7a
167 | tag: tip
168 | user: test
169 | date: Thu Jan 01 00:00:00 1970 +0000
170 | summary: A0
171 |
172 o changeset: 2:337fec4d2edc
173 | parent: 0:ea207398892e
174 | user: test
175 | date: Thu Jan 01 00:00:00 1970 +0000
176 | summary: A0
177 |
178 | x changeset: 1:471597cad322
179 |/ user: test
180 | date: Thu Jan 01 00:00:00 1970 +0000
181 | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a
182 | summary: A0
183 |
184 o changeset: 0:ea207398892e
185 user: test
186 date: Thu Jan 01 00:00:00 1970 +0000
187 summary: ROOT
188
189 Actual test
190 -----------
191 $ hg update 471597cad322
192 abort: hidden revision '471597cad322' was split as: 337fec4d2edc, f257fde29c7a!
193 (use --hidden to access hidden revisions)
194 [255]
195 $ hg update --hidden 'min(desc(A0))'
196 updating to a hidden changeset 471597cad322
197 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
198
199 Test output with lots of splitted commit
200 ========================================
201
202 Test setup
203 ----------
204
205 $ hg init $TESTTMP/local-lots-split
206 $ cd $TESTTMP/local-lots-split
207 $ mkcommit ROOT
208 $ echo 42 >> a
209 $ echo 43 >> b
210 $ echo 44 >> c
211 $ echo 45 >> d
212 $ hg commit -A -m "A0"
213 adding a
214 adding b
215 adding c
216 adding d
217 $ hg log --hidden -G
218 @ changeset: 1:de7290d8b885
219 | tag: tip
220 | user: test
221 | date: Thu Jan 01 00:00:00 1970 +0000
222 | summary: A0
223 |
224 o changeset: 0:ea207398892e
225 user: test
226 date: Thu Jan 01 00:00:00 1970 +0000
227 summary: ROOT
228
229 # Simulate a split
230 $ hg up 0
231 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
232
233 $ echo 42 >> a
234 $ hg commit -A -m "A0"
235 adding a
236 created new head
237
238 $ echo 43 >> b
239 $ hg commit -A -m "A0"
240 adding b
241
242 $ echo 44 >> c
243 $ hg commit -A -m "A0"
244 adding c
245
246 $ echo 45 >> d
247 $ hg commit -A -m "A0"
248 adding d
249
250 $ hg debugobsolete `getid '1'` `getid '2'` `getid '3'` `getid '4'` `getid '5'`
251 obsoleted 1 changesets
252
253 $ hg log --hidden -G
254 @ changeset: 5:c7f044602e9b
255 | tag: tip
256 | user: test
257 | date: Thu Jan 01 00:00:00 1970 +0000
258 | summary: A0
259 |
260 o changeset: 4:1ae8bc733a14
261 | user: test
262 | date: Thu Jan 01 00:00:00 1970 +0000
263 | summary: A0
264 |
265 o changeset: 3:f257fde29c7a
266 | user: test
267 | date: Thu Jan 01 00:00:00 1970 +0000
268 | summary: A0
269 |
270 o changeset: 2:337fec4d2edc
271 | parent: 0:ea207398892e
272 | user: test
273 | date: Thu Jan 01 00:00:00 1970 +0000
274 | summary: A0
275 |
276 | x changeset: 1:de7290d8b885
277 |/ user: test
278 | date: Thu Jan 01 00:00:00 1970 +0000
279 | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a, 4:1ae8bc733a14, 5:c7f044602e9b
280 | summary: A0
281 |
282 o changeset: 0:ea207398892e
283 user: test
284 date: Thu Jan 01 00:00:00 1970 +0000
285 summary: ROOT
286
287 Actual test
288 -----------
289 $ hg update de7290d8b885
290 abort: hidden revision 'de7290d8b885' was split as: 337fec4d2edc, f257fde29c7a and 2 more!
291 (use --hidden to access hidden revisions)
292 [255]
293 $ hg update --hidden 'min(desc(A0))'
294 updating to a hidden changeset de7290d8b885
295 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
296
297 Test output with folded commit
298 ==============================
299
300 Test setup
301 ----------
302
303 $ hg init $TESTTMP/local-fold
304 $ cd $TESTTMP/local-fold
305 $ mkcommit ROOT
306 $ mkcommit A0
307 $ mkcommit B0
308 $ hg log --hidden -G
309 @ changeset: 2:0dec01379d3b
310 | tag: tip
311 | user: test
312 | date: Thu Jan 01 00:00:00 1970 +0000
313 | summary: B0
314 |
315 o changeset: 1:471f378eab4c
316 | user: test
317 | date: Thu Jan 01 00:00:00 1970 +0000
318 | summary: A0
319 |
320 o changeset: 0:ea207398892e
321 user: test
322 date: Thu Jan 01 00:00:00 1970 +0000
323 summary: ROOT
324
325 # Simulate a fold
326 $ hg up 0
327 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
328 $ echo "A0" > A0
329 $ echo "B0" > B0
330 $ hg add A0 B0
331 $ hg commit -m "C0"
332 created new head
333
334 $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(C0)'`
335 obsoleted 1 changesets
336 $ hg debugobsolete `getid 'desc(B0)'` `getid 'desc(C0)'`
337 obsoleted 1 changesets
338
339 $ hg log --hidden -G
340 @ changeset: 3:eb5a0daa2192
341 | tag: tip
342 | parent: 0:ea207398892e
343 | user: test
344 | date: Thu Jan 01 00:00:00 1970 +0000
345 | summary: C0
346 |
347 | x changeset: 2:0dec01379d3b
348 | | user: test
349 | | date: Thu Jan 01 00:00:00 1970 +0000
350 | | obsolete: rewritten as 3:eb5a0daa2192
351 | | summary: B0
352 | |
353 | x changeset: 1:471f378eab4c
354 |/ user: test
355 | date: Thu Jan 01 00:00:00 1970 +0000
356 | obsolete: rewritten as 3:eb5a0daa2192
357 | summary: A0
358 |
359 o changeset: 0:ea207398892e
360 user: test
361 date: Thu Jan 01 00:00:00 1970 +0000
362 summary: ROOT
363
364 Actual test
365 -----------
366 $ hg update 471f378eab4c
367 abort: hidden revision '471f378eab4c' was rewritten as: eb5a0daa2192!
368 (use --hidden to access hidden revisions)
369 [255]
370 $ hg update --hidden 'desc(A0)'
371 updating to a hidden changeset 471f378eab4c
372 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
373 $ hg update 0dec01379d3b
374 abort: hidden revision '0dec01379d3b' was rewritten as: eb5a0daa2192!
375 (use --hidden to access hidden revisions)
376 [255]
377 $ hg update --hidden 'desc(B0)'
378 updating to a hidden changeset 0dec01379d3b
379 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
380
381 Test output with divergence
382 ===========================
383
384 Test setup
385 ----------
386
387 $ hg init $TESTTMP/local-divergence
388 $ cd $TESTTMP/local-divergence
389 $ mkcommit ROOT
390 $ mkcommit A0
391 $ hg commit --amend -m "A1"
392 $ hg log --hidden -G
393 @ changeset: 2:fdf9bde5129a
394 | tag: tip
395 | parent: 0:ea207398892e
396 | user: test
397 | date: Thu Jan 01 00:00:00 1970 +0000
398 | summary: A1
399 |
400 | x changeset: 1:471f378eab4c
401 |/ user: test
402 | date: Thu Jan 01 00:00:00 1970 +0000
403 | obsolete: rewritten using amend as 2:fdf9bde5129a
404 | summary: A0
405 |
406 o changeset: 0:ea207398892e
407 user: test
408 date: Thu Jan 01 00:00:00 1970 +0000
409 summary: ROOT
410
411 $ hg update --hidden 'desc(A0)'
412 updating to a hidden changeset 471f378eab4c
413 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 $ hg commit --amend -m "A2"
415 $ hg log --hidden -G
416 @ changeset: 3:65b757b745b9
417 | tag: tip
418 | parent: 0:ea207398892e
419 | user: test
420 | date: Thu Jan 01 00:00:00 1970 +0000
421 | instability: content-divergent
422 | summary: A2
423 |
424 | * changeset: 2:fdf9bde5129a
425 |/ parent: 0:ea207398892e
426 | user: test
427 | date: Thu Jan 01 00:00:00 1970 +0000
428 | instability: content-divergent
429 | summary: A1
430 |
431 | x changeset: 1:471f378eab4c
432 |/ user: test
433 | date: Thu Jan 01 00:00:00 1970 +0000
434 | obsolete: rewritten using amend as 2:fdf9bde5129a
435 | obsolete: rewritten using amend as 3:65b757b745b9
436 | summary: A0
437 |
438 o changeset: 0:ea207398892e
439 user: test
440 date: Thu Jan 01 00:00:00 1970 +0000
441 summary: ROOT
442
443 Actual test
444 -----------
445 $ hg update 471f378eab4c
446 abort: hidden revision '471f378eab4c' has diverged!
447 (use --hidden to access hidden revisions)
448 [255]
449 $ hg update --hidden 'desc(A0)'
450 updating to a hidden changeset 471f378eab4c
451 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
452
453 Test output with amended + folded commit
454 ========================================
455
456 Test setup
457 ----------
458
459 $ hg init $TESTTMP/local-amend-fold
460 $ cd $TESTTMP/local-amend-fold
461 $ mkcommit ROOT
462 $ mkcommit A0
463 $ mkcommit B0
464 $ hg commit --amend -m "B1"
465 $ hg log --hidden -G
466 @ changeset: 3:b7ea6d14e664
467 | tag: tip
468 | parent: 1:471f378eab4c
469 | user: test
470 | date: Thu Jan 01 00:00:00 1970 +0000
471 | summary: B1
472 |
473 | x changeset: 2:0dec01379d3b
474 |/ user: test
475 | date: Thu Jan 01 00:00:00 1970 +0000
476 | obsolete: rewritten using amend as 3:b7ea6d14e664
477 | summary: B0
478 |
479 o changeset: 1:471f378eab4c
480 | user: test
481 | date: Thu Jan 01 00:00:00 1970 +0000
482 | summary: A0
483 |
484 o changeset: 0:ea207398892e
485 user: test
486 date: Thu Jan 01 00:00:00 1970 +0000
487 summary: ROOT
488
489
490 # Simulate a fold
491 $ hg up 0
492 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
493 $ echo "A0" > A0
494 $ echo "B0" > B0
495 $ hg add A0 B0
496 $ hg commit -m "C0"
497 created new head
498
499 $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(C0)'`
500 obsoleted 1 changesets
501 $ hg debugobsolete `getid 'desc(B1)'` `getid 'desc(C0)'`
502 obsoleted 1 changesets
503
504 $ hg log --hidden -G
505 @ changeset: 4:eb5a0daa2192
506 | tag: tip
507 | parent: 0:ea207398892e
508 | user: test
509 | date: Thu Jan 01 00:00:00 1970 +0000
510 | summary: C0
511 |
512 | x changeset: 3:b7ea6d14e664
513 | | parent: 1:471f378eab4c
514 | | user: test
515 | | date: Thu Jan 01 00:00:00 1970 +0000
516 | | obsolete: rewritten as 4:eb5a0daa2192
517 | | summary: B1
518 | |
519 | | x changeset: 2:0dec01379d3b
520 | |/ user: test
521 | | date: Thu Jan 01 00:00:00 1970 +0000
522 | | obsolete: rewritten using amend as 3:b7ea6d14e664
523 | | summary: B0
524 | |
525 | x changeset: 1:471f378eab4c
526 |/ user: test
527 | date: Thu Jan 01 00:00:00 1970 +0000
528 | obsolete: rewritten as 4:eb5a0daa2192
529 | summary: A0
530 |
531 o changeset: 0:ea207398892e
532 user: test
533 date: Thu Jan 01 00:00:00 1970 +0000
534 summary: ROOT
535
536 Actual test
537 -----------
538 $ hg update 471f378eab4c
539 abort: hidden revision '471f378eab4c' was rewritten as: eb5a0daa2192!
540 (use --hidden to access hidden revisions)
541 [255]
542 $ hg update --hidden 'desc(A0)'
543 updating to a hidden changeset 471f378eab4c
544 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
545 $ hg update --hidden 0dec01379d3b
546 updating to a hidden changeset 0dec01379d3b
547 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
548 $ hg update 0dec01379d3b
549 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
550 $ hg update --hidden 'desc(B0)'
551 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -1,2776 +1,2790 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import filecmp
11 import filecmp
12 import os
12 import os
13 import re
13 import re
14 import stat
14 import stat
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 addednodeid,
18 addednodeid,
19 bin,
19 bin,
20 hex,
20 hex,
21 modifiednodeid,
21 modifiednodeid,
22 nullid,
22 nullid,
23 nullrev,
23 nullrev,
24 short,
24 short,
25 wdirid,
25 wdirid,
26 wdirnodes,
26 wdirnodes,
27 wdirrev,
27 wdirrev,
28 )
28 )
29 from .thirdparty import (
29 from .thirdparty import (
30 attr,
30 attr,
31 )
31 )
32 from . import (
32 from . import (
33 encoding,
33 encoding,
34 error,
34 error,
35 fileset,
35 fileset,
36 match as matchmod,
36 match as matchmod,
37 mdiff,
37 mdiff,
38 obsolete as obsmod,
38 obsolete as obsmod,
39 obsutil,
39 patch,
40 patch,
40 pathutil,
41 pathutil,
41 phases,
42 phases,
42 pycompat,
43 pycompat,
43 repoview,
44 repoview,
44 revlog,
45 revlog,
45 scmutil,
46 scmutil,
46 sparse,
47 sparse,
47 subrepo,
48 subrepo,
48 util,
49 util,
49 )
50 )
50
51
51 propertycache = util.propertycache
52 propertycache = util.propertycache
52
53
53 nonascii = re.compile(r'[^\x21-\x7f]').search
54 nonascii = re.compile(r'[^\x21-\x7f]').search
54
55
55 class basectx(object):
56 class basectx(object):
56 """A basectx object represents the common logic for its children:
57 """A basectx object represents the common logic for its children:
57 changectx: read-only context that is already present in the repo,
58 changectx: read-only context that is already present in the repo,
58 workingctx: a context that represents the working directory and can
59 workingctx: a context that represents the working directory and can
59 be committed,
60 be committed,
60 memctx: a context that represents changes in-memory and can also
61 memctx: a context that represents changes in-memory and can also
61 be committed."""
62 be committed."""
62 def __new__(cls, repo, changeid='', *args, **kwargs):
63 def __new__(cls, repo, changeid='', *args, **kwargs):
63 if isinstance(changeid, basectx):
64 if isinstance(changeid, basectx):
64 return changeid
65 return changeid
65
66
66 o = super(basectx, cls).__new__(cls)
67 o = super(basectx, cls).__new__(cls)
67
68
68 o._repo = repo
69 o._repo = repo
69 o._rev = nullrev
70 o._rev = nullrev
70 o._node = nullid
71 o._node = nullid
71
72
72 return o
73 return o
73
74
74 def __bytes__(self):
75 def __bytes__(self):
75 return short(self.node())
76 return short(self.node())
76
77
77 __str__ = encoding.strmethod(__bytes__)
78 __str__ = encoding.strmethod(__bytes__)
78
79
79 def __int__(self):
80 def __int__(self):
80 return self.rev()
81 return self.rev()
81
82
82 def __repr__(self):
83 def __repr__(self):
83 return r"<%s %s>" % (type(self).__name__, str(self))
84 return r"<%s %s>" % (type(self).__name__, str(self))
84
85
85 def __eq__(self, other):
86 def __eq__(self, other):
86 try:
87 try:
87 return type(self) == type(other) and self._rev == other._rev
88 return type(self) == type(other) and self._rev == other._rev
88 except AttributeError:
89 except AttributeError:
89 return False
90 return False
90
91
91 def __ne__(self, other):
92 def __ne__(self, other):
92 return not (self == other)
93 return not (self == other)
93
94
94 def __contains__(self, key):
95 def __contains__(self, key):
95 return key in self._manifest
96 return key in self._manifest
96
97
97 def __getitem__(self, key):
98 def __getitem__(self, key):
98 return self.filectx(key)
99 return self.filectx(key)
99
100
100 def __iter__(self):
101 def __iter__(self):
101 return iter(self._manifest)
102 return iter(self._manifest)
102
103
103 def _buildstatusmanifest(self, status):
104 def _buildstatusmanifest(self, status):
104 """Builds a manifest that includes the given status results, if this is
105 """Builds a manifest that includes the given status results, if this is
105 a working copy context. For non-working copy contexts, it just returns
106 a working copy context. For non-working copy contexts, it just returns
106 the normal manifest."""
107 the normal manifest."""
107 return self.manifest()
108 return self.manifest()
108
109
109 def _matchstatus(self, other, match):
110 def _matchstatus(self, other, match):
110 """This internal method provides a way for child objects to override the
111 """This internal method provides a way for child objects to override the
111 match operator.
112 match operator.
112 """
113 """
113 return match
114 return match
114
115
115 def _buildstatus(self, other, s, match, listignored, listclean,
116 def _buildstatus(self, other, s, match, listignored, listclean,
116 listunknown):
117 listunknown):
117 """build a status with respect to another context"""
118 """build a status with respect to another context"""
118 # Load earliest manifest first for caching reasons. More specifically,
119 # Load earliest manifest first for caching reasons. More specifically,
119 # if you have revisions 1000 and 1001, 1001 is probably stored as a
120 # if you have revisions 1000 and 1001, 1001 is probably stored as a
120 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
121 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
121 # 1000 and cache it so that when you read 1001, we just need to apply a
122 # 1000 and cache it so that when you read 1001, we just need to apply a
122 # delta to what's in the cache. So that's one full reconstruction + one
123 # delta to what's in the cache. So that's one full reconstruction + one
123 # delta application.
124 # delta application.
124 mf2 = None
125 mf2 = None
125 if self.rev() is not None and self.rev() < other.rev():
126 if self.rev() is not None and self.rev() < other.rev():
126 mf2 = self._buildstatusmanifest(s)
127 mf2 = self._buildstatusmanifest(s)
127 mf1 = other._buildstatusmanifest(s)
128 mf1 = other._buildstatusmanifest(s)
128 if mf2 is None:
129 if mf2 is None:
129 mf2 = self._buildstatusmanifest(s)
130 mf2 = self._buildstatusmanifest(s)
130
131
131 modified, added = [], []
132 modified, added = [], []
132 removed = []
133 removed = []
133 clean = []
134 clean = []
134 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
135 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
135 deletedset = set(deleted)
136 deletedset = set(deleted)
136 d = mf1.diff(mf2, match=match, clean=listclean)
137 d = mf1.diff(mf2, match=match, clean=listclean)
137 for fn, value in d.iteritems():
138 for fn, value in d.iteritems():
138 if fn in deletedset:
139 if fn in deletedset:
139 continue
140 continue
140 if value is None:
141 if value is None:
141 clean.append(fn)
142 clean.append(fn)
142 continue
143 continue
143 (node1, flag1), (node2, flag2) = value
144 (node1, flag1), (node2, flag2) = value
144 if node1 is None:
145 if node1 is None:
145 added.append(fn)
146 added.append(fn)
146 elif node2 is None:
147 elif node2 is None:
147 removed.append(fn)
148 removed.append(fn)
148 elif flag1 != flag2:
149 elif flag1 != flag2:
149 modified.append(fn)
150 modified.append(fn)
150 elif node2 not in wdirnodes:
151 elif node2 not in wdirnodes:
151 # When comparing files between two commits, we save time by
152 # When comparing files between two commits, we save time by
152 # not comparing the file contents when the nodeids differ.
153 # not comparing the file contents when the nodeids differ.
153 # Note that this means we incorrectly report a reverted change
154 # Note that this means we incorrectly report a reverted change
154 # to a file as a modification.
155 # to a file as a modification.
155 modified.append(fn)
156 modified.append(fn)
156 elif self[fn].cmp(other[fn]):
157 elif self[fn].cmp(other[fn]):
157 modified.append(fn)
158 modified.append(fn)
158 else:
159 else:
159 clean.append(fn)
160 clean.append(fn)
160
161
161 if removed:
162 if removed:
162 # need to filter files if they are already reported as removed
163 # need to filter files if they are already reported as removed
163 unknown = [fn for fn in unknown if fn not in mf1 and
164 unknown = [fn for fn in unknown if fn not in mf1 and
164 (not match or match(fn))]
165 (not match or match(fn))]
165 ignored = [fn for fn in ignored if fn not in mf1 and
166 ignored = [fn for fn in ignored if fn not in mf1 and
166 (not match or match(fn))]
167 (not match or match(fn))]
167 # if they're deleted, don't report them as removed
168 # if they're deleted, don't report them as removed
168 removed = [fn for fn in removed if fn not in deletedset]
169 removed = [fn for fn in removed if fn not in deletedset]
169
170
170 return scmutil.status(modified, added, removed, deleted, unknown,
171 return scmutil.status(modified, added, removed, deleted, unknown,
171 ignored, clean)
172 ignored, clean)
172
173
173 @propertycache
174 @propertycache
174 def substate(self):
175 def substate(self):
175 return subrepo.state(self, self._repo.ui)
176 return subrepo.state(self, self._repo.ui)
176
177
177 def subrev(self, subpath):
178 def subrev(self, subpath):
178 return self.substate[subpath][1]
179 return self.substate[subpath][1]
179
180
180 def rev(self):
181 def rev(self):
181 return self._rev
182 return self._rev
182 def node(self):
183 def node(self):
183 return self._node
184 return self._node
184 def hex(self):
185 def hex(self):
185 return hex(self.node())
186 return hex(self.node())
186 def manifest(self):
187 def manifest(self):
187 return self._manifest
188 return self._manifest
188 def manifestctx(self):
189 def manifestctx(self):
189 return self._manifestctx
190 return self._manifestctx
190 def repo(self):
191 def repo(self):
191 return self._repo
192 return self._repo
192 def phasestr(self):
193 def phasestr(self):
193 return phases.phasenames[self.phase()]
194 return phases.phasenames[self.phase()]
194 def mutable(self):
195 def mutable(self):
195 return self.phase() > phases.public
196 return self.phase() > phases.public
196
197
197 def getfileset(self, expr):
198 def getfileset(self, expr):
198 return fileset.getfileset(self, expr)
199 return fileset.getfileset(self, expr)
199
200
200 def obsolete(self):
201 def obsolete(self):
201 """True if the changeset is obsolete"""
202 """True if the changeset is obsolete"""
202 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
203 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
203
204
204 def extinct(self):
205 def extinct(self):
205 """True if the changeset is extinct"""
206 """True if the changeset is extinct"""
206 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
207 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
207
208
208 def unstable(self):
209 def unstable(self):
209 msg = ("'context.unstable' is deprecated, "
210 msg = ("'context.unstable' is deprecated, "
210 "use 'context.orphan'")
211 "use 'context.orphan'")
211 self._repo.ui.deprecwarn(msg, '4.4')
212 self._repo.ui.deprecwarn(msg, '4.4')
212 return self.orphan()
213 return self.orphan()
213
214
214 def orphan(self):
215 def orphan(self):
215 """True if the changeset is not obsolete but it's ancestor are"""
216 """True if the changeset is not obsolete but it's ancestor are"""
216 return self.rev() in obsmod.getrevs(self._repo, 'orphan')
217 return self.rev() in obsmod.getrevs(self._repo, 'orphan')
217
218
218 def bumped(self):
219 def bumped(self):
219 msg = ("'context.bumped' is deprecated, "
220 msg = ("'context.bumped' is deprecated, "
220 "use 'context.phasedivergent'")
221 "use 'context.phasedivergent'")
221 self._repo.ui.deprecwarn(msg, '4.4')
222 self._repo.ui.deprecwarn(msg, '4.4')
222 return self.phasedivergent()
223 return self.phasedivergent()
223
224
224 def phasedivergent(self):
225 def phasedivergent(self):
225 """True if the changeset try to be a successor of a public changeset
226 """True if the changeset try to be a successor of a public changeset
226
227
227 Only non-public and non-obsolete changesets may be bumped.
228 Only non-public and non-obsolete changesets may be bumped.
228 """
229 """
229 return self.rev() in obsmod.getrevs(self._repo, 'phasedivergent')
230 return self.rev() in obsmod.getrevs(self._repo, 'phasedivergent')
230
231
231 def divergent(self):
232 def divergent(self):
232 msg = ("'context.divergent' is deprecated, "
233 msg = ("'context.divergent' is deprecated, "
233 "use 'context.contentdivergent'")
234 "use 'context.contentdivergent'")
234 self._repo.ui.deprecwarn(msg, '4.4')
235 self._repo.ui.deprecwarn(msg, '4.4')
235 return self.contentdivergent()
236 return self.contentdivergent()
236
237
237 def contentdivergent(self):
238 def contentdivergent(self):
238 """Is a successors of a changeset with multiple possible successors set
239 """Is a successors of a changeset with multiple possible successors set
239
240
240 Only non-public and non-obsolete changesets may be divergent.
241 Only non-public and non-obsolete changesets may be divergent.
241 """
242 """
242 return self.rev() in obsmod.getrevs(self._repo, 'contentdivergent')
243 return self.rev() in obsmod.getrevs(self._repo, 'contentdivergent')
243
244
244 def troubled(self):
245 def troubled(self):
245 msg = ("'context.troubled' is deprecated, "
246 msg = ("'context.troubled' is deprecated, "
246 "use 'context.isunstable'")
247 "use 'context.isunstable'")
247 self._repo.ui.deprecwarn(msg, '4.4')
248 self._repo.ui.deprecwarn(msg, '4.4')
248 return self.isunstable()
249 return self.isunstable()
249
250
250 def isunstable(self):
251 def isunstable(self):
251 """True if the changeset is either unstable, bumped or divergent"""
252 """True if the changeset is either unstable, bumped or divergent"""
252 return self.orphan() or self.phasedivergent() or self.contentdivergent()
253 return self.orphan() or self.phasedivergent() or self.contentdivergent()
253
254
254 def troubles(self):
255 def troubles(self):
255 """Keep the old version around in order to avoid breaking extensions
256 """Keep the old version around in order to avoid breaking extensions
256 about different return values.
257 about different return values.
257 """
258 """
258 msg = ("'context.troubles' is deprecated, "
259 msg = ("'context.troubles' is deprecated, "
259 "use 'context.instabilities'")
260 "use 'context.instabilities'")
260 self._repo.ui.deprecwarn(msg, '4.4')
261 self._repo.ui.deprecwarn(msg, '4.4')
261
262
262 troubles = []
263 troubles = []
263 if self.orphan():
264 if self.orphan():
264 troubles.append('orphan')
265 troubles.append('orphan')
265 if self.phasedivergent():
266 if self.phasedivergent():
266 troubles.append('bumped')
267 troubles.append('bumped')
267 if self.contentdivergent():
268 if self.contentdivergent():
268 troubles.append('divergent')
269 troubles.append('divergent')
269 return troubles
270 return troubles
270
271
271 def instabilities(self):
272 def instabilities(self):
272 """return the list of instabilities affecting this changeset.
273 """return the list of instabilities affecting this changeset.
273
274
274 Instabilities are returned as strings. possible values are:
275 Instabilities are returned as strings. possible values are:
275 - orphan,
276 - orphan,
276 - phase-divergent,
277 - phase-divergent,
277 - content-divergent.
278 - content-divergent.
278 """
279 """
279 instabilities = []
280 instabilities = []
280 if self.orphan():
281 if self.orphan():
281 instabilities.append('orphan')
282 instabilities.append('orphan')
282 if self.phasedivergent():
283 if self.phasedivergent():
283 instabilities.append('phase-divergent')
284 instabilities.append('phase-divergent')
284 if self.contentdivergent():
285 if self.contentdivergent():
285 instabilities.append('content-divergent')
286 instabilities.append('content-divergent')
286 return instabilities
287 return instabilities
287
288
288 def parents(self):
289 def parents(self):
289 """return contexts for each parent changeset"""
290 """return contexts for each parent changeset"""
290 return self._parents
291 return self._parents
291
292
292 def p1(self):
293 def p1(self):
293 return self._parents[0]
294 return self._parents[0]
294
295
295 def p2(self):
296 def p2(self):
296 parents = self._parents
297 parents = self._parents
297 if len(parents) == 2:
298 if len(parents) == 2:
298 return parents[1]
299 return parents[1]
299 return changectx(self._repo, nullrev)
300 return changectx(self._repo, nullrev)
300
301
301 def _fileinfo(self, path):
302 def _fileinfo(self, path):
302 if r'_manifest' in self.__dict__:
303 if r'_manifest' in self.__dict__:
303 try:
304 try:
304 return self._manifest[path], self._manifest.flags(path)
305 return self._manifest[path], self._manifest.flags(path)
305 except KeyError:
306 except KeyError:
306 raise error.ManifestLookupError(self._node, path,
307 raise error.ManifestLookupError(self._node, path,
307 _('not found in manifest'))
308 _('not found in manifest'))
308 if r'_manifestdelta' in self.__dict__ or path in self.files():
309 if r'_manifestdelta' in self.__dict__ or path in self.files():
309 if path in self._manifestdelta:
310 if path in self._manifestdelta:
310 return (self._manifestdelta[path],
311 return (self._manifestdelta[path],
311 self._manifestdelta.flags(path))
312 self._manifestdelta.flags(path))
312 mfl = self._repo.manifestlog
313 mfl = self._repo.manifestlog
313 try:
314 try:
314 node, flag = mfl[self._changeset.manifest].find(path)
315 node, flag = mfl[self._changeset.manifest].find(path)
315 except KeyError:
316 except KeyError:
316 raise error.ManifestLookupError(self._node, path,
317 raise error.ManifestLookupError(self._node, path,
317 _('not found in manifest'))
318 _('not found in manifest'))
318
319
319 return node, flag
320 return node, flag
320
321
321 def filenode(self, path):
322 def filenode(self, path):
322 return self._fileinfo(path)[0]
323 return self._fileinfo(path)[0]
323
324
324 def flags(self, path):
325 def flags(self, path):
325 try:
326 try:
326 return self._fileinfo(path)[1]
327 return self._fileinfo(path)[1]
327 except error.LookupError:
328 except error.LookupError:
328 return ''
329 return ''
329
330
330 def sub(self, path, allowcreate=True):
331 def sub(self, path, allowcreate=True):
331 '''return a subrepo for the stored revision of path, never wdir()'''
332 '''return a subrepo for the stored revision of path, never wdir()'''
332 return subrepo.subrepo(self, path, allowcreate=allowcreate)
333 return subrepo.subrepo(self, path, allowcreate=allowcreate)
333
334
334 def nullsub(self, path, pctx):
335 def nullsub(self, path, pctx):
335 return subrepo.nullsubrepo(self, path, pctx)
336 return subrepo.nullsubrepo(self, path, pctx)
336
337
337 def workingsub(self, path):
338 def workingsub(self, path):
338 '''return a subrepo for the stored revision, or wdir if this is a wdir
339 '''return a subrepo for the stored revision, or wdir if this is a wdir
339 context.
340 context.
340 '''
341 '''
341 return subrepo.subrepo(self, path, allowwdir=True)
342 return subrepo.subrepo(self, path, allowwdir=True)
342
343
343 def match(self, pats=None, include=None, exclude=None, default='glob',
344 def match(self, pats=None, include=None, exclude=None, default='glob',
344 listsubrepos=False, badfn=None):
345 listsubrepos=False, badfn=None):
345 r = self._repo
346 r = self._repo
346 return matchmod.match(r.root, r.getcwd(), pats,
347 return matchmod.match(r.root, r.getcwd(), pats,
347 include, exclude, default,
348 include, exclude, default,
348 auditor=r.nofsauditor, ctx=self,
349 auditor=r.nofsauditor, ctx=self,
349 listsubrepos=listsubrepos, badfn=badfn)
350 listsubrepos=listsubrepos, badfn=badfn)
350
351
351 def diff(self, ctx2=None, match=None, **opts):
352 def diff(self, ctx2=None, match=None, **opts):
352 """Returns a diff generator for the given contexts and matcher"""
353 """Returns a diff generator for the given contexts and matcher"""
353 if ctx2 is None:
354 if ctx2 is None:
354 ctx2 = self.p1()
355 ctx2 = self.p1()
355 if ctx2 is not None:
356 if ctx2 is not None:
356 ctx2 = self._repo[ctx2]
357 ctx2 = self._repo[ctx2]
357 diffopts = patch.diffopts(self._repo.ui, pycompat.byteskwargs(opts))
358 diffopts = patch.diffopts(self._repo.ui, pycompat.byteskwargs(opts))
358 return patch.diff(self._repo, ctx2, self, match=match, opts=diffopts)
359 return patch.diff(self._repo, ctx2, self, match=match, opts=diffopts)
359
360
360 def dirs(self):
361 def dirs(self):
361 return self._manifest.dirs()
362 return self._manifest.dirs()
362
363
363 def hasdir(self, dir):
364 def hasdir(self, dir):
364 return self._manifest.hasdir(dir)
365 return self._manifest.hasdir(dir)
365
366
366 def status(self, other=None, match=None, listignored=False,
367 def status(self, other=None, match=None, listignored=False,
367 listclean=False, listunknown=False, listsubrepos=False):
368 listclean=False, listunknown=False, listsubrepos=False):
368 """return status of files between two nodes or node and working
369 """return status of files between two nodes or node and working
369 directory.
370 directory.
370
371
371 If other is None, compare this node with working directory.
372 If other is None, compare this node with working directory.
372
373
373 returns (modified, added, removed, deleted, unknown, ignored, clean)
374 returns (modified, added, removed, deleted, unknown, ignored, clean)
374 """
375 """
375
376
376 ctx1 = self
377 ctx1 = self
377 ctx2 = self._repo[other]
378 ctx2 = self._repo[other]
378
379
379 # This next code block is, admittedly, fragile logic that tests for
380 # This next code block is, admittedly, fragile logic that tests for
380 # reversing the contexts and wouldn't need to exist if it weren't for
381 # reversing the contexts and wouldn't need to exist if it weren't for
381 # the fast (and common) code path of comparing the working directory
382 # the fast (and common) code path of comparing the working directory
382 # with its first parent.
383 # with its first parent.
383 #
384 #
384 # What we're aiming for here is the ability to call:
385 # What we're aiming for here is the ability to call:
385 #
386 #
386 # workingctx.status(parentctx)
387 # workingctx.status(parentctx)
387 #
388 #
388 # If we always built the manifest for each context and compared those,
389 # If we always built the manifest for each context and compared those,
389 # then we'd be done. But the special case of the above call means we
390 # then we'd be done. But the special case of the above call means we
390 # just copy the manifest of the parent.
391 # just copy the manifest of the parent.
391 reversed = False
392 reversed = False
392 if (not isinstance(ctx1, changectx)
393 if (not isinstance(ctx1, changectx)
393 and isinstance(ctx2, changectx)):
394 and isinstance(ctx2, changectx)):
394 reversed = True
395 reversed = True
395 ctx1, ctx2 = ctx2, ctx1
396 ctx1, ctx2 = ctx2, ctx1
396
397
397 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
398 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
398 match = ctx2._matchstatus(ctx1, match)
399 match = ctx2._matchstatus(ctx1, match)
399 r = scmutil.status([], [], [], [], [], [], [])
400 r = scmutil.status([], [], [], [], [], [], [])
400 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
401 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
401 listunknown)
402 listunknown)
402
403
403 if reversed:
404 if reversed:
404 # Reverse added and removed. Clear deleted, unknown and ignored as
405 # Reverse added and removed. Clear deleted, unknown and ignored as
405 # these make no sense to reverse.
406 # these make no sense to reverse.
406 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
407 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
407 r.clean)
408 r.clean)
408
409
409 if listsubrepos:
410 if listsubrepos:
410 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
411 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
411 try:
412 try:
412 rev2 = ctx2.subrev(subpath)
413 rev2 = ctx2.subrev(subpath)
413 except KeyError:
414 except KeyError:
414 # A subrepo that existed in node1 was deleted between
415 # A subrepo that existed in node1 was deleted between
415 # node1 and node2 (inclusive). Thus, ctx2's substate
416 # node1 and node2 (inclusive). Thus, ctx2's substate
416 # won't contain that subpath. The best we can do ignore it.
417 # won't contain that subpath. The best we can do ignore it.
417 rev2 = None
418 rev2 = None
418 submatch = matchmod.subdirmatcher(subpath, match)
419 submatch = matchmod.subdirmatcher(subpath, match)
419 s = sub.status(rev2, match=submatch, ignored=listignored,
420 s = sub.status(rev2, match=submatch, ignored=listignored,
420 clean=listclean, unknown=listunknown,
421 clean=listclean, unknown=listunknown,
421 listsubrepos=True)
422 listsubrepos=True)
422 for rfiles, sfiles in zip(r, s):
423 for rfiles, sfiles in zip(r, s):
423 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
424 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
424
425
425 for l in r:
426 for l in r:
426 l.sort()
427 l.sort()
427
428
428 return r
429 return r
429
430
430 def _filterederror(repo, changeid):
431 def _filterederror(repo, changeid):
431 """build an exception to be raised about a filtered changeid
432 """build an exception to be raised about a filtered changeid
432
433
433 This is extracted in a function to help extensions (eg: evolve) to
434 This is extracted in a function to help extensions (eg: evolve) to
434 experiment with various message variants."""
435 experiment with various message variants."""
435 if repo.filtername.startswith('visible'):
436 if repo.filtername.startswith('visible'):
436 msg = _("hidden revision '%s'") % changeid
437
438 # Check if the changeset is obsolete
439 unfilteredrepo = repo.unfiltered()
440 ctx = unfilteredrepo[changeid]
441
442 # If the changeset is obsolete, enrich the hint with the reason that
443 # made this changeset not visible
444 if ctx.obsolete():
445 reason = obsutil._getfilteredreason(unfilteredrepo, ctx)
446 msg = _("hidden revision '%s' %s") % (changeid, reason)
447 else:
448 msg = _("hidden revision '%s'") % changeid
449
437 hint = _('use --hidden to access hidden revisions')
450 hint = _('use --hidden to access hidden revisions')
451
438 return error.FilteredRepoLookupError(msg, hint=hint)
452 return error.FilteredRepoLookupError(msg, hint=hint)
439 msg = _("filtered revision '%s' (not in '%s' subset)")
453 msg = _("filtered revision '%s' (not in '%s' subset)")
440 msg %= (changeid, repo.filtername)
454 msg %= (changeid, repo.filtername)
441 return error.FilteredRepoLookupError(msg)
455 return error.FilteredRepoLookupError(msg)
442
456
443 class changectx(basectx):
457 class changectx(basectx):
444 """A changecontext object makes access to data related to a particular
458 """A changecontext object makes access to data related to a particular
445 changeset convenient. It represents a read-only context already present in
459 changeset convenient. It represents a read-only context already present in
446 the repo."""
460 the repo."""
447 def __init__(self, repo, changeid=''):
461 def __init__(self, repo, changeid=''):
448 """changeid is a revision number, node, or tag"""
462 """changeid is a revision number, node, or tag"""
449
463
450 # since basectx.__new__ already took care of copying the object, we
464 # since basectx.__new__ already took care of copying the object, we
451 # don't need to do anything in __init__, so we just exit here
465 # don't need to do anything in __init__, so we just exit here
452 if isinstance(changeid, basectx):
466 if isinstance(changeid, basectx):
453 return
467 return
454
468
455 if changeid == '':
469 if changeid == '':
456 changeid = '.'
470 changeid = '.'
457 self._repo = repo
471 self._repo = repo
458
472
459 try:
473 try:
460 if isinstance(changeid, int):
474 if isinstance(changeid, int):
461 self._node = repo.changelog.node(changeid)
475 self._node = repo.changelog.node(changeid)
462 self._rev = changeid
476 self._rev = changeid
463 return
477 return
464 if not pycompat.ispy3 and isinstance(changeid, long):
478 if not pycompat.ispy3 and isinstance(changeid, long):
465 changeid = str(changeid)
479 changeid = str(changeid)
466 if changeid == 'null':
480 if changeid == 'null':
467 self._node = nullid
481 self._node = nullid
468 self._rev = nullrev
482 self._rev = nullrev
469 return
483 return
470 if changeid == 'tip':
484 if changeid == 'tip':
471 self._node = repo.changelog.tip()
485 self._node = repo.changelog.tip()
472 self._rev = repo.changelog.rev(self._node)
486 self._rev = repo.changelog.rev(self._node)
473 return
487 return
474 if (changeid == '.'
488 if (changeid == '.'
475 or repo.local() and changeid == repo.dirstate.p1()):
489 or repo.local() and changeid == repo.dirstate.p1()):
476 # this is a hack to delay/avoid loading obsmarkers
490 # this is a hack to delay/avoid loading obsmarkers
477 # when we know that '.' won't be hidden
491 # when we know that '.' won't be hidden
478 self._node = repo.dirstate.p1()
492 self._node = repo.dirstate.p1()
479 self._rev = repo.unfiltered().changelog.rev(self._node)
493 self._rev = repo.unfiltered().changelog.rev(self._node)
480 return
494 return
481 if len(changeid) == 20:
495 if len(changeid) == 20:
482 try:
496 try:
483 self._node = changeid
497 self._node = changeid
484 self._rev = repo.changelog.rev(changeid)
498 self._rev = repo.changelog.rev(changeid)
485 return
499 return
486 except error.FilteredRepoLookupError:
500 except error.FilteredRepoLookupError:
487 raise
501 raise
488 except LookupError:
502 except LookupError:
489 pass
503 pass
490
504
491 try:
505 try:
492 r = int(changeid)
506 r = int(changeid)
493 if '%d' % r != changeid:
507 if '%d' % r != changeid:
494 raise ValueError
508 raise ValueError
495 l = len(repo.changelog)
509 l = len(repo.changelog)
496 if r < 0:
510 if r < 0:
497 r += l
511 r += l
498 if r < 0 or r >= l and r != wdirrev:
512 if r < 0 or r >= l and r != wdirrev:
499 raise ValueError
513 raise ValueError
500 self._rev = r
514 self._rev = r
501 self._node = repo.changelog.node(r)
515 self._node = repo.changelog.node(r)
502 return
516 return
503 except error.FilteredIndexError:
517 except error.FilteredIndexError:
504 raise
518 raise
505 except (ValueError, OverflowError, IndexError):
519 except (ValueError, OverflowError, IndexError):
506 pass
520 pass
507
521
508 if len(changeid) == 40:
522 if len(changeid) == 40:
509 try:
523 try:
510 self._node = bin(changeid)
524 self._node = bin(changeid)
511 self._rev = repo.changelog.rev(self._node)
525 self._rev = repo.changelog.rev(self._node)
512 return
526 return
513 except error.FilteredLookupError:
527 except error.FilteredLookupError:
514 raise
528 raise
515 except (TypeError, LookupError):
529 except (TypeError, LookupError):
516 pass
530 pass
517
531
518 # lookup bookmarks through the name interface
532 # lookup bookmarks through the name interface
519 try:
533 try:
520 self._node = repo.names.singlenode(repo, changeid)
534 self._node = repo.names.singlenode(repo, changeid)
521 self._rev = repo.changelog.rev(self._node)
535 self._rev = repo.changelog.rev(self._node)
522 return
536 return
523 except KeyError:
537 except KeyError:
524 pass
538 pass
525 except error.FilteredRepoLookupError:
539 except error.FilteredRepoLookupError:
526 raise
540 raise
527 except error.RepoLookupError:
541 except error.RepoLookupError:
528 pass
542 pass
529
543
530 self._node = repo.unfiltered().changelog._partialmatch(changeid)
544 self._node = repo.unfiltered().changelog._partialmatch(changeid)
531 if self._node is not None:
545 if self._node is not None:
532 self._rev = repo.changelog.rev(self._node)
546 self._rev = repo.changelog.rev(self._node)
533 return
547 return
534
548
535 # lookup failed
549 # lookup failed
536 # check if it might have come from damaged dirstate
550 # check if it might have come from damaged dirstate
537 #
551 #
538 # XXX we could avoid the unfiltered if we had a recognizable
552 # XXX we could avoid the unfiltered if we had a recognizable
539 # exception for filtered changeset access
553 # exception for filtered changeset access
540 if (repo.local()
554 if (repo.local()
541 and changeid in repo.unfiltered().dirstate.parents()):
555 and changeid in repo.unfiltered().dirstate.parents()):
542 msg = _("working directory has unknown parent '%s'!")
556 msg = _("working directory has unknown parent '%s'!")
543 raise error.Abort(msg % short(changeid))
557 raise error.Abort(msg % short(changeid))
544 try:
558 try:
545 if len(changeid) == 20 and nonascii(changeid):
559 if len(changeid) == 20 and nonascii(changeid):
546 changeid = hex(changeid)
560 changeid = hex(changeid)
547 except TypeError:
561 except TypeError:
548 pass
562 pass
549 except (error.FilteredIndexError, error.FilteredLookupError,
563 except (error.FilteredIndexError, error.FilteredLookupError,
550 error.FilteredRepoLookupError):
564 error.FilteredRepoLookupError):
551 raise _filterederror(repo, changeid)
565 raise _filterederror(repo, changeid)
552 except IndexError:
566 except IndexError:
553 pass
567 pass
554 raise error.RepoLookupError(
568 raise error.RepoLookupError(
555 _("unknown revision '%s'") % changeid)
569 _("unknown revision '%s'") % changeid)
556
570
557 def __hash__(self):
571 def __hash__(self):
558 try:
572 try:
559 return hash(self._rev)
573 return hash(self._rev)
560 except AttributeError:
574 except AttributeError:
561 return id(self)
575 return id(self)
562
576
563 def __nonzero__(self):
577 def __nonzero__(self):
564 return self._rev != nullrev
578 return self._rev != nullrev
565
579
566 __bool__ = __nonzero__
580 __bool__ = __nonzero__
567
581
568 @propertycache
582 @propertycache
569 def _changeset(self):
583 def _changeset(self):
570 return self._repo.changelog.changelogrevision(self.rev())
584 return self._repo.changelog.changelogrevision(self.rev())
571
585
572 @propertycache
586 @propertycache
573 def _manifest(self):
587 def _manifest(self):
574 return self._manifestctx.read()
588 return self._manifestctx.read()
575
589
576 @property
590 @property
577 def _manifestctx(self):
591 def _manifestctx(self):
578 return self._repo.manifestlog[self._changeset.manifest]
592 return self._repo.manifestlog[self._changeset.manifest]
579
593
580 @propertycache
594 @propertycache
581 def _manifestdelta(self):
595 def _manifestdelta(self):
582 return self._manifestctx.readdelta()
596 return self._manifestctx.readdelta()
583
597
584 @propertycache
598 @propertycache
585 def _parents(self):
599 def _parents(self):
586 repo = self._repo
600 repo = self._repo
587 p1, p2 = repo.changelog.parentrevs(self._rev)
601 p1, p2 = repo.changelog.parentrevs(self._rev)
588 if p2 == nullrev:
602 if p2 == nullrev:
589 return [changectx(repo, p1)]
603 return [changectx(repo, p1)]
590 return [changectx(repo, p1), changectx(repo, p2)]
604 return [changectx(repo, p1), changectx(repo, p2)]
591
605
592 def changeset(self):
606 def changeset(self):
593 c = self._changeset
607 c = self._changeset
594 return (
608 return (
595 c.manifest,
609 c.manifest,
596 c.user,
610 c.user,
597 c.date,
611 c.date,
598 c.files,
612 c.files,
599 c.description,
613 c.description,
600 c.extra,
614 c.extra,
601 )
615 )
602 def manifestnode(self):
616 def manifestnode(self):
603 return self._changeset.manifest
617 return self._changeset.manifest
604
618
605 def user(self):
619 def user(self):
606 return self._changeset.user
620 return self._changeset.user
607 def date(self):
621 def date(self):
608 return self._changeset.date
622 return self._changeset.date
609 def files(self):
623 def files(self):
610 return self._changeset.files
624 return self._changeset.files
611 def description(self):
625 def description(self):
612 return self._changeset.description
626 return self._changeset.description
613 def branch(self):
627 def branch(self):
614 return encoding.tolocal(self._changeset.extra.get("branch"))
628 return encoding.tolocal(self._changeset.extra.get("branch"))
615 def closesbranch(self):
629 def closesbranch(self):
616 return 'close' in self._changeset.extra
630 return 'close' in self._changeset.extra
617 def extra(self):
631 def extra(self):
618 """Return a dict of extra information."""
632 """Return a dict of extra information."""
619 return self._changeset.extra
633 return self._changeset.extra
620 def tags(self):
634 def tags(self):
621 """Return a list of byte tag names"""
635 """Return a list of byte tag names"""
622 return self._repo.nodetags(self._node)
636 return self._repo.nodetags(self._node)
623 def bookmarks(self):
637 def bookmarks(self):
624 """Return a list of byte bookmark names."""
638 """Return a list of byte bookmark names."""
625 return self._repo.nodebookmarks(self._node)
639 return self._repo.nodebookmarks(self._node)
626 def phase(self):
640 def phase(self):
627 return self._repo._phasecache.phase(self._repo, self._rev)
641 return self._repo._phasecache.phase(self._repo, self._rev)
628 def hidden(self):
642 def hidden(self):
629 return self._rev in repoview.filterrevs(self._repo, 'visible')
643 return self._rev in repoview.filterrevs(self._repo, 'visible')
630
644
631 def isinmemory(self):
645 def isinmemory(self):
632 return False
646 return False
633
647
634 def children(self):
648 def children(self):
635 """return list of changectx contexts for each child changeset.
649 """return list of changectx contexts for each child changeset.
636
650
637 This returns only the immediate child changesets. Use descendants() to
651 This returns only the immediate child changesets. Use descendants() to
638 recursively walk children.
652 recursively walk children.
639 """
653 """
640 c = self._repo.changelog.children(self._node)
654 c = self._repo.changelog.children(self._node)
641 return [changectx(self._repo, x) for x in c]
655 return [changectx(self._repo, x) for x in c]
642
656
643 def ancestors(self):
657 def ancestors(self):
644 for a in self._repo.changelog.ancestors([self._rev]):
658 for a in self._repo.changelog.ancestors([self._rev]):
645 yield changectx(self._repo, a)
659 yield changectx(self._repo, a)
646
660
647 def descendants(self):
661 def descendants(self):
648 """Recursively yield all children of the changeset.
662 """Recursively yield all children of the changeset.
649
663
650 For just the immediate children, use children()
664 For just the immediate children, use children()
651 """
665 """
652 for d in self._repo.changelog.descendants([self._rev]):
666 for d in self._repo.changelog.descendants([self._rev]):
653 yield changectx(self._repo, d)
667 yield changectx(self._repo, d)
654
668
655 def filectx(self, path, fileid=None, filelog=None):
669 def filectx(self, path, fileid=None, filelog=None):
656 """get a file context from this changeset"""
670 """get a file context from this changeset"""
657 if fileid is None:
671 if fileid is None:
658 fileid = self.filenode(path)
672 fileid = self.filenode(path)
659 return filectx(self._repo, path, fileid=fileid,
673 return filectx(self._repo, path, fileid=fileid,
660 changectx=self, filelog=filelog)
674 changectx=self, filelog=filelog)
661
675
662 def ancestor(self, c2, warn=False):
676 def ancestor(self, c2, warn=False):
663 """return the "best" ancestor context of self and c2
677 """return the "best" ancestor context of self and c2
664
678
665 If there are multiple candidates, it will show a message and check
679 If there are multiple candidates, it will show a message and check
666 merge.preferancestor configuration before falling back to the
680 merge.preferancestor configuration before falling back to the
667 revlog ancestor."""
681 revlog ancestor."""
668 # deal with workingctxs
682 # deal with workingctxs
669 n2 = c2._node
683 n2 = c2._node
670 if n2 is None:
684 if n2 is None:
671 n2 = c2._parents[0]._node
685 n2 = c2._parents[0]._node
672 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
686 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
673 if not cahs:
687 if not cahs:
674 anc = nullid
688 anc = nullid
675 elif len(cahs) == 1:
689 elif len(cahs) == 1:
676 anc = cahs[0]
690 anc = cahs[0]
677 else:
691 else:
678 # experimental config: merge.preferancestor
692 # experimental config: merge.preferancestor
679 for r in self._repo.ui.configlist('merge', 'preferancestor'):
693 for r in self._repo.ui.configlist('merge', 'preferancestor'):
680 try:
694 try:
681 ctx = changectx(self._repo, r)
695 ctx = changectx(self._repo, r)
682 except error.RepoLookupError:
696 except error.RepoLookupError:
683 continue
697 continue
684 anc = ctx.node()
698 anc = ctx.node()
685 if anc in cahs:
699 if anc in cahs:
686 break
700 break
687 else:
701 else:
688 anc = self._repo.changelog.ancestor(self._node, n2)
702 anc = self._repo.changelog.ancestor(self._node, n2)
689 if warn:
703 if warn:
690 self._repo.ui.status(
704 self._repo.ui.status(
691 (_("note: using %s as ancestor of %s and %s\n") %
705 (_("note: using %s as ancestor of %s and %s\n") %
692 (short(anc), short(self._node), short(n2))) +
706 (short(anc), short(self._node), short(n2))) +
693 ''.join(_(" alternatively, use --config "
707 ''.join(_(" alternatively, use --config "
694 "merge.preferancestor=%s\n") %
708 "merge.preferancestor=%s\n") %
695 short(n) for n in sorted(cahs) if n != anc))
709 short(n) for n in sorted(cahs) if n != anc))
696 return changectx(self._repo, anc)
710 return changectx(self._repo, anc)
697
711
698 def descendant(self, other):
712 def descendant(self, other):
699 """True if other is descendant of this changeset"""
713 """True if other is descendant of this changeset"""
700 return self._repo.changelog.descendant(self._rev, other._rev)
714 return self._repo.changelog.descendant(self._rev, other._rev)
701
715
702 def walk(self, match):
716 def walk(self, match):
703 '''Generates matching file names.'''
717 '''Generates matching file names.'''
704
718
705 # Wrap match.bad method to have message with nodeid
719 # Wrap match.bad method to have message with nodeid
706 def bad(fn, msg):
720 def bad(fn, msg):
707 # The manifest doesn't know about subrepos, so don't complain about
721 # The manifest doesn't know about subrepos, so don't complain about
708 # paths into valid subrepos.
722 # paths into valid subrepos.
709 if any(fn == s or fn.startswith(s + '/')
723 if any(fn == s or fn.startswith(s + '/')
710 for s in self.substate):
724 for s in self.substate):
711 return
725 return
712 match.bad(fn, _('no such file in rev %s') % self)
726 match.bad(fn, _('no such file in rev %s') % self)
713
727
714 m = matchmod.badmatch(match, bad)
728 m = matchmod.badmatch(match, bad)
715 return self._manifest.walk(m)
729 return self._manifest.walk(m)
716
730
717 def matches(self, match):
731 def matches(self, match):
718 return self.walk(match)
732 return self.walk(match)
719
733
720 class basefilectx(object):
734 class basefilectx(object):
721 """A filecontext object represents the common logic for its children:
735 """A filecontext object represents the common logic for its children:
722 filectx: read-only access to a filerevision that is already present
736 filectx: read-only access to a filerevision that is already present
723 in the repo,
737 in the repo,
724 workingfilectx: a filecontext that represents files from the working
738 workingfilectx: a filecontext that represents files from the working
725 directory,
739 directory,
726 memfilectx: a filecontext that represents files in-memory,
740 memfilectx: a filecontext that represents files in-memory,
727 overlayfilectx: duplicate another filecontext with some fields overridden.
741 overlayfilectx: duplicate another filecontext with some fields overridden.
728 """
742 """
729 @propertycache
743 @propertycache
730 def _filelog(self):
744 def _filelog(self):
731 return self._repo.file(self._path)
745 return self._repo.file(self._path)
732
746
733 @propertycache
747 @propertycache
734 def _changeid(self):
748 def _changeid(self):
735 if r'_changeid' in self.__dict__:
749 if r'_changeid' in self.__dict__:
736 return self._changeid
750 return self._changeid
737 elif r'_changectx' in self.__dict__:
751 elif r'_changectx' in self.__dict__:
738 return self._changectx.rev()
752 return self._changectx.rev()
739 elif r'_descendantrev' in self.__dict__:
753 elif r'_descendantrev' in self.__dict__:
740 # this file context was created from a revision with a known
754 # this file context was created from a revision with a known
741 # descendant, we can (lazily) correct for linkrev aliases
755 # descendant, we can (lazily) correct for linkrev aliases
742 return self._adjustlinkrev(self._descendantrev)
756 return self._adjustlinkrev(self._descendantrev)
743 else:
757 else:
744 return self._filelog.linkrev(self._filerev)
758 return self._filelog.linkrev(self._filerev)
745
759
746 @propertycache
760 @propertycache
747 def _filenode(self):
761 def _filenode(self):
748 if r'_fileid' in self.__dict__:
762 if r'_fileid' in self.__dict__:
749 return self._filelog.lookup(self._fileid)
763 return self._filelog.lookup(self._fileid)
750 else:
764 else:
751 return self._changectx.filenode(self._path)
765 return self._changectx.filenode(self._path)
752
766
753 @propertycache
767 @propertycache
754 def _filerev(self):
768 def _filerev(self):
755 return self._filelog.rev(self._filenode)
769 return self._filelog.rev(self._filenode)
756
770
757 @propertycache
771 @propertycache
758 def _repopath(self):
772 def _repopath(self):
759 return self._path
773 return self._path
760
774
761 def __nonzero__(self):
775 def __nonzero__(self):
762 try:
776 try:
763 self._filenode
777 self._filenode
764 return True
778 return True
765 except error.LookupError:
779 except error.LookupError:
766 # file is missing
780 # file is missing
767 return False
781 return False
768
782
769 __bool__ = __nonzero__
783 __bool__ = __nonzero__
770
784
771 def __bytes__(self):
785 def __bytes__(self):
772 try:
786 try:
773 return "%s@%s" % (self.path(), self._changectx)
787 return "%s@%s" % (self.path(), self._changectx)
774 except error.LookupError:
788 except error.LookupError:
775 return "%s@???" % self.path()
789 return "%s@???" % self.path()
776
790
777 __str__ = encoding.strmethod(__bytes__)
791 __str__ = encoding.strmethod(__bytes__)
778
792
779 def __repr__(self):
793 def __repr__(self):
780 return "<%s %s>" % (type(self).__name__, str(self))
794 return "<%s %s>" % (type(self).__name__, str(self))
781
795
782 def __hash__(self):
796 def __hash__(self):
783 try:
797 try:
784 return hash((self._path, self._filenode))
798 return hash((self._path, self._filenode))
785 except AttributeError:
799 except AttributeError:
786 return id(self)
800 return id(self)
787
801
788 def __eq__(self, other):
802 def __eq__(self, other):
789 try:
803 try:
790 return (type(self) == type(other) and self._path == other._path
804 return (type(self) == type(other) and self._path == other._path
791 and self._filenode == other._filenode)
805 and self._filenode == other._filenode)
792 except AttributeError:
806 except AttributeError:
793 return False
807 return False
794
808
795 def __ne__(self, other):
809 def __ne__(self, other):
796 return not (self == other)
810 return not (self == other)
797
811
798 def filerev(self):
812 def filerev(self):
799 return self._filerev
813 return self._filerev
800 def filenode(self):
814 def filenode(self):
801 return self._filenode
815 return self._filenode
802 @propertycache
816 @propertycache
803 def _flags(self):
817 def _flags(self):
804 return self._changectx.flags(self._path)
818 return self._changectx.flags(self._path)
805 def flags(self):
819 def flags(self):
806 return self._flags
820 return self._flags
807 def filelog(self):
821 def filelog(self):
808 return self._filelog
822 return self._filelog
809 def rev(self):
823 def rev(self):
810 return self._changeid
824 return self._changeid
811 def linkrev(self):
825 def linkrev(self):
812 return self._filelog.linkrev(self._filerev)
826 return self._filelog.linkrev(self._filerev)
813 def node(self):
827 def node(self):
814 return self._changectx.node()
828 return self._changectx.node()
815 def hex(self):
829 def hex(self):
816 return self._changectx.hex()
830 return self._changectx.hex()
817 def user(self):
831 def user(self):
818 return self._changectx.user()
832 return self._changectx.user()
819 def date(self):
833 def date(self):
820 return self._changectx.date()
834 return self._changectx.date()
821 def files(self):
835 def files(self):
822 return self._changectx.files()
836 return self._changectx.files()
823 def description(self):
837 def description(self):
824 return self._changectx.description()
838 return self._changectx.description()
825 def branch(self):
839 def branch(self):
826 return self._changectx.branch()
840 return self._changectx.branch()
827 def extra(self):
841 def extra(self):
828 return self._changectx.extra()
842 return self._changectx.extra()
829 def phase(self):
843 def phase(self):
830 return self._changectx.phase()
844 return self._changectx.phase()
831 def phasestr(self):
845 def phasestr(self):
832 return self._changectx.phasestr()
846 return self._changectx.phasestr()
833 def obsolete(self):
847 def obsolete(self):
834 return self._changectx.obsolete()
848 return self._changectx.obsolete()
835 def instabilities(self):
849 def instabilities(self):
836 return self._changectx.instabilities()
850 return self._changectx.instabilities()
837 def manifest(self):
851 def manifest(self):
838 return self._changectx.manifest()
852 return self._changectx.manifest()
839 def changectx(self):
853 def changectx(self):
840 return self._changectx
854 return self._changectx
841 def renamed(self):
855 def renamed(self):
842 return self._copied
856 return self._copied
843 def repo(self):
857 def repo(self):
844 return self._repo
858 return self._repo
845 def size(self):
859 def size(self):
846 return len(self.data())
860 return len(self.data())
847
861
848 def path(self):
862 def path(self):
849 return self._path
863 return self._path
850
864
851 def isbinary(self):
865 def isbinary(self):
852 try:
866 try:
853 return util.binary(self.data())
867 return util.binary(self.data())
854 except IOError:
868 except IOError:
855 return False
869 return False
856 def isexec(self):
870 def isexec(self):
857 return 'x' in self.flags()
871 return 'x' in self.flags()
858 def islink(self):
872 def islink(self):
859 return 'l' in self.flags()
873 return 'l' in self.flags()
860
874
861 def isabsent(self):
875 def isabsent(self):
862 """whether this filectx represents a file not in self._changectx
876 """whether this filectx represents a file not in self._changectx
863
877
864 This is mainly for merge code to detect change/delete conflicts. This is
878 This is mainly for merge code to detect change/delete conflicts. This is
865 expected to be True for all subclasses of basectx."""
879 expected to be True for all subclasses of basectx."""
866 return False
880 return False
867
881
868 _customcmp = False
882 _customcmp = False
869 def cmp(self, fctx):
883 def cmp(self, fctx):
870 """compare with other file context
884 """compare with other file context
871
885
872 returns True if different than fctx.
886 returns True if different than fctx.
873 """
887 """
874 if fctx._customcmp:
888 if fctx._customcmp:
875 return fctx.cmp(self)
889 return fctx.cmp(self)
876
890
877 if (fctx._filenode is None
891 if (fctx._filenode is None
878 and (self._repo._encodefilterpats
892 and (self._repo._encodefilterpats
879 # if file data starts with '\1\n', empty metadata block is
893 # if file data starts with '\1\n', empty metadata block is
880 # prepended, which adds 4 bytes to filelog.size().
894 # prepended, which adds 4 bytes to filelog.size().
881 or self.size() - 4 == fctx.size())
895 or self.size() - 4 == fctx.size())
882 or self.size() == fctx.size()):
896 or self.size() == fctx.size()):
883 return self._filelog.cmp(self._filenode, fctx.data())
897 return self._filelog.cmp(self._filenode, fctx.data())
884
898
885 return True
899 return True
886
900
887 def _adjustlinkrev(self, srcrev, inclusive=False):
901 def _adjustlinkrev(self, srcrev, inclusive=False):
888 """return the first ancestor of <srcrev> introducing <fnode>
902 """return the first ancestor of <srcrev> introducing <fnode>
889
903
890 If the linkrev of the file revision does not point to an ancestor of
904 If the linkrev of the file revision does not point to an ancestor of
891 srcrev, we'll walk down the ancestors until we find one introducing
905 srcrev, we'll walk down the ancestors until we find one introducing
892 this file revision.
906 this file revision.
893
907
894 :srcrev: the changeset revision we search ancestors from
908 :srcrev: the changeset revision we search ancestors from
895 :inclusive: if true, the src revision will also be checked
909 :inclusive: if true, the src revision will also be checked
896 """
910 """
897 repo = self._repo
911 repo = self._repo
898 cl = repo.unfiltered().changelog
912 cl = repo.unfiltered().changelog
899 mfl = repo.manifestlog
913 mfl = repo.manifestlog
900 # fetch the linkrev
914 # fetch the linkrev
901 lkr = self.linkrev()
915 lkr = self.linkrev()
902 # hack to reuse ancestor computation when searching for renames
916 # hack to reuse ancestor computation when searching for renames
903 memberanc = getattr(self, '_ancestrycontext', None)
917 memberanc = getattr(self, '_ancestrycontext', None)
904 iteranc = None
918 iteranc = None
905 if srcrev is None:
919 if srcrev is None:
906 # wctx case, used by workingfilectx during mergecopy
920 # wctx case, used by workingfilectx during mergecopy
907 revs = [p.rev() for p in self._repo[None].parents()]
921 revs = [p.rev() for p in self._repo[None].parents()]
908 inclusive = True # we skipped the real (revless) source
922 inclusive = True # we skipped the real (revless) source
909 else:
923 else:
910 revs = [srcrev]
924 revs = [srcrev]
911 if memberanc is None:
925 if memberanc is None:
912 memberanc = iteranc = cl.ancestors(revs, lkr,
926 memberanc = iteranc = cl.ancestors(revs, lkr,
913 inclusive=inclusive)
927 inclusive=inclusive)
914 # check if this linkrev is an ancestor of srcrev
928 # check if this linkrev is an ancestor of srcrev
915 if lkr not in memberanc:
929 if lkr not in memberanc:
916 if iteranc is None:
930 if iteranc is None:
917 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
931 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
918 fnode = self._filenode
932 fnode = self._filenode
919 path = self._path
933 path = self._path
920 for a in iteranc:
934 for a in iteranc:
921 ac = cl.read(a) # get changeset data (we avoid object creation)
935 ac = cl.read(a) # get changeset data (we avoid object creation)
922 if path in ac[3]: # checking the 'files' field.
936 if path in ac[3]: # checking the 'files' field.
923 # The file has been touched, check if the content is
937 # The file has been touched, check if the content is
924 # similar to the one we search for.
938 # similar to the one we search for.
925 if fnode == mfl[ac[0]].readfast().get(path):
939 if fnode == mfl[ac[0]].readfast().get(path):
926 return a
940 return a
927 # In theory, we should never get out of that loop without a result.
941 # In theory, we should never get out of that loop without a result.
928 # But if manifest uses a buggy file revision (not children of the
942 # But if manifest uses a buggy file revision (not children of the
929 # one it replaces) we could. Such a buggy situation will likely
943 # one it replaces) we could. Such a buggy situation will likely
930 # result is crash somewhere else at to some point.
944 # result is crash somewhere else at to some point.
931 return lkr
945 return lkr
932
946
933 def introrev(self):
947 def introrev(self):
934 """return the rev of the changeset which introduced this file revision
948 """return the rev of the changeset which introduced this file revision
935
949
936 This method is different from linkrev because it take into account the
950 This method is different from linkrev because it take into account the
937 changeset the filectx was created from. It ensures the returned
951 changeset the filectx was created from. It ensures the returned
938 revision is one of its ancestors. This prevents bugs from
952 revision is one of its ancestors. This prevents bugs from
939 'linkrev-shadowing' when a file revision is used by multiple
953 'linkrev-shadowing' when a file revision is used by multiple
940 changesets.
954 changesets.
941 """
955 """
942 lkr = self.linkrev()
956 lkr = self.linkrev()
943 attrs = vars(self)
957 attrs = vars(self)
944 noctx = not ('_changeid' in attrs or '_changectx' in attrs)
958 noctx = not ('_changeid' in attrs or '_changectx' in attrs)
945 if noctx or self.rev() == lkr:
959 if noctx or self.rev() == lkr:
946 return self.linkrev()
960 return self.linkrev()
947 return self._adjustlinkrev(self.rev(), inclusive=True)
961 return self._adjustlinkrev(self.rev(), inclusive=True)
948
962
949 def introfilectx(self):
963 def introfilectx(self):
950 """Return filectx having identical contents, but pointing to the
964 """Return filectx having identical contents, but pointing to the
951 changeset revision where this filectx was introduced"""
965 changeset revision where this filectx was introduced"""
952 introrev = self.introrev()
966 introrev = self.introrev()
953 if self.rev() == introrev:
967 if self.rev() == introrev:
954 return self
968 return self
955 return self.filectx(self.filenode(), changeid=introrev)
969 return self.filectx(self.filenode(), changeid=introrev)
956
970
957 def _parentfilectx(self, path, fileid, filelog):
971 def _parentfilectx(self, path, fileid, filelog):
958 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
972 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
959 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
973 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
960 if '_changeid' in vars(self) or '_changectx' in vars(self):
974 if '_changeid' in vars(self) or '_changectx' in vars(self):
961 # If self is associated with a changeset (probably explicitly
975 # If self is associated with a changeset (probably explicitly
962 # fed), ensure the created filectx is associated with a
976 # fed), ensure the created filectx is associated with a
963 # changeset that is an ancestor of self.changectx.
977 # changeset that is an ancestor of self.changectx.
964 # This lets us later use _adjustlinkrev to get a correct link.
978 # This lets us later use _adjustlinkrev to get a correct link.
965 fctx._descendantrev = self.rev()
979 fctx._descendantrev = self.rev()
966 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
980 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
967 elif '_descendantrev' in vars(self):
981 elif '_descendantrev' in vars(self):
968 # Otherwise propagate _descendantrev if we have one associated.
982 # Otherwise propagate _descendantrev if we have one associated.
969 fctx._descendantrev = self._descendantrev
983 fctx._descendantrev = self._descendantrev
970 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
984 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
971 return fctx
985 return fctx
972
986
973 def parents(self):
987 def parents(self):
974 _path = self._path
988 _path = self._path
975 fl = self._filelog
989 fl = self._filelog
976 parents = self._filelog.parents(self._filenode)
990 parents = self._filelog.parents(self._filenode)
977 pl = [(_path, node, fl) for node in parents if node != nullid]
991 pl = [(_path, node, fl) for node in parents if node != nullid]
978
992
979 r = fl.renamed(self._filenode)
993 r = fl.renamed(self._filenode)
980 if r:
994 if r:
981 # - In the simple rename case, both parent are nullid, pl is empty.
995 # - In the simple rename case, both parent are nullid, pl is empty.
982 # - In case of merge, only one of the parent is null id and should
996 # - In case of merge, only one of the parent is null id and should
983 # be replaced with the rename information. This parent is -always-
997 # be replaced with the rename information. This parent is -always-
984 # the first one.
998 # the first one.
985 #
999 #
986 # As null id have always been filtered out in the previous list
1000 # As null id have always been filtered out in the previous list
987 # comprehension, inserting to 0 will always result in "replacing
1001 # comprehension, inserting to 0 will always result in "replacing
988 # first nullid parent with rename information.
1002 # first nullid parent with rename information.
989 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
1003 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
990
1004
991 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
1005 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
992
1006
993 def p1(self):
1007 def p1(self):
994 return self.parents()[0]
1008 return self.parents()[0]
995
1009
996 def p2(self):
1010 def p2(self):
997 p = self.parents()
1011 p = self.parents()
998 if len(p) == 2:
1012 if len(p) == 2:
999 return p[1]
1013 return p[1]
1000 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
1014 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
1001
1015
1002 def annotate(self, follow=False, linenumber=False, skiprevs=None,
1016 def annotate(self, follow=False, linenumber=False, skiprevs=None,
1003 diffopts=None):
1017 diffopts=None):
1004 '''returns a list of tuples of ((ctx, number), line) for each line
1018 '''returns a list of tuples of ((ctx, number), line) for each line
1005 in the file, where ctx is the filectx of the node where
1019 in the file, where ctx is the filectx of the node where
1006 that line was last changed; if linenumber parameter is true, number is
1020 that line was last changed; if linenumber parameter is true, number is
1007 the line number at the first appearance in the managed file, otherwise,
1021 the line number at the first appearance in the managed file, otherwise,
1008 number has a fixed value of False.
1022 number has a fixed value of False.
1009 '''
1023 '''
1010
1024
1011 def lines(text):
1025 def lines(text):
1012 if text.endswith("\n"):
1026 if text.endswith("\n"):
1013 return text.count("\n")
1027 return text.count("\n")
1014 return text.count("\n") + int(bool(text))
1028 return text.count("\n") + int(bool(text))
1015
1029
1016 if linenumber:
1030 if linenumber:
1017 def decorate(text, rev):
1031 def decorate(text, rev):
1018 return ([annotateline(fctx=rev, lineno=i)
1032 return ([annotateline(fctx=rev, lineno=i)
1019 for i in xrange(1, lines(text) + 1)], text)
1033 for i in xrange(1, lines(text) + 1)], text)
1020 else:
1034 else:
1021 def decorate(text, rev):
1035 def decorate(text, rev):
1022 return ([annotateline(fctx=rev)] * lines(text), text)
1036 return ([annotateline(fctx=rev)] * lines(text), text)
1023
1037
1024 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
1038 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
1025
1039
1026 def parents(f):
1040 def parents(f):
1027 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
1041 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
1028 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
1042 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
1029 # from the topmost introrev (= srcrev) down to p.linkrev() if it
1043 # from the topmost introrev (= srcrev) down to p.linkrev() if it
1030 # isn't an ancestor of the srcrev.
1044 # isn't an ancestor of the srcrev.
1031 f._changeid
1045 f._changeid
1032 pl = f.parents()
1046 pl = f.parents()
1033
1047
1034 # Don't return renamed parents if we aren't following.
1048 # Don't return renamed parents if we aren't following.
1035 if not follow:
1049 if not follow:
1036 pl = [p for p in pl if p.path() == f.path()]
1050 pl = [p for p in pl if p.path() == f.path()]
1037
1051
1038 # renamed filectx won't have a filelog yet, so set it
1052 # renamed filectx won't have a filelog yet, so set it
1039 # from the cache to save time
1053 # from the cache to save time
1040 for p in pl:
1054 for p in pl:
1041 if not '_filelog' in p.__dict__:
1055 if not '_filelog' in p.__dict__:
1042 p._filelog = getlog(p.path())
1056 p._filelog = getlog(p.path())
1043
1057
1044 return pl
1058 return pl
1045
1059
1046 # use linkrev to find the first changeset where self appeared
1060 # use linkrev to find the first changeset where self appeared
1047 base = self.introfilectx()
1061 base = self.introfilectx()
1048 if getattr(base, '_ancestrycontext', None) is None:
1062 if getattr(base, '_ancestrycontext', None) is None:
1049 cl = self._repo.changelog
1063 cl = self._repo.changelog
1050 if base.rev() is None:
1064 if base.rev() is None:
1051 # wctx is not inclusive, but works because _ancestrycontext
1065 # wctx is not inclusive, but works because _ancestrycontext
1052 # is used to test filelog revisions
1066 # is used to test filelog revisions
1053 ac = cl.ancestors([p.rev() for p in base.parents()],
1067 ac = cl.ancestors([p.rev() for p in base.parents()],
1054 inclusive=True)
1068 inclusive=True)
1055 else:
1069 else:
1056 ac = cl.ancestors([base.rev()], inclusive=True)
1070 ac = cl.ancestors([base.rev()], inclusive=True)
1057 base._ancestrycontext = ac
1071 base._ancestrycontext = ac
1058
1072
1059 # This algorithm would prefer to be recursive, but Python is a
1073 # This algorithm would prefer to be recursive, but Python is a
1060 # bit recursion-hostile. Instead we do an iterative
1074 # bit recursion-hostile. Instead we do an iterative
1061 # depth-first search.
1075 # depth-first search.
1062
1076
1063 # 1st DFS pre-calculates pcache and needed
1077 # 1st DFS pre-calculates pcache and needed
1064 visit = [base]
1078 visit = [base]
1065 pcache = {}
1079 pcache = {}
1066 needed = {base: 1}
1080 needed = {base: 1}
1067 while visit:
1081 while visit:
1068 f = visit.pop()
1082 f = visit.pop()
1069 if f in pcache:
1083 if f in pcache:
1070 continue
1084 continue
1071 pl = parents(f)
1085 pl = parents(f)
1072 pcache[f] = pl
1086 pcache[f] = pl
1073 for p in pl:
1087 for p in pl:
1074 needed[p] = needed.get(p, 0) + 1
1088 needed[p] = needed.get(p, 0) + 1
1075 if p not in pcache:
1089 if p not in pcache:
1076 visit.append(p)
1090 visit.append(p)
1077
1091
1078 # 2nd DFS does the actual annotate
1092 # 2nd DFS does the actual annotate
1079 visit[:] = [base]
1093 visit[:] = [base]
1080 hist = {}
1094 hist = {}
1081 while visit:
1095 while visit:
1082 f = visit[-1]
1096 f = visit[-1]
1083 if f in hist:
1097 if f in hist:
1084 visit.pop()
1098 visit.pop()
1085 continue
1099 continue
1086
1100
1087 ready = True
1101 ready = True
1088 pl = pcache[f]
1102 pl = pcache[f]
1089 for p in pl:
1103 for p in pl:
1090 if p not in hist:
1104 if p not in hist:
1091 ready = False
1105 ready = False
1092 visit.append(p)
1106 visit.append(p)
1093 if ready:
1107 if ready:
1094 visit.pop()
1108 visit.pop()
1095 curr = decorate(f.data(), f)
1109 curr = decorate(f.data(), f)
1096 skipchild = False
1110 skipchild = False
1097 if skiprevs is not None:
1111 if skiprevs is not None:
1098 skipchild = f._changeid in skiprevs
1112 skipchild = f._changeid in skiprevs
1099 curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild,
1113 curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild,
1100 diffopts)
1114 diffopts)
1101 for p in pl:
1115 for p in pl:
1102 if needed[p] == 1:
1116 if needed[p] == 1:
1103 del hist[p]
1117 del hist[p]
1104 del needed[p]
1118 del needed[p]
1105 else:
1119 else:
1106 needed[p] -= 1
1120 needed[p] -= 1
1107
1121
1108 hist[f] = curr
1122 hist[f] = curr
1109 del pcache[f]
1123 del pcache[f]
1110
1124
1111 return zip(hist[base][0], hist[base][1].splitlines(True))
1125 return zip(hist[base][0], hist[base][1].splitlines(True))
1112
1126
1113 def ancestors(self, followfirst=False):
1127 def ancestors(self, followfirst=False):
1114 visit = {}
1128 visit = {}
1115 c = self
1129 c = self
1116 if followfirst:
1130 if followfirst:
1117 cut = 1
1131 cut = 1
1118 else:
1132 else:
1119 cut = None
1133 cut = None
1120
1134
1121 while True:
1135 while True:
1122 for parent in c.parents()[:cut]:
1136 for parent in c.parents()[:cut]:
1123 visit[(parent.linkrev(), parent.filenode())] = parent
1137 visit[(parent.linkrev(), parent.filenode())] = parent
1124 if not visit:
1138 if not visit:
1125 break
1139 break
1126 c = visit.pop(max(visit))
1140 c = visit.pop(max(visit))
1127 yield c
1141 yield c
1128
1142
1129 def decodeddata(self):
1143 def decodeddata(self):
1130 """Returns `data()` after running repository decoding filters.
1144 """Returns `data()` after running repository decoding filters.
1131
1145
1132 This is often equivalent to how the data would be expressed on disk.
1146 This is often equivalent to how the data would be expressed on disk.
1133 """
1147 """
1134 return self._repo.wwritedata(self.path(), self.data())
1148 return self._repo.wwritedata(self.path(), self.data())
1135
1149
1136 @attr.s(slots=True, frozen=True)
1150 @attr.s(slots=True, frozen=True)
1137 class annotateline(object):
1151 class annotateline(object):
1138 fctx = attr.ib()
1152 fctx = attr.ib()
1139 lineno = attr.ib(default=False)
1153 lineno = attr.ib(default=False)
1140 # Whether this annotation was the result of a skip-annotate.
1154 # Whether this annotation was the result of a skip-annotate.
1141 skip = attr.ib(default=False)
1155 skip = attr.ib(default=False)
1142
1156
1143 def _annotatepair(parents, childfctx, child, skipchild, diffopts):
1157 def _annotatepair(parents, childfctx, child, skipchild, diffopts):
1144 r'''
1158 r'''
1145 Given parent and child fctxes and annotate data for parents, for all lines
1159 Given parent and child fctxes and annotate data for parents, for all lines
1146 in either parent that match the child, annotate the child with the parent's
1160 in either parent that match the child, annotate the child with the parent's
1147 data.
1161 data.
1148
1162
1149 Additionally, if `skipchild` is True, replace all other lines with parent
1163 Additionally, if `skipchild` is True, replace all other lines with parent
1150 annotate data as well such that child is never blamed for any lines.
1164 annotate data as well such that child is never blamed for any lines.
1151
1165
1152 See test-annotate.py for unit tests.
1166 See test-annotate.py for unit tests.
1153 '''
1167 '''
1154 pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts))
1168 pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts))
1155 for parent in parents]
1169 for parent in parents]
1156
1170
1157 if skipchild:
1171 if skipchild:
1158 # Need to iterate over the blocks twice -- make it a list
1172 # Need to iterate over the blocks twice -- make it a list
1159 pblocks = [(p, list(blocks)) for (p, blocks) in pblocks]
1173 pblocks = [(p, list(blocks)) for (p, blocks) in pblocks]
1160 # Mercurial currently prefers p2 over p1 for annotate.
1174 # Mercurial currently prefers p2 over p1 for annotate.
1161 # TODO: change this?
1175 # TODO: change this?
1162 for parent, blocks in pblocks:
1176 for parent, blocks in pblocks:
1163 for (a1, a2, b1, b2), t in blocks:
1177 for (a1, a2, b1, b2), t in blocks:
1164 # Changed blocks ('!') or blocks made only of blank lines ('~')
1178 # Changed blocks ('!') or blocks made only of blank lines ('~')
1165 # belong to the child.
1179 # belong to the child.
1166 if t == '=':
1180 if t == '=':
1167 child[0][b1:b2] = parent[0][a1:a2]
1181 child[0][b1:b2] = parent[0][a1:a2]
1168
1182
1169 if skipchild:
1183 if skipchild:
1170 # Now try and match up anything that couldn't be matched,
1184 # Now try and match up anything that couldn't be matched,
1171 # Reversing pblocks maintains bias towards p2, matching above
1185 # Reversing pblocks maintains bias towards p2, matching above
1172 # behavior.
1186 # behavior.
1173 pblocks.reverse()
1187 pblocks.reverse()
1174
1188
1175 # The heuristics are:
1189 # The heuristics are:
1176 # * Work on blocks of changed lines (effectively diff hunks with -U0).
1190 # * Work on blocks of changed lines (effectively diff hunks with -U0).
1177 # This could potentially be smarter but works well enough.
1191 # This could potentially be smarter but works well enough.
1178 # * For a non-matching section, do a best-effort fit. Match lines in
1192 # * For a non-matching section, do a best-effort fit. Match lines in
1179 # diff hunks 1:1, dropping lines as necessary.
1193 # diff hunks 1:1, dropping lines as necessary.
1180 # * Repeat the last line as a last resort.
1194 # * Repeat the last line as a last resort.
1181
1195
1182 # First, replace as much as possible without repeating the last line.
1196 # First, replace as much as possible without repeating the last line.
1183 remaining = [(parent, []) for parent, _blocks in pblocks]
1197 remaining = [(parent, []) for parent, _blocks in pblocks]
1184 for idx, (parent, blocks) in enumerate(pblocks):
1198 for idx, (parent, blocks) in enumerate(pblocks):
1185 for (a1, a2, b1, b2), _t in blocks:
1199 for (a1, a2, b1, b2), _t in blocks:
1186 if a2 - a1 >= b2 - b1:
1200 if a2 - a1 >= b2 - b1:
1187 for bk in xrange(b1, b2):
1201 for bk in xrange(b1, b2):
1188 if child[0][bk].fctx == childfctx:
1202 if child[0][bk].fctx == childfctx:
1189 ak = min(a1 + (bk - b1), a2 - 1)
1203 ak = min(a1 + (bk - b1), a2 - 1)
1190 child[0][bk] = attr.evolve(parent[0][ak], skip=True)
1204 child[0][bk] = attr.evolve(parent[0][ak], skip=True)
1191 else:
1205 else:
1192 remaining[idx][1].append((a1, a2, b1, b2))
1206 remaining[idx][1].append((a1, a2, b1, b2))
1193
1207
1194 # Then, look at anything left, which might involve repeating the last
1208 # Then, look at anything left, which might involve repeating the last
1195 # line.
1209 # line.
1196 for parent, blocks in remaining:
1210 for parent, blocks in remaining:
1197 for a1, a2, b1, b2 in blocks:
1211 for a1, a2, b1, b2 in blocks:
1198 for bk in xrange(b1, b2):
1212 for bk in xrange(b1, b2):
1199 if child[0][bk].fctx == childfctx:
1213 if child[0][bk].fctx == childfctx:
1200 ak = min(a1 + (bk - b1), a2 - 1)
1214 ak = min(a1 + (bk - b1), a2 - 1)
1201 child[0][bk] = attr.evolve(parent[0][ak], skip=True)
1215 child[0][bk] = attr.evolve(parent[0][ak], skip=True)
1202 return child
1216 return child
1203
1217
1204 class filectx(basefilectx):
1218 class filectx(basefilectx):
1205 """A filecontext object makes access to data related to a particular
1219 """A filecontext object makes access to data related to a particular
1206 filerevision convenient."""
1220 filerevision convenient."""
1207 def __init__(self, repo, path, changeid=None, fileid=None,
1221 def __init__(self, repo, path, changeid=None, fileid=None,
1208 filelog=None, changectx=None):
1222 filelog=None, changectx=None):
1209 """changeid can be a changeset revision, node, or tag.
1223 """changeid can be a changeset revision, node, or tag.
1210 fileid can be a file revision or node."""
1224 fileid can be a file revision or node."""
1211 self._repo = repo
1225 self._repo = repo
1212 self._path = path
1226 self._path = path
1213
1227
1214 assert (changeid is not None
1228 assert (changeid is not None
1215 or fileid is not None
1229 or fileid is not None
1216 or changectx is not None), \
1230 or changectx is not None), \
1217 ("bad args: changeid=%r, fileid=%r, changectx=%r"
1231 ("bad args: changeid=%r, fileid=%r, changectx=%r"
1218 % (changeid, fileid, changectx))
1232 % (changeid, fileid, changectx))
1219
1233
1220 if filelog is not None:
1234 if filelog is not None:
1221 self._filelog = filelog
1235 self._filelog = filelog
1222
1236
1223 if changeid is not None:
1237 if changeid is not None:
1224 self._changeid = changeid
1238 self._changeid = changeid
1225 if changectx is not None:
1239 if changectx is not None:
1226 self._changectx = changectx
1240 self._changectx = changectx
1227 if fileid is not None:
1241 if fileid is not None:
1228 self._fileid = fileid
1242 self._fileid = fileid
1229
1243
1230 @propertycache
1244 @propertycache
1231 def _changectx(self):
1245 def _changectx(self):
1232 try:
1246 try:
1233 return changectx(self._repo, self._changeid)
1247 return changectx(self._repo, self._changeid)
1234 except error.FilteredRepoLookupError:
1248 except error.FilteredRepoLookupError:
1235 # Linkrev may point to any revision in the repository. When the
1249 # Linkrev may point to any revision in the repository. When the
1236 # repository is filtered this may lead to `filectx` trying to build
1250 # repository is filtered this may lead to `filectx` trying to build
1237 # `changectx` for filtered revision. In such case we fallback to
1251 # `changectx` for filtered revision. In such case we fallback to
1238 # creating `changectx` on the unfiltered version of the reposition.
1252 # creating `changectx` on the unfiltered version of the reposition.
1239 # This fallback should not be an issue because `changectx` from
1253 # This fallback should not be an issue because `changectx` from
1240 # `filectx` are not used in complex operations that care about
1254 # `filectx` are not used in complex operations that care about
1241 # filtering.
1255 # filtering.
1242 #
1256 #
1243 # This fallback is a cheap and dirty fix that prevent several
1257 # This fallback is a cheap and dirty fix that prevent several
1244 # crashes. It does not ensure the behavior is correct. However the
1258 # crashes. It does not ensure the behavior is correct. However the
1245 # behavior was not correct before filtering either and "incorrect
1259 # behavior was not correct before filtering either and "incorrect
1246 # behavior" is seen as better as "crash"
1260 # behavior" is seen as better as "crash"
1247 #
1261 #
1248 # Linkrevs have several serious troubles with filtering that are
1262 # Linkrevs have several serious troubles with filtering that are
1249 # complicated to solve. Proper handling of the issue here should be
1263 # complicated to solve. Proper handling of the issue here should be
1250 # considered when solving linkrev issue are on the table.
1264 # considered when solving linkrev issue are on the table.
1251 return changectx(self._repo.unfiltered(), self._changeid)
1265 return changectx(self._repo.unfiltered(), self._changeid)
1252
1266
1253 def filectx(self, fileid, changeid=None):
1267 def filectx(self, fileid, changeid=None):
1254 '''opens an arbitrary revision of the file without
1268 '''opens an arbitrary revision of the file without
1255 opening a new filelog'''
1269 opening a new filelog'''
1256 return filectx(self._repo, self._path, fileid=fileid,
1270 return filectx(self._repo, self._path, fileid=fileid,
1257 filelog=self._filelog, changeid=changeid)
1271 filelog=self._filelog, changeid=changeid)
1258
1272
1259 def rawdata(self):
1273 def rawdata(self):
1260 return self._filelog.revision(self._filenode, raw=True)
1274 return self._filelog.revision(self._filenode, raw=True)
1261
1275
1262 def rawflags(self):
1276 def rawflags(self):
1263 """low-level revlog flags"""
1277 """low-level revlog flags"""
1264 return self._filelog.flags(self._filerev)
1278 return self._filelog.flags(self._filerev)
1265
1279
1266 def data(self):
1280 def data(self):
1267 try:
1281 try:
1268 return self._filelog.read(self._filenode)
1282 return self._filelog.read(self._filenode)
1269 except error.CensoredNodeError:
1283 except error.CensoredNodeError:
1270 if self._repo.ui.config("censor", "policy") == "ignore":
1284 if self._repo.ui.config("censor", "policy") == "ignore":
1271 return ""
1285 return ""
1272 raise error.Abort(_("censored node: %s") % short(self._filenode),
1286 raise error.Abort(_("censored node: %s") % short(self._filenode),
1273 hint=_("set censor.policy to ignore errors"))
1287 hint=_("set censor.policy to ignore errors"))
1274
1288
1275 def size(self):
1289 def size(self):
1276 return self._filelog.size(self._filerev)
1290 return self._filelog.size(self._filerev)
1277
1291
1278 @propertycache
1292 @propertycache
1279 def _copied(self):
1293 def _copied(self):
1280 """check if file was actually renamed in this changeset revision
1294 """check if file was actually renamed in this changeset revision
1281
1295
1282 If rename logged in file revision, we report copy for changeset only
1296 If rename logged in file revision, we report copy for changeset only
1283 if file revisions linkrev points back to the changeset in question
1297 if file revisions linkrev points back to the changeset in question
1284 or both changeset parents contain different file revisions.
1298 or both changeset parents contain different file revisions.
1285 """
1299 """
1286
1300
1287 renamed = self._filelog.renamed(self._filenode)
1301 renamed = self._filelog.renamed(self._filenode)
1288 if not renamed:
1302 if not renamed:
1289 return renamed
1303 return renamed
1290
1304
1291 if self.rev() == self.linkrev():
1305 if self.rev() == self.linkrev():
1292 return renamed
1306 return renamed
1293
1307
1294 name = self.path()
1308 name = self.path()
1295 fnode = self._filenode
1309 fnode = self._filenode
1296 for p in self._changectx.parents():
1310 for p in self._changectx.parents():
1297 try:
1311 try:
1298 if fnode == p.filenode(name):
1312 if fnode == p.filenode(name):
1299 return None
1313 return None
1300 except error.LookupError:
1314 except error.LookupError:
1301 pass
1315 pass
1302 return renamed
1316 return renamed
1303
1317
1304 def children(self):
1318 def children(self):
1305 # hard for renames
1319 # hard for renames
1306 c = self._filelog.children(self._filenode)
1320 c = self._filelog.children(self._filenode)
1307 return [filectx(self._repo, self._path, fileid=x,
1321 return [filectx(self._repo, self._path, fileid=x,
1308 filelog=self._filelog) for x in c]
1322 filelog=self._filelog) for x in c]
1309
1323
1310 class committablectx(basectx):
1324 class committablectx(basectx):
1311 """A committablectx object provides common functionality for a context that
1325 """A committablectx object provides common functionality for a context that
1312 wants the ability to commit, e.g. workingctx or memctx."""
1326 wants the ability to commit, e.g. workingctx or memctx."""
1313 def __init__(self, repo, text="", user=None, date=None, extra=None,
1327 def __init__(self, repo, text="", user=None, date=None, extra=None,
1314 changes=None):
1328 changes=None):
1315 self._repo = repo
1329 self._repo = repo
1316 self._rev = None
1330 self._rev = None
1317 self._node = None
1331 self._node = None
1318 self._text = text
1332 self._text = text
1319 if date:
1333 if date:
1320 self._date = util.parsedate(date)
1334 self._date = util.parsedate(date)
1321 if user:
1335 if user:
1322 self._user = user
1336 self._user = user
1323 if changes:
1337 if changes:
1324 self._status = changes
1338 self._status = changes
1325
1339
1326 self._extra = {}
1340 self._extra = {}
1327 if extra:
1341 if extra:
1328 self._extra = extra.copy()
1342 self._extra = extra.copy()
1329 if 'branch' not in self._extra:
1343 if 'branch' not in self._extra:
1330 try:
1344 try:
1331 branch = encoding.fromlocal(self._repo.dirstate.branch())
1345 branch = encoding.fromlocal(self._repo.dirstate.branch())
1332 except UnicodeDecodeError:
1346 except UnicodeDecodeError:
1333 raise error.Abort(_('branch name not in UTF-8!'))
1347 raise error.Abort(_('branch name not in UTF-8!'))
1334 self._extra['branch'] = branch
1348 self._extra['branch'] = branch
1335 if self._extra['branch'] == '':
1349 if self._extra['branch'] == '':
1336 self._extra['branch'] = 'default'
1350 self._extra['branch'] = 'default'
1337
1351
1338 def __bytes__(self):
1352 def __bytes__(self):
1339 return bytes(self._parents[0]) + "+"
1353 return bytes(self._parents[0]) + "+"
1340
1354
1341 __str__ = encoding.strmethod(__bytes__)
1355 __str__ = encoding.strmethod(__bytes__)
1342
1356
1343 def __nonzero__(self):
1357 def __nonzero__(self):
1344 return True
1358 return True
1345
1359
1346 __bool__ = __nonzero__
1360 __bool__ = __nonzero__
1347
1361
1348 def _buildflagfunc(self):
1362 def _buildflagfunc(self):
1349 # Create a fallback function for getting file flags when the
1363 # Create a fallback function for getting file flags when the
1350 # filesystem doesn't support them
1364 # filesystem doesn't support them
1351
1365
1352 copiesget = self._repo.dirstate.copies().get
1366 copiesget = self._repo.dirstate.copies().get
1353 parents = self.parents()
1367 parents = self.parents()
1354 if len(parents) < 2:
1368 if len(parents) < 2:
1355 # when we have one parent, it's easy: copy from parent
1369 # when we have one parent, it's easy: copy from parent
1356 man = parents[0].manifest()
1370 man = parents[0].manifest()
1357 def func(f):
1371 def func(f):
1358 f = copiesget(f, f)
1372 f = copiesget(f, f)
1359 return man.flags(f)
1373 return man.flags(f)
1360 else:
1374 else:
1361 # merges are tricky: we try to reconstruct the unstored
1375 # merges are tricky: we try to reconstruct the unstored
1362 # result from the merge (issue1802)
1376 # result from the merge (issue1802)
1363 p1, p2 = parents
1377 p1, p2 = parents
1364 pa = p1.ancestor(p2)
1378 pa = p1.ancestor(p2)
1365 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1379 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1366
1380
1367 def func(f):
1381 def func(f):
1368 f = copiesget(f, f) # may be wrong for merges with copies
1382 f = copiesget(f, f) # may be wrong for merges with copies
1369 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1383 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1370 if fl1 == fl2:
1384 if fl1 == fl2:
1371 return fl1
1385 return fl1
1372 if fl1 == fla:
1386 if fl1 == fla:
1373 return fl2
1387 return fl2
1374 if fl2 == fla:
1388 if fl2 == fla:
1375 return fl1
1389 return fl1
1376 return '' # punt for conflicts
1390 return '' # punt for conflicts
1377
1391
1378 return func
1392 return func
1379
1393
1380 @propertycache
1394 @propertycache
1381 def _flagfunc(self):
1395 def _flagfunc(self):
1382 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1396 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1383
1397
1384 @propertycache
1398 @propertycache
1385 def _status(self):
1399 def _status(self):
1386 return self._repo.status()
1400 return self._repo.status()
1387
1401
1388 @propertycache
1402 @propertycache
1389 def _user(self):
1403 def _user(self):
1390 return self._repo.ui.username()
1404 return self._repo.ui.username()
1391
1405
1392 @propertycache
1406 @propertycache
1393 def _date(self):
1407 def _date(self):
1394 ui = self._repo.ui
1408 ui = self._repo.ui
1395 date = ui.configdate('devel', 'default-date')
1409 date = ui.configdate('devel', 'default-date')
1396 if date is None:
1410 if date is None:
1397 date = util.makedate()
1411 date = util.makedate()
1398 return date
1412 return date
1399
1413
1400 def subrev(self, subpath):
1414 def subrev(self, subpath):
1401 return None
1415 return None
1402
1416
1403 def manifestnode(self):
1417 def manifestnode(self):
1404 return None
1418 return None
1405 def user(self):
1419 def user(self):
1406 return self._user or self._repo.ui.username()
1420 return self._user or self._repo.ui.username()
1407 def date(self):
1421 def date(self):
1408 return self._date
1422 return self._date
1409 def description(self):
1423 def description(self):
1410 return self._text
1424 return self._text
1411 def files(self):
1425 def files(self):
1412 return sorted(self._status.modified + self._status.added +
1426 return sorted(self._status.modified + self._status.added +
1413 self._status.removed)
1427 self._status.removed)
1414
1428
1415 def modified(self):
1429 def modified(self):
1416 return self._status.modified
1430 return self._status.modified
1417 def added(self):
1431 def added(self):
1418 return self._status.added
1432 return self._status.added
1419 def removed(self):
1433 def removed(self):
1420 return self._status.removed
1434 return self._status.removed
1421 def deleted(self):
1435 def deleted(self):
1422 return self._status.deleted
1436 return self._status.deleted
1423 def branch(self):
1437 def branch(self):
1424 return encoding.tolocal(self._extra['branch'])
1438 return encoding.tolocal(self._extra['branch'])
1425 def closesbranch(self):
1439 def closesbranch(self):
1426 return 'close' in self._extra
1440 return 'close' in self._extra
1427 def extra(self):
1441 def extra(self):
1428 return self._extra
1442 return self._extra
1429
1443
1430 def isinmemory(self):
1444 def isinmemory(self):
1431 return False
1445 return False
1432
1446
1433 def tags(self):
1447 def tags(self):
1434 return []
1448 return []
1435
1449
1436 def bookmarks(self):
1450 def bookmarks(self):
1437 b = []
1451 b = []
1438 for p in self.parents():
1452 for p in self.parents():
1439 b.extend(p.bookmarks())
1453 b.extend(p.bookmarks())
1440 return b
1454 return b
1441
1455
1442 def phase(self):
1456 def phase(self):
1443 phase = phases.draft # default phase to draft
1457 phase = phases.draft # default phase to draft
1444 for p in self.parents():
1458 for p in self.parents():
1445 phase = max(phase, p.phase())
1459 phase = max(phase, p.phase())
1446 return phase
1460 return phase
1447
1461
1448 def hidden(self):
1462 def hidden(self):
1449 return False
1463 return False
1450
1464
1451 def children(self):
1465 def children(self):
1452 return []
1466 return []
1453
1467
1454 def flags(self, path):
1468 def flags(self, path):
1455 if r'_manifest' in self.__dict__:
1469 if r'_manifest' in self.__dict__:
1456 try:
1470 try:
1457 return self._manifest.flags(path)
1471 return self._manifest.flags(path)
1458 except KeyError:
1472 except KeyError:
1459 return ''
1473 return ''
1460
1474
1461 try:
1475 try:
1462 return self._flagfunc(path)
1476 return self._flagfunc(path)
1463 except OSError:
1477 except OSError:
1464 return ''
1478 return ''
1465
1479
1466 def ancestor(self, c2):
1480 def ancestor(self, c2):
1467 """return the "best" ancestor context of self and c2"""
1481 """return the "best" ancestor context of self and c2"""
1468 return self._parents[0].ancestor(c2) # punt on two parents for now
1482 return self._parents[0].ancestor(c2) # punt on two parents for now
1469
1483
1470 def walk(self, match):
1484 def walk(self, match):
1471 '''Generates matching file names.'''
1485 '''Generates matching file names.'''
1472 return sorted(self._repo.dirstate.walk(match,
1486 return sorted(self._repo.dirstate.walk(match,
1473 subrepos=sorted(self.substate),
1487 subrepos=sorted(self.substate),
1474 unknown=True, ignored=False))
1488 unknown=True, ignored=False))
1475
1489
1476 def matches(self, match):
1490 def matches(self, match):
1477 return sorted(self._repo.dirstate.matches(match))
1491 return sorted(self._repo.dirstate.matches(match))
1478
1492
1479 def ancestors(self):
1493 def ancestors(self):
1480 for p in self._parents:
1494 for p in self._parents:
1481 yield p
1495 yield p
1482 for a in self._repo.changelog.ancestors(
1496 for a in self._repo.changelog.ancestors(
1483 [p.rev() for p in self._parents]):
1497 [p.rev() for p in self._parents]):
1484 yield changectx(self._repo, a)
1498 yield changectx(self._repo, a)
1485
1499
1486 def markcommitted(self, node):
1500 def markcommitted(self, node):
1487 """Perform post-commit cleanup necessary after committing this ctx
1501 """Perform post-commit cleanup necessary after committing this ctx
1488
1502
1489 Specifically, this updates backing stores this working context
1503 Specifically, this updates backing stores this working context
1490 wraps to reflect the fact that the changes reflected by this
1504 wraps to reflect the fact that the changes reflected by this
1491 workingctx have been committed. For example, it marks
1505 workingctx have been committed. For example, it marks
1492 modified and added files as normal in the dirstate.
1506 modified and added files as normal in the dirstate.
1493
1507
1494 """
1508 """
1495
1509
1496 with self._repo.dirstate.parentchange():
1510 with self._repo.dirstate.parentchange():
1497 for f in self.modified() + self.added():
1511 for f in self.modified() + self.added():
1498 self._repo.dirstate.normal(f)
1512 self._repo.dirstate.normal(f)
1499 for f in self.removed():
1513 for f in self.removed():
1500 self._repo.dirstate.drop(f)
1514 self._repo.dirstate.drop(f)
1501 self._repo.dirstate.setparents(node)
1515 self._repo.dirstate.setparents(node)
1502
1516
1503 # write changes out explicitly, because nesting wlock at
1517 # write changes out explicitly, because nesting wlock at
1504 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1518 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1505 # from immediately doing so for subsequent changing files
1519 # from immediately doing so for subsequent changing files
1506 self._repo.dirstate.write(self._repo.currenttransaction())
1520 self._repo.dirstate.write(self._repo.currenttransaction())
1507
1521
1508 def dirty(self, missing=False, merge=True, branch=True):
1522 def dirty(self, missing=False, merge=True, branch=True):
1509 return False
1523 return False
1510
1524
1511 class workingctx(committablectx):
1525 class workingctx(committablectx):
1512 """A workingctx object makes access to data related to
1526 """A workingctx object makes access to data related to
1513 the current working directory convenient.
1527 the current working directory convenient.
1514 date - any valid date string or (unixtime, offset), or None.
1528 date - any valid date string or (unixtime, offset), or None.
1515 user - username string, or None.
1529 user - username string, or None.
1516 extra - a dictionary of extra values, or None.
1530 extra - a dictionary of extra values, or None.
1517 changes - a list of file lists as returned by localrepo.status()
1531 changes - a list of file lists as returned by localrepo.status()
1518 or None to use the repository status.
1532 or None to use the repository status.
1519 """
1533 """
1520 def __init__(self, repo, text="", user=None, date=None, extra=None,
1534 def __init__(self, repo, text="", user=None, date=None, extra=None,
1521 changes=None):
1535 changes=None):
1522 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1536 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1523
1537
1524 def __iter__(self):
1538 def __iter__(self):
1525 d = self._repo.dirstate
1539 d = self._repo.dirstate
1526 for f in d:
1540 for f in d:
1527 if d[f] != 'r':
1541 if d[f] != 'r':
1528 yield f
1542 yield f
1529
1543
1530 def __contains__(self, key):
1544 def __contains__(self, key):
1531 return self._repo.dirstate[key] not in "?r"
1545 return self._repo.dirstate[key] not in "?r"
1532
1546
1533 def hex(self):
1547 def hex(self):
1534 return hex(wdirid)
1548 return hex(wdirid)
1535
1549
1536 @propertycache
1550 @propertycache
1537 def _parents(self):
1551 def _parents(self):
1538 p = self._repo.dirstate.parents()
1552 p = self._repo.dirstate.parents()
1539 if p[1] == nullid:
1553 if p[1] == nullid:
1540 p = p[:-1]
1554 p = p[:-1]
1541 return [changectx(self._repo, x) for x in p]
1555 return [changectx(self._repo, x) for x in p]
1542
1556
1543 def filectx(self, path, filelog=None):
1557 def filectx(self, path, filelog=None):
1544 """get a file context from the working directory"""
1558 """get a file context from the working directory"""
1545 return workingfilectx(self._repo, path, workingctx=self,
1559 return workingfilectx(self._repo, path, workingctx=self,
1546 filelog=filelog)
1560 filelog=filelog)
1547
1561
1548 def dirty(self, missing=False, merge=True, branch=True):
1562 def dirty(self, missing=False, merge=True, branch=True):
1549 "check whether a working directory is modified"
1563 "check whether a working directory is modified"
1550 # check subrepos first
1564 # check subrepos first
1551 for s in sorted(self.substate):
1565 for s in sorted(self.substate):
1552 if self.sub(s).dirty(missing=missing):
1566 if self.sub(s).dirty(missing=missing):
1553 return True
1567 return True
1554 # check current working dir
1568 # check current working dir
1555 return ((merge and self.p2()) or
1569 return ((merge and self.p2()) or
1556 (branch and self.branch() != self.p1().branch()) or
1570 (branch and self.branch() != self.p1().branch()) or
1557 self.modified() or self.added() or self.removed() or
1571 self.modified() or self.added() or self.removed() or
1558 (missing and self.deleted()))
1572 (missing and self.deleted()))
1559
1573
1560 def add(self, list, prefix=""):
1574 def add(self, list, prefix=""):
1561 with self._repo.wlock():
1575 with self._repo.wlock():
1562 ui, ds = self._repo.ui, self._repo.dirstate
1576 ui, ds = self._repo.ui, self._repo.dirstate
1563 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1577 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1564 rejected = []
1578 rejected = []
1565 lstat = self._repo.wvfs.lstat
1579 lstat = self._repo.wvfs.lstat
1566 for f in list:
1580 for f in list:
1567 # ds.pathto() returns an absolute file when this is invoked from
1581 # ds.pathto() returns an absolute file when this is invoked from
1568 # the keyword extension. That gets flagged as non-portable on
1582 # the keyword extension. That gets flagged as non-portable on
1569 # Windows, since it contains the drive letter and colon.
1583 # Windows, since it contains the drive letter and colon.
1570 scmutil.checkportable(ui, os.path.join(prefix, f))
1584 scmutil.checkportable(ui, os.path.join(prefix, f))
1571 try:
1585 try:
1572 st = lstat(f)
1586 st = lstat(f)
1573 except OSError:
1587 except OSError:
1574 ui.warn(_("%s does not exist!\n") % uipath(f))
1588 ui.warn(_("%s does not exist!\n") % uipath(f))
1575 rejected.append(f)
1589 rejected.append(f)
1576 continue
1590 continue
1577 if st.st_size > 10000000:
1591 if st.st_size > 10000000:
1578 ui.warn(_("%s: up to %d MB of RAM may be required "
1592 ui.warn(_("%s: up to %d MB of RAM may be required "
1579 "to manage this file\n"
1593 "to manage this file\n"
1580 "(use 'hg revert %s' to cancel the "
1594 "(use 'hg revert %s' to cancel the "
1581 "pending addition)\n")
1595 "pending addition)\n")
1582 % (f, 3 * st.st_size // 1000000, uipath(f)))
1596 % (f, 3 * st.st_size // 1000000, uipath(f)))
1583 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1597 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1584 ui.warn(_("%s not added: only files and symlinks "
1598 ui.warn(_("%s not added: only files and symlinks "
1585 "supported currently\n") % uipath(f))
1599 "supported currently\n") % uipath(f))
1586 rejected.append(f)
1600 rejected.append(f)
1587 elif ds[f] in 'amn':
1601 elif ds[f] in 'amn':
1588 ui.warn(_("%s already tracked!\n") % uipath(f))
1602 ui.warn(_("%s already tracked!\n") % uipath(f))
1589 elif ds[f] == 'r':
1603 elif ds[f] == 'r':
1590 ds.normallookup(f)
1604 ds.normallookup(f)
1591 else:
1605 else:
1592 ds.add(f)
1606 ds.add(f)
1593 return rejected
1607 return rejected
1594
1608
1595 def forget(self, files, prefix=""):
1609 def forget(self, files, prefix=""):
1596 with self._repo.wlock():
1610 with self._repo.wlock():
1597 ds = self._repo.dirstate
1611 ds = self._repo.dirstate
1598 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1612 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1599 rejected = []
1613 rejected = []
1600 for f in files:
1614 for f in files:
1601 if f not in self._repo.dirstate:
1615 if f not in self._repo.dirstate:
1602 self._repo.ui.warn(_("%s not tracked!\n") % uipath(f))
1616 self._repo.ui.warn(_("%s not tracked!\n") % uipath(f))
1603 rejected.append(f)
1617 rejected.append(f)
1604 elif self._repo.dirstate[f] != 'a':
1618 elif self._repo.dirstate[f] != 'a':
1605 self._repo.dirstate.remove(f)
1619 self._repo.dirstate.remove(f)
1606 else:
1620 else:
1607 self._repo.dirstate.drop(f)
1621 self._repo.dirstate.drop(f)
1608 return rejected
1622 return rejected
1609
1623
1610 def undelete(self, list):
1624 def undelete(self, list):
1611 pctxs = self.parents()
1625 pctxs = self.parents()
1612 with self._repo.wlock():
1626 with self._repo.wlock():
1613 ds = self._repo.dirstate
1627 ds = self._repo.dirstate
1614 for f in list:
1628 for f in list:
1615 if self._repo.dirstate[f] != 'r':
1629 if self._repo.dirstate[f] != 'r':
1616 self._repo.ui.warn(_("%s not removed!\n") % ds.pathto(f))
1630 self._repo.ui.warn(_("%s not removed!\n") % ds.pathto(f))
1617 else:
1631 else:
1618 fctx = f in pctxs[0] and pctxs[0][f] or pctxs[1][f]
1632 fctx = f in pctxs[0] and pctxs[0][f] or pctxs[1][f]
1619 t = fctx.data()
1633 t = fctx.data()
1620 self._repo.wwrite(f, t, fctx.flags())
1634 self._repo.wwrite(f, t, fctx.flags())
1621 self._repo.dirstate.normal(f)
1635 self._repo.dirstate.normal(f)
1622
1636
1623 def copy(self, source, dest):
1637 def copy(self, source, dest):
1624 try:
1638 try:
1625 st = self._repo.wvfs.lstat(dest)
1639 st = self._repo.wvfs.lstat(dest)
1626 except OSError as err:
1640 except OSError as err:
1627 if err.errno != errno.ENOENT:
1641 if err.errno != errno.ENOENT:
1628 raise
1642 raise
1629 self._repo.ui.warn(_("%s does not exist!\n")
1643 self._repo.ui.warn(_("%s does not exist!\n")
1630 % self._repo.dirstate.pathto(dest))
1644 % self._repo.dirstate.pathto(dest))
1631 return
1645 return
1632 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1646 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1633 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1647 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1634 "symbolic link\n")
1648 "symbolic link\n")
1635 % self._repo.dirstate.pathto(dest))
1649 % self._repo.dirstate.pathto(dest))
1636 else:
1650 else:
1637 with self._repo.wlock():
1651 with self._repo.wlock():
1638 if self._repo.dirstate[dest] in '?':
1652 if self._repo.dirstate[dest] in '?':
1639 self._repo.dirstate.add(dest)
1653 self._repo.dirstate.add(dest)
1640 elif self._repo.dirstate[dest] in 'r':
1654 elif self._repo.dirstate[dest] in 'r':
1641 self._repo.dirstate.normallookup(dest)
1655 self._repo.dirstate.normallookup(dest)
1642 self._repo.dirstate.copy(source, dest)
1656 self._repo.dirstate.copy(source, dest)
1643
1657
1644 def match(self, pats=None, include=None, exclude=None, default='glob',
1658 def match(self, pats=None, include=None, exclude=None, default='glob',
1645 listsubrepos=False, badfn=None):
1659 listsubrepos=False, badfn=None):
1646 r = self._repo
1660 r = self._repo
1647
1661
1648 # Only a case insensitive filesystem needs magic to translate user input
1662 # Only a case insensitive filesystem needs magic to translate user input
1649 # to actual case in the filesystem.
1663 # to actual case in the filesystem.
1650 icasefs = not util.fscasesensitive(r.root)
1664 icasefs = not util.fscasesensitive(r.root)
1651 return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
1665 return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
1652 default, auditor=r.auditor, ctx=self,
1666 default, auditor=r.auditor, ctx=self,
1653 listsubrepos=listsubrepos, badfn=badfn,
1667 listsubrepos=listsubrepos, badfn=badfn,
1654 icasefs=icasefs)
1668 icasefs=icasefs)
1655
1669
1656 def _filtersuspectsymlink(self, files):
1670 def _filtersuspectsymlink(self, files):
1657 if not files or self._repo.dirstate._checklink:
1671 if not files or self._repo.dirstate._checklink:
1658 return files
1672 return files
1659
1673
1660 # Symlink placeholders may get non-symlink-like contents
1674 # Symlink placeholders may get non-symlink-like contents
1661 # via user error or dereferencing by NFS or Samba servers,
1675 # via user error or dereferencing by NFS or Samba servers,
1662 # so we filter out any placeholders that don't look like a
1676 # so we filter out any placeholders that don't look like a
1663 # symlink
1677 # symlink
1664 sane = []
1678 sane = []
1665 for f in files:
1679 for f in files:
1666 if self.flags(f) == 'l':
1680 if self.flags(f) == 'l':
1667 d = self[f].data()
1681 d = self[f].data()
1668 if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
1682 if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
1669 self._repo.ui.debug('ignoring suspect symlink placeholder'
1683 self._repo.ui.debug('ignoring suspect symlink placeholder'
1670 ' "%s"\n' % f)
1684 ' "%s"\n' % f)
1671 continue
1685 continue
1672 sane.append(f)
1686 sane.append(f)
1673 return sane
1687 return sane
1674
1688
1675 def _checklookup(self, files):
1689 def _checklookup(self, files):
1676 # check for any possibly clean files
1690 # check for any possibly clean files
1677 if not files:
1691 if not files:
1678 return [], [], []
1692 return [], [], []
1679
1693
1680 modified = []
1694 modified = []
1681 deleted = []
1695 deleted = []
1682 fixup = []
1696 fixup = []
1683 pctx = self._parents[0]
1697 pctx = self._parents[0]
1684 # do a full compare of any files that might have changed
1698 # do a full compare of any files that might have changed
1685 for f in sorted(files):
1699 for f in sorted(files):
1686 try:
1700 try:
1687 # This will return True for a file that got replaced by a
1701 # This will return True for a file that got replaced by a
1688 # directory in the interim, but fixing that is pretty hard.
1702 # directory in the interim, but fixing that is pretty hard.
1689 if (f not in pctx or self.flags(f) != pctx.flags(f)
1703 if (f not in pctx or self.flags(f) != pctx.flags(f)
1690 or pctx[f].cmp(self[f])):
1704 or pctx[f].cmp(self[f])):
1691 modified.append(f)
1705 modified.append(f)
1692 else:
1706 else:
1693 fixup.append(f)
1707 fixup.append(f)
1694 except (IOError, OSError):
1708 except (IOError, OSError):
1695 # A file become inaccessible in between? Mark it as deleted,
1709 # A file become inaccessible in between? Mark it as deleted,
1696 # matching dirstate behavior (issue5584).
1710 # matching dirstate behavior (issue5584).
1697 # The dirstate has more complex behavior around whether a
1711 # The dirstate has more complex behavior around whether a
1698 # missing file matches a directory, etc, but we don't need to
1712 # missing file matches a directory, etc, but we don't need to
1699 # bother with that: if f has made it to this point, we're sure
1713 # bother with that: if f has made it to this point, we're sure
1700 # it's in the dirstate.
1714 # it's in the dirstate.
1701 deleted.append(f)
1715 deleted.append(f)
1702
1716
1703 return modified, deleted, fixup
1717 return modified, deleted, fixup
1704
1718
1705 def _poststatusfixup(self, status, fixup):
1719 def _poststatusfixup(self, status, fixup):
1706 """update dirstate for files that are actually clean"""
1720 """update dirstate for files that are actually clean"""
1707 poststatus = self._repo.postdsstatus()
1721 poststatus = self._repo.postdsstatus()
1708 if fixup or poststatus:
1722 if fixup or poststatus:
1709 try:
1723 try:
1710 oldid = self._repo.dirstate.identity()
1724 oldid = self._repo.dirstate.identity()
1711
1725
1712 # updating the dirstate is optional
1726 # updating the dirstate is optional
1713 # so we don't wait on the lock
1727 # so we don't wait on the lock
1714 # wlock can invalidate the dirstate, so cache normal _after_
1728 # wlock can invalidate the dirstate, so cache normal _after_
1715 # taking the lock
1729 # taking the lock
1716 with self._repo.wlock(False):
1730 with self._repo.wlock(False):
1717 if self._repo.dirstate.identity() == oldid:
1731 if self._repo.dirstate.identity() == oldid:
1718 if fixup:
1732 if fixup:
1719 normal = self._repo.dirstate.normal
1733 normal = self._repo.dirstate.normal
1720 for f in fixup:
1734 for f in fixup:
1721 normal(f)
1735 normal(f)
1722 # write changes out explicitly, because nesting
1736 # write changes out explicitly, because nesting
1723 # wlock at runtime may prevent 'wlock.release()'
1737 # wlock at runtime may prevent 'wlock.release()'
1724 # after this block from doing so for subsequent
1738 # after this block from doing so for subsequent
1725 # changing files
1739 # changing files
1726 tr = self._repo.currenttransaction()
1740 tr = self._repo.currenttransaction()
1727 self._repo.dirstate.write(tr)
1741 self._repo.dirstate.write(tr)
1728
1742
1729 if poststatus:
1743 if poststatus:
1730 for ps in poststatus:
1744 for ps in poststatus:
1731 ps(self, status)
1745 ps(self, status)
1732 else:
1746 else:
1733 # in this case, writing changes out breaks
1747 # in this case, writing changes out breaks
1734 # consistency, because .hg/dirstate was
1748 # consistency, because .hg/dirstate was
1735 # already changed simultaneously after last
1749 # already changed simultaneously after last
1736 # caching (see also issue5584 for detail)
1750 # caching (see also issue5584 for detail)
1737 self._repo.ui.debug('skip updating dirstate: '
1751 self._repo.ui.debug('skip updating dirstate: '
1738 'identity mismatch\n')
1752 'identity mismatch\n')
1739 except error.LockError:
1753 except error.LockError:
1740 pass
1754 pass
1741 finally:
1755 finally:
1742 # Even if the wlock couldn't be grabbed, clear out the list.
1756 # Even if the wlock couldn't be grabbed, clear out the list.
1743 self._repo.clearpostdsstatus()
1757 self._repo.clearpostdsstatus()
1744
1758
1745 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
1759 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
1746 '''Gets the status from the dirstate -- internal use only.'''
1760 '''Gets the status from the dirstate -- internal use only.'''
1747 subrepos = []
1761 subrepos = []
1748 if '.hgsub' in self:
1762 if '.hgsub' in self:
1749 subrepos = sorted(self.substate)
1763 subrepos = sorted(self.substate)
1750 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
1764 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
1751 clean=clean, unknown=unknown)
1765 clean=clean, unknown=unknown)
1752
1766
1753 # check for any possibly clean files
1767 # check for any possibly clean files
1754 fixup = []
1768 fixup = []
1755 if cmp:
1769 if cmp:
1756 modified2, deleted2, fixup = self._checklookup(cmp)
1770 modified2, deleted2, fixup = self._checklookup(cmp)
1757 s.modified.extend(modified2)
1771 s.modified.extend(modified2)
1758 s.deleted.extend(deleted2)
1772 s.deleted.extend(deleted2)
1759
1773
1760 if fixup and clean:
1774 if fixup and clean:
1761 s.clean.extend(fixup)
1775 s.clean.extend(fixup)
1762
1776
1763 self._poststatusfixup(s, fixup)
1777 self._poststatusfixup(s, fixup)
1764
1778
1765 if match.always():
1779 if match.always():
1766 # cache for performance
1780 # cache for performance
1767 if s.unknown or s.ignored or s.clean:
1781 if s.unknown or s.ignored or s.clean:
1768 # "_status" is cached with list*=False in the normal route
1782 # "_status" is cached with list*=False in the normal route
1769 self._status = scmutil.status(s.modified, s.added, s.removed,
1783 self._status = scmutil.status(s.modified, s.added, s.removed,
1770 s.deleted, [], [], [])
1784 s.deleted, [], [], [])
1771 else:
1785 else:
1772 self._status = s
1786 self._status = s
1773
1787
1774 return s
1788 return s
1775
1789
1776 @propertycache
1790 @propertycache
1777 def _manifest(self):
1791 def _manifest(self):
1778 """generate a manifest corresponding to the values in self._status
1792 """generate a manifest corresponding to the values in self._status
1779
1793
1780 This reuse the file nodeid from parent, but we use special node
1794 This reuse the file nodeid from parent, but we use special node
1781 identifiers for added and modified files. This is used by manifests
1795 identifiers for added and modified files. This is used by manifests
1782 merge to see that files are different and by update logic to avoid
1796 merge to see that files are different and by update logic to avoid
1783 deleting newly added files.
1797 deleting newly added files.
1784 """
1798 """
1785 return self._buildstatusmanifest(self._status)
1799 return self._buildstatusmanifest(self._status)
1786
1800
1787 def _buildstatusmanifest(self, status):
1801 def _buildstatusmanifest(self, status):
1788 """Builds a manifest that includes the given status results."""
1802 """Builds a manifest that includes the given status results."""
1789 parents = self.parents()
1803 parents = self.parents()
1790
1804
1791 man = parents[0].manifest().copy()
1805 man = parents[0].manifest().copy()
1792
1806
1793 ff = self._flagfunc
1807 ff = self._flagfunc
1794 for i, l in ((addednodeid, status.added),
1808 for i, l in ((addednodeid, status.added),
1795 (modifiednodeid, status.modified)):
1809 (modifiednodeid, status.modified)):
1796 for f in l:
1810 for f in l:
1797 man[f] = i
1811 man[f] = i
1798 try:
1812 try:
1799 man.setflag(f, ff(f))
1813 man.setflag(f, ff(f))
1800 except OSError:
1814 except OSError:
1801 pass
1815 pass
1802
1816
1803 for f in status.deleted + status.removed:
1817 for f in status.deleted + status.removed:
1804 if f in man:
1818 if f in man:
1805 del man[f]
1819 del man[f]
1806
1820
1807 return man
1821 return man
1808
1822
1809 def _buildstatus(self, other, s, match, listignored, listclean,
1823 def _buildstatus(self, other, s, match, listignored, listclean,
1810 listunknown):
1824 listunknown):
1811 """build a status with respect to another context
1825 """build a status with respect to another context
1812
1826
1813 This includes logic for maintaining the fast path of status when
1827 This includes logic for maintaining the fast path of status when
1814 comparing the working directory against its parent, which is to skip
1828 comparing the working directory against its parent, which is to skip
1815 building a new manifest if self (working directory) is not comparing
1829 building a new manifest if self (working directory) is not comparing
1816 against its parent (repo['.']).
1830 against its parent (repo['.']).
1817 """
1831 """
1818 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1832 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1819 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1833 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1820 # might have accidentally ended up with the entire contents of the file
1834 # might have accidentally ended up with the entire contents of the file
1821 # they are supposed to be linking to.
1835 # they are supposed to be linking to.
1822 s.modified[:] = self._filtersuspectsymlink(s.modified)
1836 s.modified[:] = self._filtersuspectsymlink(s.modified)
1823 if other != self._repo['.']:
1837 if other != self._repo['.']:
1824 s = super(workingctx, self)._buildstatus(other, s, match,
1838 s = super(workingctx, self)._buildstatus(other, s, match,
1825 listignored, listclean,
1839 listignored, listclean,
1826 listunknown)
1840 listunknown)
1827 return s
1841 return s
1828
1842
1829 def _matchstatus(self, other, match):
1843 def _matchstatus(self, other, match):
1830 """override the match method with a filter for directory patterns
1844 """override the match method with a filter for directory patterns
1831
1845
1832 We use inheritance to customize the match.bad method only in cases of
1846 We use inheritance to customize the match.bad method only in cases of
1833 workingctx since it belongs only to the working directory when
1847 workingctx since it belongs only to the working directory when
1834 comparing against the parent changeset.
1848 comparing against the parent changeset.
1835
1849
1836 If we aren't comparing against the working directory's parent, then we
1850 If we aren't comparing against the working directory's parent, then we
1837 just use the default match object sent to us.
1851 just use the default match object sent to us.
1838 """
1852 """
1839 if other != self._repo['.']:
1853 if other != self._repo['.']:
1840 def bad(f, msg):
1854 def bad(f, msg):
1841 # 'f' may be a directory pattern from 'match.files()',
1855 # 'f' may be a directory pattern from 'match.files()',
1842 # so 'f not in ctx1' is not enough
1856 # so 'f not in ctx1' is not enough
1843 if f not in other and not other.hasdir(f):
1857 if f not in other and not other.hasdir(f):
1844 self._repo.ui.warn('%s: %s\n' %
1858 self._repo.ui.warn('%s: %s\n' %
1845 (self._repo.dirstate.pathto(f), msg))
1859 (self._repo.dirstate.pathto(f), msg))
1846 match.bad = bad
1860 match.bad = bad
1847 return match
1861 return match
1848
1862
1849 def markcommitted(self, node):
1863 def markcommitted(self, node):
1850 super(workingctx, self).markcommitted(node)
1864 super(workingctx, self).markcommitted(node)
1851
1865
1852 sparse.aftercommit(self._repo, node)
1866 sparse.aftercommit(self._repo, node)
1853
1867
1854 class committablefilectx(basefilectx):
1868 class committablefilectx(basefilectx):
1855 """A committablefilectx provides common functionality for a file context
1869 """A committablefilectx provides common functionality for a file context
1856 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1870 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1857 def __init__(self, repo, path, filelog=None, ctx=None):
1871 def __init__(self, repo, path, filelog=None, ctx=None):
1858 self._repo = repo
1872 self._repo = repo
1859 self._path = path
1873 self._path = path
1860 self._changeid = None
1874 self._changeid = None
1861 self._filerev = self._filenode = None
1875 self._filerev = self._filenode = None
1862
1876
1863 if filelog is not None:
1877 if filelog is not None:
1864 self._filelog = filelog
1878 self._filelog = filelog
1865 if ctx:
1879 if ctx:
1866 self._changectx = ctx
1880 self._changectx = ctx
1867
1881
1868 def __nonzero__(self):
1882 def __nonzero__(self):
1869 return True
1883 return True
1870
1884
1871 __bool__ = __nonzero__
1885 __bool__ = __nonzero__
1872
1886
1873 def linkrev(self):
1887 def linkrev(self):
1874 # linked to self._changectx no matter if file is modified or not
1888 # linked to self._changectx no matter if file is modified or not
1875 return self.rev()
1889 return self.rev()
1876
1890
1877 def parents(self):
1891 def parents(self):
1878 '''return parent filectxs, following copies if necessary'''
1892 '''return parent filectxs, following copies if necessary'''
1879 def filenode(ctx, path):
1893 def filenode(ctx, path):
1880 return ctx._manifest.get(path, nullid)
1894 return ctx._manifest.get(path, nullid)
1881
1895
1882 path = self._path
1896 path = self._path
1883 fl = self._filelog
1897 fl = self._filelog
1884 pcl = self._changectx._parents
1898 pcl = self._changectx._parents
1885 renamed = self.renamed()
1899 renamed = self.renamed()
1886
1900
1887 if renamed:
1901 if renamed:
1888 pl = [renamed + (None,)]
1902 pl = [renamed + (None,)]
1889 else:
1903 else:
1890 pl = [(path, filenode(pcl[0], path), fl)]
1904 pl = [(path, filenode(pcl[0], path), fl)]
1891
1905
1892 for pc in pcl[1:]:
1906 for pc in pcl[1:]:
1893 pl.append((path, filenode(pc, path), fl))
1907 pl.append((path, filenode(pc, path), fl))
1894
1908
1895 return [self._parentfilectx(p, fileid=n, filelog=l)
1909 return [self._parentfilectx(p, fileid=n, filelog=l)
1896 for p, n, l in pl if n != nullid]
1910 for p, n, l in pl if n != nullid]
1897
1911
1898 def children(self):
1912 def children(self):
1899 return []
1913 return []
1900
1914
1901 class workingfilectx(committablefilectx):
1915 class workingfilectx(committablefilectx):
1902 """A workingfilectx object makes access to data related to a particular
1916 """A workingfilectx object makes access to data related to a particular
1903 file in the working directory convenient."""
1917 file in the working directory convenient."""
1904 def __init__(self, repo, path, filelog=None, workingctx=None):
1918 def __init__(self, repo, path, filelog=None, workingctx=None):
1905 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1919 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1906
1920
1907 @propertycache
1921 @propertycache
1908 def _changectx(self):
1922 def _changectx(self):
1909 return workingctx(self._repo)
1923 return workingctx(self._repo)
1910
1924
1911 def data(self):
1925 def data(self):
1912 return self._repo.wread(self._path)
1926 return self._repo.wread(self._path)
1913 def renamed(self):
1927 def renamed(self):
1914 rp = self._repo.dirstate.copied(self._path)
1928 rp = self._repo.dirstate.copied(self._path)
1915 if not rp:
1929 if not rp:
1916 return None
1930 return None
1917 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
1931 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
1918
1932
1919 def size(self):
1933 def size(self):
1920 return self._repo.wvfs.lstat(self._path).st_size
1934 return self._repo.wvfs.lstat(self._path).st_size
1921 def date(self):
1935 def date(self):
1922 t, tz = self._changectx.date()
1936 t, tz = self._changectx.date()
1923 try:
1937 try:
1924 return (self._repo.wvfs.lstat(self._path).st_mtime, tz)
1938 return (self._repo.wvfs.lstat(self._path).st_mtime, tz)
1925 except OSError as err:
1939 except OSError as err:
1926 if err.errno != errno.ENOENT:
1940 if err.errno != errno.ENOENT:
1927 raise
1941 raise
1928 return (t, tz)
1942 return (t, tz)
1929
1943
1930 def exists(self):
1944 def exists(self):
1931 return self._repo.wvfs.exists(self._path)
1945 return self._repo.wvfs.exists(self._path)
1932
1946
1933 def lexists(self):
1947 def lexists(self):
1934 return self._repo.wvfs.lexists(self._path)
1948 return self._repo.wvfs.lexists(self._path)
1935
1949
1936 def audit(self):
1950 def audit(self):
1937 return self._repo.wvfs.audit(self._path)
1951 return self._repo.wvfs.audit(self._path)
1938
1952
1939 def cmp(self, fctx):
1953 def cmp(self, fctx):
1940 """compare with other file context
1954 """compare with other file context
1941
1955
1942 returns True if different than fctx.
1956 returns True if different than fctx.
1943 """
1957 """
1944 # fctx should be a filectx (not a workingfilectx)
1958 # fctx should be a filectx (not a workingfilectx)
1945 # invert comparison to reuse the same code path
1959 # invert comparison to reuse the same code path
1946 return fctx.cmp(self)
1960 return fctx.cmp(self)
1947
1961
1948 def remove(self, ignoremissing=False):
1962 def remove(self, ignoremissing=False):
1949 """wraps unlink for a repo's working directory"""
1963 """wraps unlink for a repo's working directory"""
1950 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing)
1964 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing)
1951
1965
1952 def write(self, data, flags, backgroundclose=False):
1966 def write(self, data, flags, backgroundclose=False):
1953 """wraps repo.wwrite"""
1967 """wraps repo.wwrite"""
1954 self._repo.wwrite(self._path, data, flags,
1968 self._repo.wwrite(self._path, data, flags,
1955 backgroundclose=backgroundclose)
1969 backgroundclose=backgroundclose)
1956
1970
1957 def markcopied(self, src):
1971 def markcopied(self, src):
1958 """marks this file a copy of `src`"""
1972 """marks this file a copy of `src`"""
1959 if self._repo.dirstate[self._path] in "nma":
1973 if self._repo.dirstate[self._path] in "nma":
1960 self._repo.dirstate.copy(src, self._path)
1974 self._repo.dirstate.copy(src, self._path)
1961
1975
1962 def clearunknown(self):
1976 def clearunknown(self):
1963 """Removes conflicting items in the working directory so that
1977 """Removes conflicting items in the working directory so that
1964 ``write()`` can be called successfully.
1978 ``write()`` can be called successfully.
1965 """
1979 """
1966 wvfs = self._repo.wvfs
1980 wvfs = self._repo.wvfs
1967 f = self._path
1981 f = self._path
1968 wvfs.audit(f)
1982 wvfs.audit(f)
1969 if wvfs.isdir(f) and not wvfs.islink(f):
1983 if wvfs.isdir(f) and not wvfs.islink(f):
1970 wvfs.rmtree(f, forcibly=True)
1984 wvfs.rmtree(f, forcibly=True)
1971 for p in reversed(list(util.finddirs(f))):
1985 for p in reversed(list(util.finddirs(f))):
1972 if wvfs.isfileorlink(p):
1986 if wvfs.isfileorlink(p):
1973 wvfs.unlink(p)
1987 wvfs.unlink(p)
1974 break
1988 break
1975
1989
1976 def setflags(self, l, x):
1990 def setflags(self, l, x):
1977 self._repo.wvfs.setflags(self._path, l, x)
1991 self._repo.wvfs.setflags(self._path, l, x)
1978
1992
1979 class overlayworkingctx(committablectx):
1993 class overlayworkingctx(committablectx):
1980 """Wraps another mutable context with a write-back cache that can be
1994 """Wraps another mutable context with a write-back cache that can be
1981 converted into a commit context.
1995 converted into a commit context.
1982
1996
1983 self._cache[path] maps to a dict with keys: {
1997 self._cache[path] maps to a dict with keys: {
1984 'exists': bool?
1998 'exists': bool?
1985 'date': date?
1999 'date': date?
1986 'data': str?
2000 'data': str?
1987 'flags': str?
2001 'flags': str?
1988 'copied': str? (path or None)
2002 'copied': str? (path or None)
1989 }
2003 }
1990 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it
2004 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it
1991 is `False`, the file was deleted.
2005 is `False`, the file was deleted.
1992 """
2006 """
1993
2007
1994 def __init__(self, repo):
2008 def __init__(self, repo):
1995 super(overlayworkingctx, self).__init__(repo)
2009 super(overlayworkingctx, self).__init__(repo)
1996 self._repo = repo
2010 self._repo = repo
1997 self.clean()
2011 self.clean()
1998
2012
1999 def setbase(self, wrappedctx):
2013 def setbase(self, wrappedctx):
2000 self._wrappedctx = wrappedctx
2014 self._wrappedctx = wrappedctx
2001 self._parents = [wrappedctx]
2015 self._parents = [wrappedctx]
2002 # Drop old manifest cache as it is now out of date.
2016 # Drop old manifest cache as it is now out of date.
2003 # This is necessary when, e.g., rebasing several nodes with one
2017 # This is necessary when, e.g., rebasing several nodes with one
2004 # ``overlayworkingctx`` (e.g. with --collapse).
2018 # ``overlayworkingctx`` (e.g. with --collapse).
2005 util.clearcachedproperty(self, '_manifest')
2019 util.clearcachedproperty(self, '_manifest')
2006
2020
2007 def data(self, path):
2021 def data(self, path):
2008 if self.isdirty(path):
2022 if self.isdirty(path):
2009 if self._cache[path]['exists']:
2023 if self._cache[path]['exists']:
2010 if self._cache[path]['data']:
2024 if self._cache[path]['data']:
2011 return self._cache[path]['data']
2025 return self._cache[path]['data']
2012 else:
2026 else:
2013 # Must fallback here, too, because we only set flags.
2027 # Must fallback here, too, because we only set flags.
2014 return self._wrappedctx[path].data()
2028 return self._wrappedctx[path].data()
2015 else:
2029 else:
2016 raise error.ProgrammingError("No such file or directory: %s" %
2030 raise error.ProgrammingError("No such file or directory: %s" %
2017 path)
2031 path)
2018 else:
2032 else:
2019 return self._wrappedctx[path].data()
2033 return self._wrappedctx[path].data()
2020
2034
2021 @propertycache
2035 @propertycache
2022 def _manifest(self):
2036 def _manifest(self):
2023 parents = self.parents()
2037 parents = self.parents()
2024 man = parents[0].manifest().copy()
2038 man = parents[0].manifest().copy()
2025
2039
2026 flag = self._flagfunc
2040 flag = self._flagfunc
2027 for path in self.added():
2041 for path in self.added():
2028 man[path] = addednodeid
2042 man[path] = addednodeid
2029 man.setflag(path, flag(path))
2043 man.setflag(path, flag(path))
2030 for path in self.modified():
2044 for path in self.modified():
2031 man[path] = modifiednodeid
2045 man[path] = modifiednodeid
2032 man.setflag(path, flag(path))
2046 man.setflag(path, flag(path))
2033 for path in self.removed():
2047 for path in self.removed():
2034 del man[path]
2048 del man[path]
2035 return man
2049 return man
2036
2050
2037 @propertycache
2051 @propertycache
2038 def _flagfunc(self):
2052 def _flagfunc(self):
2039 def f(path):
2053 def f(path):
2040 return self._cache[path]['flags']
2054 return self._cache[path]['flags']
2041 return f
2055 return f
2042
2056
2043 def files(self):
2057 def files(self):
2044 return sorted(self.added() + self.modified() + self.removed())
2058 return sorted(self.added() + self.modified() + self.removed())
2045
2059
2046 def modified(self):
2060 def modified(self):
2047 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
2061 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
2048 self._existsinparent(f)]
2062 self._existsinparent(f)]
2049
2063
2050 def added(self):
2064 def added(self):
2051 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
2065 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
2052 not self._existsinparent(f)]
2066 not self._existsinparent(f)]
2053
2067
2054 def removed(self):
2068 def removed(self):
2055 return [f for f in self._cache.keys() if
2069 return [f for f in self._cache.keys() if
2056 not self._cache[f]['exists'] and self._existsinparent(f)]
2070 not self._cache[f]['exists'] and self._existsinparent(f)]
2057
2071
2058 def isinmemory(self):
2072 def isinmemory(self):
2059 return True
2073 return True
2060
2074
2061 def filedate(self, path):
2075 def filedate(self, path):
2062 if self.isdirty(path):
2076 if self.isdirty(path):
2063 return self._cache[path]['date']
2077 return self._cache[path]['date']
2064 else:
2078 else:
2065 return self._wrappedctx[path].date()
2079 return self._wrappedctx[path].date()
2066
2080
2067 def markcopied(self, path, origin):
2081 def markcopied(self, path, origin):
2068 if self.isdirty(path):
2082 if self.isdirty(path):
2069 self._cache[path]['copied'] = origin
2083 self._cache[path]['copied'] = origin
2070 else:
2084 else:
2071 raise error.ProgrammingError('markcopied() called on clean context')
2085 raise error.ProgrammingError('markcopied() called on clean context')
2072
2086
2073 def copydata(self, path):
2087 def copydata(self, path):
2074 if self.isdirty(path):
2088 if self.isdirty(path):
2075 return self._cache[path]['copied']
2089 return self._cache[path]['copied']
2076 else:
2090 else:
2077 raise error.ProgrammingError('copydata() called on clean context')
2091 raise error.ProgrammingError('copydata() called on clean context')
2078
2092
2079 def flags(self, path):
2093 def flags(self, path):
2080 if self.isdirty(path):
2094 if self.isdirty(path):
2081 if self._cache[path]['exists']:
2095 if self._cache[path]['exists']:
2082 return self._cache[path]['flags']
2096 return self._cache[path]['flags']
2083 else:
2097 else:
2084 raise error.ProgrammingError("No such file or directory: %s" %
2098 raise error.ProgrammingError("No such file or directory: %s" %
2085 self._path)
2099 self._path)
2086 else:
2100 else:
2087 return self._wrappedctx[path].flags()
2101 return self._wrappedctx[path].flags()
2088
2102
2089 def _existsinparent(self, path):
2103 def _existsinparent(self, path):
2090 try:
2104 try:
2091 # ``commitctx` raises a ``ManifestLookupError`` if a path does not
2105 # ``commitctx` raises a ``ManifestLookupError`` if a path does not
2092 # exist, unlike ``workingctx``, which returns a ``workingfilectx``
2106 # exist, unlike ``workingctx``, which returns a ``workingfilectx``
2093 # with an ``exists()`` function.
2107 # with an ``exists()`` function.
2094 self._wrappedctx[path]
2108 self._wrappedctx[path]
2095 return True
2109 return True
2096 except error.ManifestLookupError:
2110 except error.ManifestLookupError:
2097 return False
2111 return False
2098
2112
2099 def _auditconflicts(self, path):
2113 def _auditconflicts(self, path):
2100 """Replicates conflict checks done by wvfs.write().
2114 """Replicates conflict checks done by wvfs.write().
2101
2115
2102 Since we never write to the filesystem and never call `applyupdates` in
2116 Since we never write to the filesystem and never call `applyupdates` in
2103 IMM, we'll never check that a path is actually writable -- e.g., because
2117 IMM, we'll never check that a path is actually writable -- e.g., because
2104 it adds `a/foo`, but `a` is actually a file in the other commit.
2118 it adds `a/foo`, but `a` is actually a file in the other commit.
2105 """
2119 """
2106 def fail(path, component):
2120 def fail(path, component):
2107 # p1() is the base and we're receiving "writes" for p2()'s
2121 # p1() is the base and we're receiving "writes" for p2()'s
2108 # files.
2122 # files.
2109 if 'l' in self.p1()[component].flags():
2123 if 'l' in self.p1()[component].flags():
2110 raise error.Abort("error: %s conflicts with symlink %s "
2124 raise error.Abort("error: %s conflicts with symlink %s "
2111 "in %s." % (path, component,
2125 "in %s." % (path, component,
2112 self.p1().rev()))
2126 self.p1().rev()))
2113 else:
2127 else:
2114 raise error.Abort("error: '%s' conflicts with file '%s' in "
2128 raise error.Abort("error: '%s' conflicts with file '%s' in "
2115 "%s." % (path, component,
2129 "%s." % (path, component,
2116 self.p1().rev()))
2130 self.p1().rev()))
2117
2131
2118 # Test that each new directory to be created to write this path from p2
2132 # Test that each new directory to be created to write this path from p2
2119 # is not a file in p1.
2133 # is not a file in p1.
2120 components = path.split('/')
2134 components = path.split('/')
2121 for i in xrange(len(components)):
2135 for i in xrange(len(components)):
2122 component = "/".join(components[0:i])
2136 component = "/".join(components[0:i])
2123 if component in self.p1():
2137 if component in self.p1():
2124 fail(path, component)
2138 fail(path, component)
2125
2139
2126 # Test the other direction -- that this path from p2 isn't a directory
2140 # Test the other direction -- that this path from p2 isn't a directory
2127 # in p1 (test that p1 doesn't any paths matching `path/*`).
2141 # in p1 (test that p1 doesn't any paths matching `path/*`).
2128 match = matchmod.match('/', '', [path + '/'], default=b'relpath')
2142 match = matchmod.match('/', '', [path + '/'], default=b'relpath')
2129 matches = self.p1().manifest().matches(match)
2143 matches = self.p1().manifest().matches(match)
2130 if len(matches) > 0:
2144 if len(matches) > 0:
2131 if len(matches) == 1 and matches.keys()[0] == path:
2145 if len(matches) == 1 and matches.keys()[0] == path:
2132 return
2146 return
2133 raise error.Abort("error: file '%s' cannot be written because "
2147 raise error.Abort("error: file '%s' cannot be written because "
2134 " '%s/' is a folder in %s (containing %d "
2148 " '%s/' is a folder in %s (containing %d "
2135 "entries: %s)"
2149 "entries: %s)"
2136 % (path, path, self.p1(), len(matches),
2150 % (path, path, self.p1(), len(matches),
2137 ', '.join(matches.keys())))
2151 ', '.join(matches.keys())))
2138
2152
2139 def write(self, path, data, flags=''):
2153 def write(self, path, data, flags=''):
2140 if data is None:
2154 if data is None:
2141 raise error.ProgrammingError("data must be non-None")
2155 raise error.ProgrammingError("data must be non-None")
2142 self._auditconflicts(path)
2156 self._auditconflicts(path)
2143 self._markdirty(path, exists=True, data=data, date=util.makedate(),
2157 self._markdirty(path, exists=True, data=data, date=util.makedate(),
2144 flags=flags)
2158 flags=flags)
2145
2159
2146 def setflags(self, path, l, x):
2160 def setflags(self, path, l, x):
2147 self._markdirty(path, exists=True, date=util.makedate(),
2161 self._markdirty(path, exists=True, date=util.makedate(),
2148 flags=(l and 'l' or '') + (x and 'x' or ''))
2162 flags=(l and 'l' or '') + (x and 'x' or ''))
2149
2163
2150 def remove(self, path):
2164 def remove(self, path):
2151 self._markdirty(path, exists=False)
2165 self._markdirty(path, exists=False)
2152
2166
2153 def exists(self, path):
2167 def exists(self, path):
2154 """exists behaves like `lexists`, but needs to follow symlinks and
2168 """exists behaves like `lexists`, but needs to follow symlinks and
2155 return False if they are broken.
2169 return False if they are broken.
2156 """
2170 """
2157 if self.isdirty(path):
2171 if self.isdirty(path):
2158 # If this path exists and is a symlink, "follow" it by calling
2172 # If this path exists and is a symlink, "follow" it by calling
2159 # exists on the destination path.
2173 # exists on the destination path.
2160 if (self._cache[path]['exists'] and
2174 if (self._cache[path]['exists'] and
2161 'l' in self._cache[path]['flags']):
2175 'l' in self._cache[path]['flags']):
2162 return self.exists(self._cache[path]['data'].strip())
2176 return self.exists(self._cache[path]['data'].strip())
2163 else:
2177 else:
2164 return self._cache[path]['exists']
2178 return self._cache[path]['exists']
2165
2179
2166 return self._existsinparent(path)
2180 return self._existsinparent(path)
2167
2181
2168 def lexists(self, path):
2182 def lexists(self, path):
2169 """lexists returns True if the path exists"""
2183 """lexists returns True if the path exists"""
2170 if self.isdirty(path):
2184 if self.isdirty(path):
2171 return self._cache[path]['exists']
2185 return self._cache[path]['exists']
2172
2186
2173 return self._existsinparent(path)
2187 return self._existsinparent(path)
2174
2188
2175 def size(self, path):
2189 def size(self, path):
2176 if self.isdirty(path):
2190 if self.isdirty(path):
2177 if self._cache[path]['exists']:
2191 if self._cache[path]['exists']:
2178 return len(self._cache[path]['data'])
2192 return len(self._cache[path]['data'])
2179 else:
2193 else:
2180 raise error.ProgrammingError("No such file or directory: %s" %
2194 raise error.ProgrammingError("No such file or directory: %s" %
2181 self._path)
2195 self._path)
2182 return self._wrappedctx[path].size()
2196 return self._wrappedctx[path].size()
2183
2197
2184 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
2198 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
2185 user=None, editor=None):
2199 user=None, editor=None):
2186 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
2200 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
2187 committed.
2201 committed.
2188
2202
2189 ``text`` is the commit message.
2203 ``text`` is the commit message.
2190 ``parents`` (optional) are rev numbers.
2204 ``parents`` (optional) are rev numbers.
2191 """
2205 """
2192 # Default parents to the wrapped contexts' if not passed.
2206 # Default parents to the wrapped contexts' if not passed.
2193 if parents is None:
2207 if parents is None:
2194 parents = self._wrappedctx.parents()
2208 parents = self._wrappedctx.parents()
2195 if len(parents) == 1:
2209 if len(parents) == 1:
2196 parents = (parents[0], None)
2210 parents = (parents[0], None)
2197
2211
2198 # ``parents`` is passed as rev numbers; convert to ``commitctxs``.
2212 # ``parents`` is passed as rev numbers; convert to ``commitctxs``.
2199 if parents[1] is None:
2213 if parents[1] is None:
2200 parents = (self._repo[parents[0]], None)
2214 parents = (self._repo[parents[0]], None)
2201 else:
2215 else:
2202 parents = (self._repo[parents[0]], self._repo[parents[1]])
2216 parents = (self._repo[parents[0]], self._repo[parents[1]])
2203
2217
2204 files = self._cache.keys()
2218 files = self._cache.keys()
2205 def getfile(repo, memctx, path):
2219 def getfile(repo, memctx, path):
2206 if self._cache[path]['exists']:
2220 if self._cache[path]['exists']:
2207 return memfilectx(repo, memctx, path,
2221 return memfilectx(repo, memctx, path,
2208 self._cache[path]['data'],
2222 self._cache[path]['data'],
2209 'l' in self._cache[path]['flags'],
2223 'l' in self._cache[path]['flags'],
2210 'x' in self._cache[path]['flags'],
2224 'x' in self._cache[path]['flags'],
2211 self._cache[path]['copied'])
2225 self._cache[path]['copied'])
2212 else:
2226 else:
2213 # Returning None, but including the path in `files`, is
2227 # Returning None, but including the path in `files`, is
2214 # necessary for memctx to register a deletion.
2228 # necessary for memctx to register a deletion.
2215 return None
2229 return None
2216 return memctx(self._repo, parents, text, files, getfile, date=date,
2230 return memctx(self._repo, parents, text, files, getfile, date=date,
2217 extra=extra, user=user, branch=branch, editor=editor)
2231 extra=extra, user=user, branch=branch, editor=editor)
2218
2232
2219 def isdirty(self, path):
2233 def isdirty(self, path):
2220 return path in self._cache
2234 return path in self._cache
2221
2235
2222 def isempty(self):
2236 def isempty(self):
2223 # We need to discard any keys that are actually clean before the empty
2237 # We need to discard any keys that are actually clean before the empty
2224 # commit check.
2238 # commit check.
2225 self._compact()
2239 self._compact()
2226 return len(self._cache) == 0
2240 return len(self._cache) == 0
2227
2241
2228 def clean(self):
2242 def clean(self):
2229 self._cache = {}
2243 self._cache = {}
2230
2244
2231 def _compact(self):
2245 def _compact(self):
2232 """Removes keys from the cache that are actually clean, by comparing
2246 """Removes keys from the cache that are actually clean, by comparing
2233 them with the underlying context.
2247 them with the underlying context.
2234
2248
2235 This can occur during the merge process, e.g. by passing --tool :local
2249 This can occur during the merge process, e.g. by passing --tool :local
2236 to resolve a conflict.
2250 to resolve a conflict.
2237 """
2251 """
2238 keys = []
2252 keys = []
2239 for path in self._cache.keys():
2253 for path in self._cache.keys():
2240 cache = self._cache[path]
2254 cache = self._cache[path]
2241 try:
2255 try:
2242 underlying = self._wrappedctx[path]
2256 underlying = self._wrappedctx[path]
2243 if (underlying.data() == cache['data'] and
2257 if (underlying.data() == cache['data'] and
2244 underlying.flags() == cache['flags']):
2258 underlying.flags() == cache['flags']):
2245 keys.append(path)
2259 keys.append(path)
2246 except error.ManifestLookupError:
2260 except error.ManifestLookupError:
2247 # Path not in the underlying manifest (created).
2261 # Path not in the underlying manifest (created).
2248 continue
2262 continue
2249
2263
2250 for path in keys:
2264 for path in keys:
2251 del self._cache[path]
2265 del self._cache[path]
2252 return keys
2266 return keys
2253
2267
2254 def _markdirty(self, path, exists, data=None, date=None, flags=''):
2268 def _markdirty(self, path, exists, data=None, date=None, flags=''):
2255 self._cache[path] = {
2269 self._cache[path] = {
2256 'exists': exists,
2270 'exists': exists,
2257 'data': data,
2271 'data': data,
2258 'date': date,
2272 'date': date,
2259 'flags': flags,
2273 'flags': flags,
2260 'copied': None,
2274 'copied': None,
2261 }
2275 }
2262
2276
2263 def filectx(self, path, filelog=None):
2277 def filectx(self, path, filelog=None):
2264 return overlayworkingfilectx(self._repo, path, parent=self,
2278 return overlayworkingfilectx(self._repo, path, parent=self,
2265 filelog=filelog)
2279 filelog=filelog)
2266
2280
2267 class overlayworkingfilectx(committablefilectx):
2281 class overlayworkingfilectx(committablefilectx):
2268 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
2282 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
2269 cache, which can be flushed through later by calling ``flush()``."""
2283 cache, which can be flushed through later by calling ``flush()``."""
2270
2284
2271 def __init__(self, repo, path, filelog=None, parent=None):
2285 def __init__(self, repo, path, filelog=None, parent=None):
2272 super(overlayworkingfilectx, self).__init__(repo, path, filelog,
2286 super(overlayworkingfilectx, self).__init__(repo, path, filelog,
2273 parent)
2287 parent)
2274 self._repo = repo
2288 self._repo = repo
2275 self._parent = parent
2289 self._parent = parent
2276 self._path = path
2290 self._path = path
2277
2291
2278 def cmp(self, fctx):
2292 def cmp(self, fctx):
2279 return self.data() != fctx.data()
2293 return self.data() != fctx.data()
2280
2294
2281 def changectx(self):
2295 def changectx(self):
2282 return self._parent
2296 return self._parent
2283
2297
2284 def data(self):
2298 def data(self):
2285 return self._parent.data(self._path)
2299 return self._parent.data(self._path)
2286
2300
2287 def date(self):
2301 def date(self):
2288 return self._parent.filedate(self._path)
2302 return self._parent.filedate(self._path)
2289
2303
2290 def exists(self):
2304 def exists(self):
2291 return self.lexists()
2305 return self.lexists()
2292
2306
2293 def lexists(self):
2307 def lexists(self):
2294 return self._parent.exists(self._path)
2308 return self._parent.exists(self._path)
2295
2309
2296 def renamed(self):
2310 def renamed(self):
2297 path = self._parent.copydata(self._path)
2311 path = self._parent.copydata(self._path)
2298 if not path:
2312 if not path:
2299 return None
2313 return None
2300 return path, self._changectx._parents[0]._manifest.get(path, nullid)
2314 return path, self._changectx._parents[0]._manifest.get(path, nullid)
2301
2315
2302 def size(self):
2316 def size(self):
2303 return self._parent.size(self._path)
2317 return self._parent.size(self._path)
2304
2318
2305 def markcopied(self, origin):
2319 def markcopied(self, origin):
2306 self._parent.markcopied(self._path, origin)
2320 self._parent.markcopied(self._path, origin)
2307
2321
2308 def audit(self):
2322 def audit(self):
2309 pass
2323 pass
2310
2324
2311 def flags(self):
2325 def flags(self):
2312 return self._parent.flags(self._path)
2326 return self._parent.flags(self._path)
2313
2327
2314 def setflags(self, islink, isexec):
2328 def setflags(self, islink, isexec):
2315 return self._parent.setflags(self._path, islink, isexec)
2329 return self._parent.setflags(self._path, islink, isexec)
2316
2330
2317 def write(self, data, flags, backgroundclose=False):
2331 def write(self, data, flags, backgroundclose=False):
2318 return self._parent.write(self._path, data, flags)
2332 return self._parent.write(self._path, data, flags)
2319
2333
2320 def remove(self, ignoremissing=False):
2334 def remove(self, ignoremissing=False):
2321 return self._parent.remove(self._path)
2335 return self._parent.remove(self._path)
2322
2336
2323 def clearunknown(self):
2337 def clearunknown(self):
2324 pass
2338 pass
2325
2339
2326 class workingcommitctx(workingctx):
2340 class workingcommitctx(workingctx):
2327 """A workingcommitctx object makes access to data related to
2341 """A workingcommitctx object makes access to data related to
2328 the revision being committed convenient.
2342 the revision being committed convenient.
2329
2343
2330 This hides changes in the working directory, if they aren't
2344 This hides changes in the working directory, if they aren't
2331 committed in this context.
2345 committed in this context.
2332 """
2346 """
2333 def __init__(self, repo, changes,
2347 def __init__(self, repo, changes,
2334 text="", user=None, date=None, extra=None):
2348 text="", user=None, date=None, extra=None):
2335 super(workingctx, self).__init__(repo, text, user, date, extra,
2349 super(workingctx, self).__init__(repo, text, user, date, extra,
2336 changes)
2350 changes)
2337
2351
2338 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
2352 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
2339 """Return matched files only in ``self._status``
2353 """Return matched files only in ``self._status``
2340
2354
2341 Uncommitted files appear "clean" via this context, even if
2355 Uncommitted files appear "clean" via this context, even if
2342 they aren't actually so in the working directory.
2356 they aren't actually so in the working directory.
2343 """
2357 """
2344 if clean:
2358 if clean:
2345 clean = [f for f in self._manifest if f not in self._changedset]
2359 clean = [f for f in self._manifest if f not in self._changedset]
2346 else:
2360 else:
2347 clean = []
2361 clean = []
2348 return scmutil.status([f for f in self._status.modified if match(f)],
2362 return scmutil.status([f for f in self._status.modified if match(f)],
2349 [f for f in self._status.added if match(f)],
2363 [f for f in self._status.added if match(f)],
2350 [f for f in self._status.removed if match(f)],
2364 [f for f in self._status.removed if match(f)],
2351 [], [], [], clean)
2365 [], [], [], clean)
2352
2366
2353 @propertycache
2367 @propertycache
2354 def _changedset(self):
2368 def _changedset(self):
2355 """Return the set of files changed in this context
2369 """Return the set of files changed in this context
2356 """
2370 """
2357 changed = set(self._status.modified)
2371 changed = set(self._status.modified)
2358 changed.update(self._status.added)
2372 changed.update(self._status.added)
2359 changed.update(self._status.removed)
2373 changed.update(self._status.removed)
2360 return changed
2374 return changed
2361
2375
2362 def makecachingfilectxfn(func):
2376 def makecachingfilectxfn(func):
2363 """Create a filectxfn that caches based on the path.
2377 """Create a filectxfn that caches based on the path.
2364
2378
2365 We can't use util.cachefunc because it uses all arguments as the cache
2379 We can't use util.cachefunc because it uses all arguments as the cache
2366 key and this creates a cycle since the arguments include the repo and
2380 key and this creates a cycle since the arguments include the repo and
2367 memctx.
2381 memctx.
2368 """
2382 """
2369 cache = {}
2383 cache = {}
2370
2384
2371 def getfilectx(repo, memctx, path):
2385 def getfilectx(repo, memctx, path):
2372 if path not in cache:
2386 if path not in cache:
2373 cache[path] = func(repo, memctx, path)
2387 cache[path] = func(repo, memctx, path)
2374 return cache[path]
2388 return cache[path]
2375
2389
2376 return getfilectx
2390 return getfilectx
2377
2391
2378 def memfilefromctx(ctx):
2392 def memfilefromctx(ctx):
2379 """Given a context return a memfilectx for ctx[path]
2393 """Given a context return a memfilectx for ctx[path]
2380
2394
2381 This is a convenience method for building a memctx based on another
2395 This is a convenience method for building a memctx based on another
2382 context.
2396 context.
2383 """
2397 """
2384 def getfilectx(repo, memctx, path):
2398 def getfilectx(repo, memctx, path):
2385 fctx = ctx[path]
2399 fctx = ctx[path]
2386 # this is weird but apparently we only keep track of one parent
2400 # this is weird but apparently we only keep track of one parent
2387 # (why not only store that instead of a tuple?)
2401 # (why not only store that instead of a tuple?)
2388 copied = fctx.renamed()
2402 copied = fctx.renamed()
2389 if copied:
2403 if copied:
2390 copied = copied[0]
2404 copied = copied[0]
2391 return memfilectx(repo, memctx, path, fctx.data(),
2405 return memfilectx(repo, memctx, path, fctx.data(),
2392 islink=fctx.islink(), isexec=fctx.isexec(),
2406 islink=fctx.islink(), isexec=fctx.isexec(),
2393 copied=copied)
2407 copied=copied)
2394
2408
2395 return getfilectx
2409 return getfilectx
2396
2410
2397 def memfilefrompatch(patchstore):
2411 def memfilefrompatch(patchstore):
2398 """Given a patch (e.g. patchstore object) return a memfilectx
2412 """Given a patch (e.g. patchstore object) return a memfilectx
2399
2413
2400 This is a convenience method for building a memctx based on a patchstore.
2414 This is a convenience method for building a memctx based on a patchstore.
2401 """
2415 """
2402 def getfilectx(repo, memctx, path):
2416 def getfilectx(repo, memctx, path):
2403 data, mode, copied = patchstore.getfile(path)
2417 data, mode, copied = patchstore.getfile(path)
2404 if data is None:
2418 if data is None:
2405 return None
2419 return None
2406 islink, isexec = mode
2420 islink, isexec = mode
2407 return memfilectx(repo, memctx, path, data, islink=islink,
2421 return memfilectx(repo, memctx, path, data, islink=islink,
2408 isexec=isexec, copied=copied)
2422 isexec=isexec, copied=copied)
2409
2423
2410 return getfilectx
2424 return getfilectx
2411
2425
2412 class memctx(committablectx):
2426 class memctx(committablectx):
2413 """Use memctx to perform in-memory commits via localrepo.commitctx().
2427 """Use memctx to perform in-memory commits via localrepo.commitctx().
2414
2428
2415 Revision information is supplied at initialization time while
2429 Revision information is supplied at initialization time while
2416 related files data and is made available through a callback
2430 related files data and is made available through a callback
2417 mechanism. 'repo' is the current localrepo, 'parents' is a
2431 mechanism. 'repo' is the current localrepo, 'parents' is a
2418 sequence of two parent revisions identifiers (pass None for every
2432 sequence of two parent revisions identifiers (pass None for every
2419 missing parent), 'text' is the commit message and 'files' lists
2433 missing parent), 'text' is the commit message and 'files' lists
2420 names of files touched by the revision (normalized and relative to
2434 names of files touched by the revision (normalized and relative to
2421 repository root).
2435 repository root).
2422
2436
2423 filectxfn(repo, memctx, path) is a callable receiving the
2437 filectxfn(repo, memctx, path) is a callable receiving the
2424 repository, the current memctx object and the normalized path of
2438 repository, the current memctx object and the normalized path of
2425 requested file, relative to repository root. It is fired by the
2439 requested file, relative to repository root. It is fired by the
2426 commit function for every file in 'files', but calls order is
2440 commit function for every file in 'files', but calls order is
2427 undefined. If the file is available in the revision being
2441 undefined. If the file is available in the revision being
2428 committed (updated or added), filectxfn returns a memfilectx
2442 committed (updated or added), filectxfn returns a memfilectx
2429 object. If the file was removed, filectxfn return None for recent
2443 object. If the file was removed, filectxfn return None for recent
2430 Mercurial. Moved files are represented by marking the source file
2444 Mercurial. Moved files are represented by marking the source file
2431 removed and the new file added with copy information (see
2445 removed and the new file added with copy information (see
2432 memfilectx).
2446 memfilectx).
2433
2447
2434 user receives the committer name and defaults to current
2448 user receives the committer name and defaults to current
2435 repository username, date is the commit date in any format
2449 repository username, date is the commit date in any format
2436 supported by util.parsedate() and defaults to current date, extra
2450 supported by util.parsedate() and defaults to current date, extra
2437 is a dictionary of metadata or is left empty.
2451 is a dictionary of metadata or is left empty.
2438 """
2452 """
2439
2453
2440 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
2454 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
2441 # Extensions that need to retain compatibility across Mercurial 3.1 can use
2455 # Extensions that need to retain compatibility across Mercurial 3.1 can use
2442 # this field to determine what to do in filectxfn.
2456 # this field to determine what to do in filectxfn.
2443 _returnnoneformissingfiles = True
2457 _returnnoneformissingfiles = True
2444
2458
2445 def __init__(self, repo, parents, text, files, filectxfn, user=None,
2459 def __init__(self, repo, parents, text, files, filectxfn, user=None,
2446 date=None, extra=None, branch=None, editor=False):
2460 date=None, extra=None, branch=None, editor=False):
2447 super(memctx, self).__init__(repo, text, user, date, extra)
2461 super(memctx, self).__init__(repo, text, user, date, extra)
2448 self._rev = None
2462 self._rev = None
2449 self._node = None
2463 self._node = None
2450 parents = [(p or nullid) for p in parents]
2464 parents = [(p or nullid) for p in parents]
2451 p1, p2 = parents
2465 p1, p2 = parents
2452 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
2466 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
2453 files = sorted(set(files))
2467 files = sorted(set(files))
2454 self._files = files
2468 self._files = files
2455 if branch is not None:
2469 if branch is not None:
2456 self._extra['branch'] = encoding.fromlocal(branch)
2470 self._extra['branch'] = encoding.fromlocal(branch)
2457 self.substate = {}
2471 self.substate = {}
2458
2472
2459 if isinstance(filectxfn, patch.filestore):
2473 if isinstance(filectxfn, patch.filestore):
2460 filectxfn = memfilefrompatch(filectxfn)
2474 filectxfn = memfilefrompatch(filectxfn)
2461 elif not callable(filectxfn):
2475 elif not callable(filectxfn):
2462 # if store is not callable, wrap it in a function
2476 # if store is not callable, wrap it in a function
2463 filectxfn = memfilefromctx(filectxfn)
2477 filectxfn = memfilefromctx(filectxfn)
2464
2478
2465 # memoizing increases performance for e.g. vcs convert scenarios.
2479 # memoizing increases performance for e.g. vcs convert scenarios.
2466 self._filectxfn = makecachingfilectxfn(filectxfn)
2480 self._filectxfn = makecachingfilectxfn(filectxfn)
2467
2481
2468 if editor:
2482 if editor:
2469 self._text = editor(self._repo, self, [])
2483 self._text = editor(self._repo, self, [])
2470 self._repo.savecommitmessage(self._text)
2484 self._repo.savecommitmessage(self._text)
2471
2485
2472 def filectx(self, path, filelog=None):
2486 def filectx(self, path, filelog=None):
2473 """get a file context from the working directory
2487 """get a file context from the working directory
2474
2488
2475 Returns None if file doesn't exist and should be removed."""
2489 Returns None if file doesn't exist and should be removed."""
2476 return self._filectxfn(self._repo, self, path)
2490 return self._filectxfn(self._repo, self, path)
2477
2491
2478 def commit(self):
2492 def commit(self):
2479 """commit context to the repo"""
2493 """commit context to the repo"""
2480 return self._repo.commitctx(self)
2494 return self._repo.commitctx(self)
2481
2495
2482 @propertycache
2496 @propertycache
2483 def _manifest(self):
2497 def _manifest(self):
2484 """generate a manifest based on the return values of filectxfn"""
2498 """generate a manifest based on the return values of filectxfn"""
2485
2499
2486 # keep this simple for now; just worry about p1
2500 # keep this simple for now; just worry about p1
2487 pctx = self._parents[0]
2501 pctx = self._parents[0]
2488 man = pctx.manifest().copy()
2502 man = pctx.manifest().copy()
2489
2503
2490 for f in self._status.modified:
2504 for f in self._status.modified:
2491 p1node = nullid
2505 p1node = nullid
2492 p2node = nullid
2506 p2node = nullid
2493 p = pctx[f].parents() # if file isn't in pctx, check p2?
2507 p = pctx[f].parents() # if file isn't in pctx, check p2?
2494 if len(p) > 0:
2508 if len(p) > 0:
2495 p1node = p[0].filenode()
2509 p1node = p[0].filenode()
2496 if len(p) > 1:
2510 if len(p) > 1:
2497 p2node = p[1].filenode()
2511 p2node = p[1].filenode()
2498 man[f] = revlog.hash(self[f].data(), p1node, p2node)
2512 man[f] = revlog.hash(self[f].data(), p1node, p2node)
2499
2513
2500 for f in self._status.added:
2514 for f in self._status.added:
2501 man[f] = revlog.hash(self[f].data(), nullid, nullid)
2515 man[f] = revlog.hash(self[f].data(), nullid, nullid)
2502
2516
2503 for f in self._status.removed:
2517 for f in self._status.removed:
2504 if f in man:
2518 if f in man:
2505 del man[f]
2519 del man[f]
2506
2520
2507 return man
2521 return man
2508
2522
2509 @propertycache
2523 @propertycache
2510 def _status(self):
2524 def _status(self):
2511 """Calculate exact status from ``files`` specified at construction
2525 """Calculate exact status from ``files`` specified at construction
2512 """
2526 """
2513 man1 = self.p1().manifest()
2527 man1 = self.p1().manifest()
2514 p2 = self._parents[1]
2528 p2 = self._parents[1]
2515 # "1 < len(self._parents)" can't be used for checking
2529 # "1 < len(self._parents)" can't be used for checking
2516 # existence of the 2nd parent, because "memctx._parents" is
2530 # existence of the 2nd parent, because "memctx._parents" is
2517 # explicitly initialized by the list, of which length is 2.
2531 # explicitly initialized by the list, of which length is 2.
2518 if p2.node() != nullid:
2532 if p2.node() != nullid:
2519 man2 = p2.manifest()
2533 man2 = p2.manifest()
2520 managing = lambda f: f in man1 or f in man2
2534 managing = lambda f: f in man1 or f in man2
2521 else:
2535 else:
2522 managing = lambda f: f in man1
2536 managing = lambda f: f in man1
2523
2537
2524 modified, added, removed = [], [], []
2538 modified, added, removed = [], [], []
2525 for f in self._files:
2539 for f in self._files:
2526 if not managing(f):
2540 if not managing(f):
2527 added.append(f)
2541 added.append(f)
2528 elif self[f]:
2542 elif self[f]:
2529 modified.append(f)
2543 modified.append(f)
2530 else:
2544 else:
2531 removed.append(f)
2545 removed.append(f)
2532
2546
2533 return scmutil.status(modified, added, removed, [], [], [], [])
2547 return scmutil.status(modified, added, removed, [], [], [], [])
2534
2548
2535 class memfilectx(committablefilectx):
2549 class memfilectx(committablefilectx):
2536 """memfilectx represents an in-memory file to commit.
2550 """memfilectx represents an in-memory file to commit.
2537
2551
2538 See memctx and committablefilectx for more details.
2552 See memctx and committablefilectx for more details.
2539 """
2553 """
2540 def __init__(self, repo, changectx, path, data, islink=False,
2554 def __init__(self, repo, changectx, path, data, islink=False,
2541 isexec=False, copied=None):
2555 isexec=False, copied=None):
2542 """
2556 """
2543 path is the normalized file path relative to repository root.
2557 path is the normalized file path relative to repository root.
2544 data is the file content as a string.
2558 data is the file content as a string.
2545 islink is True if the file is a symbolic link.
2559 islink is True if the file is a symbolic link.
2546 isexec is True if the file is executable.
2560 isexec is True if the file is executable.
2547 copied is the source file path if current file was copied in the
2561 copied is the source file path if current file was copied in the
2548 revision being committed, or None."""
2562 revision being committed, or None."""
2549 super(memfilectx, self).__init__(repo, path, None, changectx)
2563 super(memfilectx, self).__init__(repo, path, None, changectx)
2550 self._data = data
2564 self._data = data
2551 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
2565 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
2552 self._copied = None
2566 self._copied = None
2553 if copied:
2567 if copied:
2554 self._copied = (copied, nullid)
2568 self._copied = (copied, nullid)
2555
2569
2556 def data(self):
2570 def data(self):
2557 return self._data
2571 return self._data
2558
2572
2559 def remove(self, ignoremissing=False):
2573 def remove(self, ignoremissing=False):
2560 """wraps unlink for a repo's working directory"""
2574 """wraps unlink for a repo's working directory"""
2561 # need to figure out what to do here
2575 # need to figure out what to do here
2562 del self._changectx[self._path]
2576 del self._changectx[self._path]
2563
2577
2564 def write(self, data, flags):
2578 def write(self, data, flags):
2565 """wraps repo.wwrite"""
2579 """wraps repo.wwrite"""
2566 self._data = data
2580 self._data = data
2567
2581
2568 class overlayfilectx(committablefilectx):
2582 class overlayfilectx(committablefilectx):
2569 """Like memfilectx but take an original filectx and optional parameters to
2583 """Like memfilectx but take an original filectx and optional parameters to
2570 override parts of it. This is useful when fctx.data() is expensive (i.e.
2584 override parts of it. This is useful when fctx.data() is expensive (i.e.
2571 flag processor is expensive) and raw data, flags, and filenode could be
2585 flag processor is expensive) and raw data, flags, and filenode could be
2572 reused (ex. rebase or mode-only amend a REVIDX_EXTSTORED file).
2586 reused (ex. rebase or mode-only amend a REVIDX_EXTSTORED file).
2573 """
2587 """
2574
2588
2575 def __init__(self, originalfctx, datafunc=None, path=None, flags=None,
2589 def __init__(self, originalfctx, datafunc=None, path=None, flags=None,
2576 copied=None, ctx=None):
2590 copied=None, ctx=None):
2577 """originalfctx: filecontext to duplicate
2591 """originalfctx: filecontext to duplicate
2578
2592
2579 datafunc: None or a function to override data (file content). It is a
2593 datafunc: None or a function to override data (file content). It is a
2580 function to be lazy. path, flags, copied, ctx: None or overridden value
2594 function to be lazy. path, flags, copied, ctx: None or overridden value
2581
2595
2582 copied could be (path, rev), or False. copied could also be just path,
2596 copied could be (path, rev), or False. copied could also be just path,
2583 and will be converted to (path, nullid). This simplifies some callers.
2597 and will be converted to (path, nullid). This simplifies some callers.
2584 """
2598 """
2585
2599
2586 if path is None:
2600 if path is None:
2587 path = originalfctx.path()
2601 path = originalfctx.path()
2588 if ctx is None:
2602 if ctx is None:
2589 ctx = originalfctx.changectx()
2603 ctx = originalfctx.changectx()
2590 ctxmatch = lambda: True
2604 ctxmatch = lambda: True
2591 else:
2605 else:
2592 ctxmatch = lambda: ctx == originalfctx.changectx()
2606 ctxmatch = lambda: ctx == originalfctx.changectx()
2593
2607
2594 repo = originalfctx.repo()
2608 repo = originalfctx.repo()
2595 flog = originalfctx.filelog()
2609 flog = originalfctx.filelog()
2596 super(overlayfilectx, self).__init__(repo, path, flog, ctx)
2610 super(overlayfilectx, self).__init__(repo, path, flog, ctx)
2597
2611
2598 if copied is None:
2612 if copied is None:
2599 copied = originalfctx.renamed()
2613 copied = originalfctx.renamed()
2600 copiedmatch = lambda: True
2614 copiedmatch = lambda: True
2601 else:
2615 else:
2602 if copied and not isinstance(copied, tuple):
2616 if copied and not isinstance(copied, tuple):
2603 # repo._filecommit will recalculate copyrev so nullid is okay
2617 # repo._filecommit will recalculate copyrev so nullid is okay
2604 copied = (copied, nullid)
2618 copied = (copied, nullid)
2605 copiedmatch = lambda: copied == originalfctx.renamed()
2619 copiedmatch = lambda: copied == originalfctx.renamed()
2606
2620
2607 # When data, copied (could affect data), ctx (could affect filelog
2621 # When data, copied (could affect data), ctx (could affect filelog
2608 # parents) are not overridden, rawdata, rawflags, and filenode may be
2622 # parents) are not overridden, rawdata, rawflags, and filenode may be
2609 # reused (repo._filecommit should double check filelog parents).
2623 # reused (repo._filecommit should double check filelog parents).
2610 #
2624 #
2611 # path, flags are not hashed in filelog (but in manifestlog) so they do
2625 # path, flags are not hashed in filelog (but in manifestlog) so they do
2612 # not affect reusable here.
2626 # not affect reusable here.
2613 #
2627 #
2614 # If ctx or copied is overridden to a same value with originalfctx,
2628 # If ctx or copied is overridden to a same value with originalfctx,
2615 # still consider it's reusable. originalfctx.renamed() may be a bit
2629 # still consider it's reusable. originalfctx.renamed() may be a bit
2616 # expensive so it's not called unless necessary. Assuming datafunc is
2630 # expensive so it's not called unless necessary. Assuming datafunc is
2617 # always expensive, do not call it for this "reusable" test.
2631 # always expensive, do not call it for this "reusable" test.
2618 reusable = datafunc is None and ctxmatch() and copiedmatch()
2632 reusable = datafunc is None and ctxmatch() and copiedmatch()
2619
2633
2620 if datafunc is None:
2634 if datafunc is None:
2621 datafunc = originalfctx.data
2635 datafunc = originalfctx.data
2622 if flags is None:
2636 if flags is None:
2623 flags = originalfctx.flags()
2637 flags = originalfctx.flags()
2624
2638
2625 self._datafunc = datafunc
2639 self._datafunc = datafunc
2626 self._flags = flags
2640 self._flags = flags
2627 self._copied = copied
2641 self._copied = copied
2628
2642
2629 if reusable:
2643 if reusable:
2630 # copy extra fields from originalfctx
2644 # copy extra fields from originalfctx
2631 attrs = ['rawdata', 'rawflags', '_filenode', '_filerev']
2645 attrs = ['rawdata', 'rawflags', '_filenode', '_filerev']
2632 for attr_ in attrs:
2646 for attr_ in attrs:
2633 if util.safehasattr(originalfctx, attr_):
2647 if util.safehasattr(originalfctx, attr_):
2634 setattr(self, attr_, getattr(originalfctx, attr_))
2648 setattr(self, attr_, getattr(originalfctx, attr_))
2635
2649
2636 def data(self):
2650 def data(self):
2637 return self._datafunc()
2651 return self._datafunc()
2638
2652
2639 class metadataonlyctx(committablectx):
2653 class metadataonlyctx(committablectx):
2640 """Like memctx but it's reusing the manifest of different commit.
2654 """Like memctx but it's reusing the manifest of different commit.
2641 Intended to be used by lightweight operations that are creating
2655 Intended to be used by lightweight operations that are creating
2642 metadata-only changes.
2656 metadata-only changes.
2643
2657
2644 Revision information is supplied at initialization time. 'repo' is the
2658 Revision information is supplied at initialization time. 'repo' is the
2645 current localrepo, 'ctx' is original revision which manifest we're reuisng
2659 current localrepo, 'ctx' is original revision which manifest we're reuisng
2646 'parents' is a sequence of two parent revisions identifiers (pass None for
2660 'parents' is a sequence of two parent revisions identifiers (pass None for
2647 every missing parent), 'text' is the commit.
2661 every missing parent), 'text' is the commit.
2648
2662
2649 user receives the committer name and defaults to current repository
2663 user receives the committer name and defaults to current repository
2650 username, date is the commit date in any format supported by
2664 username, date is the commit date in any format supported by
2651 util.parsedate() and defaults to current date, extra is a dictionary of
2665 util.parsedate() and defaults to current date, extra is a dictionary of
2652 metadata or is left empty.
2666 metadata or is left empty.
2653 """
2667 """
2654 def __new__(cls, repo, originalctx, *args, **kwargs):
2668 def __new__(cls, repo, originalctx, *args, **kwargs):
2655 return super(metadataonlyctx, cls).__new__(cls, repo)
2669 return super(metadataonlyctx, cls).__new__(cls, repo)
2656
2670
2657 def __init__(self, repo, originalctx, parents=None, text=None, user=None,
2671 def __init__(self, repo, originalctx, parents=None, text=None, user=None,
2658 date=None, extra=None, editor=False):
2672 date=None, extra=None, editor=False):
2659 if text is None:
2673 if text is None:
2660 text = originalctx.description()
2674 text = originalctx.description()
2661 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2675 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2662 self._rev = None
2676 self._rev = None
2663 self._node = None
2677 self._node = None
2664 self._originalctx = originalctx
2678 self._originalctx = originalctx
2665 self._manifestnode = originalctx.manifestnode()
2679 self._manifestnode = originalctx.manifestnode()
2666 if parents is None:
2680 if parents is None:
2667 parents = originalctx.parents()
2681 parents = originalctx.parents()
2668 else:
2682 else:
2669 parents = [repo[p] for p in parents if p is not None]
2683 parents = [repo[p] for p in parents if p is not None]
2670 parents = parents[:]
2684 parents = parents[:]
2671 while len(parents) < 2:
2685 while len(parents) < 2:
2672 parents.append(repo[nullid])
2686 parents.append(repo[nullid])
2673 p1, p2 = self._parents = parents
2687 p1, p2 = self._parents = parents
2674
2688
2675 # sanity check to ensure that the reused manifest parents are
2689 # sanity check to ensure that the reused manifest parents are
2676 # manifests of our commit parents
2690 # manifests of our commit parents
2677 mp1, mp2 = self.manifestctx().parents
2691 mp1, mp2 = self.manifestctx().parents
2678 if p1 != nullid and p1.manifestnode() != mp1:
2692 if p1 != nullid and p1.manifestnode() != mp1:
2679 raise RuntimeError('can\'t reuse the manifest: '
2693 raise RuntimeError('can\'t reuse the manifest: '
2680 'its p1 doesn\'t match the new ctx p1')
2694 'its p1 doesn\'t match the new ctx p1')
2681 if p2 != nullid and p2.manifestnode() != mp2:
2695 if p2 != nullid and p2.manifestnode() != mp2:
2682 raise RuntimeError('can\'t reuse the manifest: '
2696 raise RuntimeError('can\'t reuse the manifest: '
2683 'its p2 doesn\'t match the new ctx p2')
2697 'its p2 doesn\'t match the new ctx p2')
2684
2698
2685 self._files = originalctx.files()
2699 self._files = originalctx.files()
2686 self.substate = {}
2700 self.substate = {}
2687
2701
2688 if editor:
2702 if editor:
2689 self._text = editor(self._repo, self, [])
2703 self._text = editor(self._repo, self, [])
2690 self._repo.savecommitmessage(self._text)
2704 self._repo.savecommitmessage(self._text)
2691
2705
2692 def manifestnode(self):
2706 def manifestnode(self):
2693 return self._manifestnode
2707 return self._manifestnode
2694
2708
2695 @property
2709 @property
2696 def _manifestctx(self):
2710 def _manifestctx(self):
2697 return self._repo.manifestlog[self._manifestnode]
2711 return self._repo.manifestlog[self._manifestnode]
2698
2712
2699 def filectx(self, path, filelog=None):
2713 def filectx(self, path, filelog=None):
2700 return self._originalctx.filectx(path, filelog=filelog)
2714 return self._originalctx.filectx(path, filelog=filelog)
2701
2715
2702 def commit(self):
2716 def commit(self):
2703 """commit context to the repo"""
2717 """commit context to the repo"""
2704 return self._repo.commitctx(self)
2718 return self._repo.commitctx(self)
2705
2719
2706 @property
2720 @property
2707 def _manifest(self):
2721 def _manifest(self):
2708 return self._originalctx.manifest()
2722 return self._originalctx.manifest()
2709
2723
2710 @propertycache
2724 @propertycache
2711 def _status(self):
2725 def _status(self):
2712 """Calculate exact status from ``files`` specified in the ``origctx``
2726 """Calculate exact status from ``files`` specified in the ``origctx``
2713 and parents manifests.
2727 and parents manifests.
2714 """
2728 """
2715 man1 = self.p1().manifest()
2729 man1 = self.p1().manifest()
2716 p2 = self._parents[1]
2730 p2 = self._parents[1]
2717 # "1 < len(self._parents)" can't be used for checking
2731 # "1 < len(self._parents)" can't be used for checking
2718 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2732 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2719 # explicitly initialized by the list, of which length is 2.
2733 # explicitly initialized by the list, of which length is 2.
2720 if p2.node() != nullid:
2734 if p2.node() != nullid:
2721 man2 = p2.manifest()
2735 man2 = p2.manifest()
2722 managing = lambda f: f in man1 or f in man2
2736 managing = lambda f: f in man1 or f in man2
2723 else:
2737 else:
2724 managing = lambda f: f in man1
2738 managing = lambda f: f in man1
2725
2739
2726 modified, added, removed = [], [], []
2740 modified, added, removed = [], [], []
2727 for f in self._files:
2741 for f in self._files:
2728 if not managing(f):
2742 if not managing(f):
2729 added.append(f)
2743 added.append(f)
2730 elif f in self:
2744 elif f in self:
2731 modified.append(f)
2745 modified.append(f)
2732 else:
2746 else:
2733 removed.append(f)
2747 removed.append(f)
2734
2748
2735 return scmutil.status(modified, added, removed, [], [], [], [])
2749 return scmutil.status(modified, added, removed, [], [], [], [])
2736
2750
2737 class arbitraryfilectx(object):
2751 class arbitraryfilectx(object):
2738 """Allows you to use filectx-like functions on a file in an arbitrary
2752 """Allows you to use filectx-like functions on a file in an arbitrary
2739 location on disk, possibly not in the working directory.
2753 location on disk, possibly not in the working directory.
2740 """
2754 """
2741 def __init__(self, path, repo=None):
2755 def __init__(self, path, repo=None):
2742 # Repo is optional because contrib/simplemerge uses this class.
2756 # Repo is optional because contrib/simplemerge uses this class.
2743 self._repo = repo
2757 self._repo = repo
2744 self._path = path
2758 self._path = path
2745
2759
2746 def cmp(self, fctx):
2760 def cmp(self, fctx):
2747 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2761 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2748 # path if either side is a symlink.
2762 # path if either side is a symlink.
2749 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2763 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2750 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2764 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2751 # Add a fast-path for merge if both sides are disk-backed.
2765 # Add a fast-path for merge if both sides are disk-backed.
2752 # Note that filecmp uses the opposite return values (True if same)
2766 # Note that filecmp uses the opposite return values (True if same)
2753 # from our cmp functions (True if different).
2767 # from our cmp functions (True if different).
2754 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2768 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2755 return self.data() != fctx.data()
2769 return self.data() != fctx.data()
2756
2770
2757 def path(self):
2771 def path(self):
2758 return self._path
2772 return self._path
2759
2773
2760 def flags(self):
2774 def flags(self):
2761 return ''
2775 return ''
2762
2776
2763 def data(self):
2777 def data(self):
2764 return util.readfile(self._path)
2778 return util.readfile(self._path)
2765
2779
2766 def decodeddata(self):
2780 def decodeddata(self):
2767 with open(self._path, "rb") as f:
2781 with open(self._path, "rb") as f:
2768 return f.read()
2782 return f.read()
2769
2783
2770 def remove(self):
2784 def remove(self):
2771 util.unlink(self._path)
2785 util.unlink(self._path)
2772
2786
2773 def write(self, data, flags):
2787 def write(self, data, flags):
2774 assert not flags
2788 assert not flags
2775 with open(self._path, "w") as f:
2789 with open(self._path, "w") as f:
2776 f.write(data)
2790 f.write(data)
@@ -1,838 +1,897 b''
1 # obsutil.py - utility functions for obsolescence
1 # obsutil.py - utility functions for obsolescence
2 #
2 #
3 # Copyright 2017 Boris Feld <boris.feld@octobus.net>
3 # Copyright 2017 Boris Feld <boris.feld@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import re
10 import re
11
11
12 from .i18n import _
12 from . import (
13 from . import (
14 node as nodemod,
13 phases,
15 phases,
14 util
16 util,
15 )
17 )
16
18
17 class marker(object):
19 class marker(object):
18 """Wrap obsolete marker raw data"""
20 """Wrap obsolete marker raw data"""
19
21
20 def __init__(self, repo, data):
22 def __init__(self, repo, data):
21 # the repo argument will be used to create changectx in later version
23 # the repo argument will be used to create changectx in later version
22 self._repo = repo
24 self._repo = repo
23 self._data = data
25 self._data = data
24 self._decodedmeta = None
26 self._decodedmeta = None
25
27
26 def __hash__(self):
28 def __hash__(self):
27 return hash(self._data)
29 return hash(self._data)
28
30
29 def __eq__(self, other):
31 def __eq__(self, other):
30 if type(other) != type(self):
32 if type(other) != type(self):
31 return False
33 return False
32 return self._data == other._data
34 return self._data == other._data
33
35
34 def precnode(self):
36 def precnode(self):
35 msg = ("'marker.precnode' is deprecated, "
37 msg = ("'marker.precnode' is deprecated, "
36 "use 'marker.prednode'")
38 "use 'marker.prednode'")
37 util.nouideprecwarn(msg, '4.4')
39 util.nouideprecwarn(msg, '4.4')
38 return self.prednode()
40 return self.prednode()
39
41
40 def prednode(self):
42 def prednode(self):
41 """Predecessor changeset node identifier"""
43 """Predecessor changeset node identifier"""
42 return self._data[0]
44 return self._data[0]
43
45
44 def succnodes(self):
46 def succnodes(self):
45 """List of successor changesets node identifiers"""
47 """List of successor changesets node identifiers"""
46 return self._data[1]
48 return self._data[1]
47
49
48 def parentnodes(self):
50 def parentnodes(self):
49 """Parents of the predecessors (None if not recorded)"""
51 """Parents of the predecessors (None if not recorded)"""
50 return self._data[5]
52 return self._data[5]
51
53
52 def metadata(self):
54 def metadata(self):
53 """Decoded metadata dictionary"""
55 """Decoded metadata dictionary"""
54 return dict(self._data[3])
56 return dict(self._data[3])
55
57
56 def date(self):
58 def date(self):
57 """Creation date as (unixtime, offset)"""
59 """Creation date as (unixtime, offset)"""
58 return self._data[4]
60 return self._data[4]
59
61
60 def flags(self):
62 def flags(self):
61 """The flags field of the marker"""
63 """The flags field of the marker"""
62 return self._data[2]
64 return self._data[2]
63
65
64 def getmarkers(repo, nodes=None, exclusive=False):
66 def getmarkers(repo, nodes=None, exclusive=False):
65 """returns markers known in a repository
67 """returns markers known in a repository
66
68
67 If <nodes> is specified, only markers "relevant" to those nodes are are
69 If <nodes> is specified, only markers "relevant" to those nodes are are
68 returned"""
70 returned"""
69 if nodes is None:
71 if nodes is None:
70 rawmarkers = repo.obsstore
72 rawmarkers = repo.obsstore
71 elif exclusive:
73 elif exclusive:
72 rawmarkers = exclusivemarkers(repo, nodes)
74 rawmarkers = exclusivemarkers(repo, nodes)
73 else:
75 else:
74 rawmarkers = repo.obsstore.relevantmarkers(nodes)
76 rawmarkers = repo.obsstore.relevantmarkers(nodes)
75
77
76 for markerdata in rawmarkers:
78 for markerdata in rawmarkers:
77 yield marker(repo, markerdata)
79 yield marker(repo, markerdata)
78
80
79 def closestpredecessors(repo, nodeid):
81 def closestpredecessors(repo, nodeid):
80 """yield the list of next predecessors pointing on visible changectx nodes
82 """yield the list of next predecessors pointing on visible changectx nodes
81
83
82 This function respect the repoview filtering, filtered revision will be
84 This function respect the repoview filtering, filtered revision will be
83 considered missing.
85 considered missing.
84 """
86 """
85
87
86 precursors = repo.obsstore.predecessors
88 precursors = repo.obsstore.predecessors
87 stack = [nodeid]
89 stack = [nodeid]
88 seen = set(stack)
90 seen = set(stack)
89
91
90 while stack:
92 while stack:
91 current = stack.pop()
93 current = stack.pop()
92 currentpreccs = precursors.get(current, ())
94 currentpreccs = precursors.get(current, ())
93
95
94 for prec in currentpreccs:
96 for prec in currentpreccs:
95 precnodeid = prec[0]
97 precnodeid = prec[0]
96
98
97 # Basic cycle protection
99 # Basic cycle protection
98 if precnodeid in seen:
100 if precnodeid in seen:
99 continue
101 continue
100 seen.add(precnodeid)
102 seen.add(precnodeid)
101
103
102 if precnodeid in repo:
104 if precnodeid in repo:
103 yield precnodeid
105 yield precnodeid
104 else:
106 else:
105 stack.append(precnodeid)
107 stack.append(precnodeid)
106
108
107 def allprecursors(*args, **kwargs):
109 def allprecursors(*args, **kwargs):
108 """ (DEPRECATED)
110 """ (DEPRECATED)
109 """
111 """
110 msg = ("'obsutil.allprecursors' is deprecated, "
112 msg = ("'obsutil.allprecursors' is deprecated, "
111 "use 'obsutil.allpredecessors'")
113 "use 'obsutil.allpredecessors'")
112 util.nouideprecwarn(msg, '4.4')
114 util.nouideprecwarn(msg, '4.4')
113
115
114 return allpredecessors(*args, **kwargs)
116 return allpredecessors(*args, **kwargs)
115
117
116 def allpredecessors(obsstore, nodes, ignoreflags=0):
118 def allpredecessors(obsstore, nodes, ignoreflags=0):
117 """Yield node for every precursors of <nodes>.
119 """Yield node for every precursors of <nodes>.
118
120
119 Some precursors may be unknown locally.
121 Some precursors may be unknown locally.
120
122
121 This is a linear yield unsuited to detecting folded changesets. It includes
123 This is a linear yield unsuited to detecting folded changesets. It includes
122 initial nodes too."""
124 initial nodes too."""
123
125
124 remaining = set(nodes)
126 remaining = set(nodes)
125 seen = set(remaining)
127 seen = set(remaining)
126 while remaining:
128 while remaining:
127 current = remaining.pop()
129 current = remaining.pop()
128 yield current
130 yield current
129 for mark in obsstore.predecessors.get(current, ()):
131 for mark in obsstore.predecessors.get(current, ()):
130 # ignore marker flagged with specified flag
132 # ignore marker flagged with specified flag
131 if mark[2] & ignoreflags:
133 if mark[2] & ignoreflags:
132 continue
134 continue
133 suc = mark[0]
135 suc = mark[0]
134 if suc not in seen:
136 if suc not in seen:
135 seen.add(suc)
137 seen.add(suc)
136 remaining.add(suc)
138 remaining.add(suc)
137
139
138 def allsuccessors(obsstore, nodes, ignoreflags=0):
140 def allsuccessors(obsstore, nodes, ignoreflags=0):
139 """Yield node for every successor of <nodes>.
141 """Yield node for every successor of <nodes>.
140
142
141 Some successors may be unknown locally.
143 Some successors may be unknown locally.
142
144
143 This is a linear yield unsuited to detecting split changesets. It includes
145 This is a linear yield unsuited to detecting split changesets. It includes
144 initial nodes too."""
146 initial nodes too."""
145 remaining = set(nodes)
147 remaining = set(nodes)
146 seen = set(remaining)
148 seen = set(remaining)
147 while remaining:
149 while remaining:
148 current = remaining.pop()
150 current = remaining.pop()
149 yield current
151 yield current
150 for mark in obsstore.successors.get(current, ()):
152 for mark in obsstore.successors.get(current, ()):
151 # ignore marker flagged with specified flag
153 # ignore marker flagged with specified flag
152 if mark[2] & ignoreflags:
154 if mark[2] & ignoreflags:
153 continue
155 continue
154 for suc in mark[1]:
156 for suc in mark[1]:
155 if suc not in seen:
157 if suc not in seen:
156 seen.add(suc)
158 seen.add(suc)
157 remaining.add(suc)
159 remaining.add(suc)
158
160
159 def _filterprunes(markers):
161 def _filterprunes(markers):
160 """return a set with no prune markers"""
162 """return a set with no prune markers"""
161 return set(m for m in markers if m[1])
163 return set(m for m in markers if m[1])
162
164
163 def exclusivemarkers(repo, nodes):
165 def exclusivemarkers(repo, nodes):
164 """set of markers relevant to "nodes" but no other locally-known nodes
166 """set of markers relevant to "nodes" but no other locally-known nodes
165
167
166 This function compute the set of markers "exclusive" to a locally-known
168 This function compute the set of markers "exclusive" to a locally-known
167 node. This means we walk the markers starting from <nodes> until we reach a
169 node. This means we walk the markers starting from <nodes> until we reach a
168 locally-known precursors outside of <nodes>. Element of <nodes> with
170 locally-known precursors outside of <nodes>. Element of <nodes> with
169 locally-known successors outside of <nodes> are ignored (since their
171 locally-known successors outside of <nodes> are ignored (since their
170 precursors markers are also relevant to these successors).
172 precursors markers are also relevant to these successors).
171
173
172 For example:
174 For example:
173
175
174 # (A0 rewritten as A1)
176 # (A0 rewritten as A1)
175 #
177 #
176 # A0 <-1- A1 # Marker "1" is exclusive to A1
178 # A0 <-1- A1 # Marker "1" is exclusive to A1
177
179
178 or
180 or
179
181
180 # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally)
182 # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally)
181 #
183 #
182 # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1
184 # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1
183
185
184 or
186 or
185
187
186 # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence))
188 # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence))
187 #
189 #
188 # <-2- A1 # Marker "2" is exclusive to A0,A1
190 # <-2- A1 # Marker "2" is exclusive to A0,A1
189 # /
191 # /
190 # <-1- A0
192 # <-1- A0
191 # \
193 # \
192 # <-3- A2 # Marker "3" is exclusive to A0,A2
194 # <-3- A2 # Marker "3" is exclusive to A0,A2
193 #
195 #
194 # in addition:
196 # in addition:
195 #
197 #
196 # Markers "2,3" are exclusive to A1,A2
198 # Markers "2,3" are exclusive to A1,A2
197 # Markers "1,2,3" are exclusive to A0,A1,A2
199 # Markers "1,2,3" are exclusive to A0,A1,A2
198
200
199 See test/test-obsolete-bundle-strip.t for more examples.
201 See test/test-obsolete-bundle-strip.t for more examples.
200
202
201 An example usage is strip. When stripping a changeset, we also want to
203 An example usage is strip. When stripping a changeset, we also want to
202 strip the markers exclusive to this changeset. Otherwise we would have
204 strip the markers exclusive to this changeset. Otherwise we would have
203 "dangling"" obsolescence markers from its precursors: Obsolescence markers
205 "dangling"" obsolescence markers from its precursors: Obsolescence markers
204 marking a node as obsolete without any successors available locally.
206 marking a node as obsolete without any successors available locally.
205
207
206 As for relevant markers, the prune markers for children will be followed.
208 As for relevant markers, the prune markers for children will be followed.
207 Of course, they will only be followed if the pruned children is
209 Of course, they will only be followed if the pruned children is
208 locally-known. Since the prune markers are relevant to the pruned node.
210 locally-known. Since the prune markers are relevant to the pruned node.
209 However, while prune markers are considered relevant to the parent of the
211 However, while prune markers are considered relevant to the parent of the
210 pruned changesets, prune markers for locally-known changeset (with no
212 pruned changesets, prune markers for locally-known changeset (with no
211 successors) are considered exclusive to the pruned nodes. This allows
213 successors) are considered exclusive to the pruned nodes. This allows
212 to strip the prune markers (with the rest of the exclusive chain) alongside
214 to strip the prune markers (with the rest of the exclusive chain) alongside
213 the pruned changesets.
215 the pruned changesets.
214 """
216 """
215 # running on a filtered repository would be dangerous as markers could be
217 # running on a filtered repository would be dangerous as markers could be
216 # reported as exclusive when they are relevant for other filtered nodes.
218 # reported as exclusive when they are relevant for other filtered nodes.
217 unfi = repo.unfiltered()
219 unfi = repo.unfiltered()
218
220
219 # shortcut to various useful item
221 # shortcut to various useful item
220 nm = unfi.changelog.nodemap
222 nm = unfi.changelog.nodemap
221 precursorsmarkers = unfi.obsstore.predecessors
223 precursorsmarkers = unfi.obsstore.predecessors
222 successormarkers = unfi.obsstore.successors
224 successormarkers = unfi.obsstore.successors
223 childrenmarkers = unfi.obsstore.children
225 childrenmarkers = unfi.obsstore.children
224
226
225 # exclusive markers (return of the function)
227 # exclusive markers (return of the function)
226 exclmarkers = set()
228 exclmarkers = set()
227 # we need fast membership testing
229 # we need fast membership testing
228 nodes = set(nodes)
230 nodes = set(nodes)
229 # looking for head in the obshistory
231 # looking for head in the obshistory
230 #
232 #
231 # XXX we are ignoring all issues in regard with cycle for now.
233 # XXX we are ignoring all issues in regard with cycle for now.
232 stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))]
234 stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))]
233 stack.sort()
235 stack.sort()
234 # nodes already stacked
236 # nodes already stacked
235 seennodes = set(stack)
237 seennodes = set(stack)
236 while stack:
238 while stack:
237 current = stack.pop()
239 current = stack.pop()
238 # fetch precursors markers
240 # fetch precursors markers
239 markers = list(precursorsmarkers.get(current, ()))
241 markers = list(precursorsmarkers.get(current, ()))
240 # extend the list with prune markers
242 # extend the list with prune markers
241 for mark in successormarkers.get(current, ()):
243 for mark in successormarkers.get(current, ()):
242 if not mark[1]:
244 if not mark[1]:
243 markers.append(mark)
245 markers.append(mark)
244 # and markers from children (looking for prune)
246 # and markers from children (looking for prune)
245 for mark in childrenmarkers.get(current, ()):
247 for mark in childrenmarkers.get(current, ()):
246 if not mark[1]:
248 if not mark[1]:
247 markers.append(mark)
249 markers.append(mark)
248 # traverse the markers
250 # traverse the markers
249 for mark in markers:
251 for mark in markers:
250 if mark in exclmarkers:
252 if mark in exclmarkers:
251 # markers already selected
253 # markers already selected
252 continue
254 continue
253
255
254 # If the markers is about the current node, select it
256 # If the markers is about the current node, select it
255 #
257 #
256 # (this delay the addition of markers from children)
258 # (this delay the addition of markers from children)
257 if mark[1] or mark[0] == current:
259 if mark[1] or mark[0] == current:
258 exclmarkers.add(mark)
260 exclmarkers.add(mark)
259
261
260 # should we keep traversing through the precursors?
262 # should we keep traversing through the precursors?
261 prec = mark[0]
263 prec = mark[0]
262
264
263 # nodes in the stack or already processed
265 # nodes in the stack or already processed
264 if prec in seennodes:
266 if prec in seennodes:
265 continue
267 continue
266
268
267 # is this a locally known node ?
269 # is this a locally known node ?
268 known = prec in nm
270 known = prec in nm
269 # if locally-known and not in the <nodes> set the traversal
271 # if locally-known and not in the <nodes> set the traversal
270 # stop here.
272 # stop here.
271 if known and prec not in nodes:
273 if known and prec not in nodes:
272 continue
274 continue
273
275
274 # do not keep going if there are unselected markers pointing to this
276 # do not keep going if there are unselected markers pointing to this
275 # nodes. If we end up traversing these unselected markers later the
277 # nodes. If we end up traversing these unselected markers later the
276 # node will be taken care of at that point.
278 # node will be taken care of at that point.
277 precmarkers = _filterprunes(successormarkers.get(prec))
279 precmarkers = _filterprunes(successormarkers.get(prec))
278 if precmarkers.issubset(exclmarkers):
280 if precmarkers.issubset(exclmarkers):
279 seennodes.add(prec)
281 seennodes.add(prec)
280 stack.append(prec)
282 stack.append(prec)
281
283
282 return exclmarkers
284 return exclmarkers
283
285
284 def foreground(repo, nodes):
286 def foreground(repo, nodes):
285 """return all nodes in the "foreground" of other node
287 """return all nodes in the "foreground" of other node
286
288
287 The foreground of a revision is anything reachable using parent -> children
289 The foreground of a revision is anything reachable using parent -> children
288 or precursor -> successor relation. It is very similar to "descendant" but
290 or precursor -> successor relation. It is very similar to "descendant" but
289 augmented with obsolescence information.
291 augmented with obsolescence information.
290
292
291 Beware that possible obsolescence cycle may result if complex situation.
293 Beware that possible obsolescence cycle may result if complex situation.
292 """
294 """
293 repo = repo.unfiltered()
295 repo = repo.unfiltered()
294 foreground = set(repo.set('%ln::', nodes))
296 foreground = set(repo.set('%ln::', nodes))
295 if repo.obsstore:
297 if repo.obsstore:
296 # We only need this complicated logic if there is obsolescence
298 # We only need this complicated logic if there is obsolescence
297 # XXX will probably deserve an optimised revset.
299 # XXX will probably deserve an optimised revset.
298 nm = repo.changelog.nodemap
300 nm = repo.changelog.nodemap
299 plen = -1
301 plen = -1
300 # compute the whole set of successors or descendants
302 # compute the whole set of successors or descendants
301 while len(foreground) != plen:
303 while len(foreground) != plen:
302 plen = len(foreground)
304 plen = len(foreground)
303 succs = set(c.node() for c in foreground)
305 succs = set(c.node() for c in foreground)
304 mutable = [c.node() for c in foreground if c.mutable()]
306 mutable = [c.node() for c in foreground if c.mutable()]
305 succs.update(allsuccessors(repo.obsstore, mutable))
307 succs.update(allsuccessors(repo.obsstore, mutable))
306 known = (n for n in succs if n in nm)
308 known = (n for n in succs if n in nm)
307 foreground = set(repo.set('%ln::', known))
309 foreground = set(repo.set('%ln::', known))
308 return set(c.node() for c in foreground)
310 return set(c.node() for c in foreground)
309
311
310 # effectflag field
312 # effectflag field
311 #
313 #
312 # Effect-flag is a 1-byte bit field used to store what changed between a
314 # Effect-flag is a 1-byte bit field used to store what changed between a
313 # changeset and its successor(s).
315 # changeset and its successor(s).
314 #
316 #
315 # The effect flag is stored in obs-markers metadata while we iterate on the
317 # The effect flag is stored in obs-markers metadata while we iterate on the
316 # information design. That's why we have the EFFECTFLAGFIELD. If we come up
318 # information design. That's why we have the EFFECTFLAGFIELD. If we come up
317 # with an incompatible design for effect flag, we can store a new design under
319 # with an incompatible design for effect flag, we can store a new design under
318 # another field name so we don't break readers. We plan to extend the existing
320 # another field name so we don't break readers. We plan to extend the existing
319 # obsmarkers bit-field when the effect flag design will be stabilized.
321 # obsmarkers bit-field when the effect flag design will be stabilized.
320 #
322 #
321 # The effect-flag is placed behind an experimental flag
323 # The effect-flag is placed behind an experimental flag
322 # `effect-flags` set to off by default.
324 # `effect-flags` set to off by default.
323 #
325 #
324
326
325 EFFECTFLAGFIELD = "ef1"
327 EFFECTFLAGFIELD = "ef1"
326
328
327 DESCCHANGED = 1 << 0 # action changed the description
329 DESCCHANGED = 1 << 0 # action changed the description
328 METACHANGED = 1 << 1 # action change the meta
330 METACHANGED = 1 << 1 # action change the meta
329 DIFFCHANGED = 1 << 3 # action change diff introduced by the changeset
331 DIFFCHANGED = 1 << 3 # action change diff introduced by the changeset
330 PARENTCHANGED = 1 << 2 # action change the parent
332 PARENTCHANGED = 1 << 2 # action change the parent
331 USERCHANGED = 1 << 4 # the user changed
333 USERCHANGED = 1 << 4 # the user changed
332 DATECHANGED = 1 << 5 # the date changed
334 DATECHANGED = 1 << 5 # the date changed
333 BRANCHCHANGED = 1 << 6 # the branch changed
335 BRANCHCHANGED = 1 << 6 # the branch changed
334
336
335 METABLACKLIST = [
337 METABLACKLIST = [
336 re.compile('^branch$'),
338 re.compile('^branch$'),
337 re.compile('^.*-source$'),
339 re.compile('^.*-source$'),
338 re.compile('^.*_source$'),
340 re.compile('^.*_source$'),
339 re.compile('^source$'),
341 re.compile('^source$'),
340 ]
342 ]
341
343
342 def metanotblacklisted(metaitem):
344 def metanotblacklisted(metaitem):
343 """ Check that the key of a meta item (extrakey, extravalue) does not
345 """ Check that the key of a meta item (extrakey, extravalue) does not
344 match at least one of the blacklist pattern
346 match at least one of the blacklist pattern
345 """
347 """
346 metakey = metaitem[0]
348 metakey = metaitem[0]
347
349
348 return not any(pattern.match(metakey) for pattern in METABLACKLIST)
350 return not any(pattern.match(metakey) for pattern in METABLACKLIST)
349
351
350 def _prepare_hunk(hunk):
352 def _prepare_hunk(hunk):
351 """Drop all information but the username and patch"""
353 """Drop all information but the username and patch"""
352 cleanhunk = []
354 cleanhunk = []
353 for line in hunk.splitlines():
355 for line in hunk.splitlines():
354 if line.startswith(b'# User') or not line.startswith(b'#'):
356 if line.startswith(b'# User') or not line.startswith(b'#'):
355 if line.startswith(b'@@'):
357 if line.startswith(b'@@'):
356 line = b'@@\n'
358 line = b'@@\n'
357 cleanhunk.append(line)
359 cleanhunk.append(line)
358 return cleanhunk
360 return cleanhunk
359
361
360 def _getdifflines(iterdiff):
362 def _getdifflines(iterdiff):
361 """return a cleaned up lines"""
363 """return a cleaned up lines"""
362 lines = next(iterdiff, None)
364 lines = next(iterdiff, None)
363
365
364 if lines is None:
366 if lines is None:
365 return lines
367 return lines
366
368
367 return _prepare_hunk(lines)
369 return _prepare_hunk(lines)
368
370
369 def _cmpdiff(leftctx, rightctx):
371 def _cmpdiff(leftctx, rightctx):
370 """return True if both ctx introduce the "same diff"
372 """return True if both ctx introduce the "same diff"
371
373
372 This is a first and basic implementation, with many shortcoming.
374 This is a first and basic implementation, with many shortcoming.
373 """
375 """
374
376
375 # Leftctx or right ctx might be filtered, so we need to use the contexts
377 # Leftctx or right ctx might be filtered, so we need to use the contexts
376 # with an unfiltered repository to safely compute the diff
378 # with an unfiltered repository to safely compute the diff
377 leftunfi = leftctx._repo.unfiltered()[leftctx.rev()]
379 leftunfi = leftctx._repo.unfiltered()[leftctx.rev()]
378 leftdiff = leftunfi.diff(git=1)
380 leftdiff = leftunfi.diff(git=1)
379 rightunfi = rightctx._repo.unfiltered()[rightctx.rev()]
381 rightunfi = rightctx._repo.unfiltered()[rightctx.rev()]
380 rightdiff = rightunfi.diff(git=1)
382 rightdiff = rightunfi.diff(git=1)
381
383
382 left, right = (0, 0)
384 left, right = (0, 0)
383 while None not in (left, right):
385 while None not in (left, right):
384 left = _getdifflines(leftdiff)
386 left = _getdifflines(leftdiff)
385 right = _getdifflines(rightdiff)
387 right = _getdifflines(rightdiff)
386
388
387 if left != right:
389 if left != right:
388 return False
390 return False
389 return True
391 return True
390
392
391 def geteffectflag(relation):
393 def geteffectflag(relation):
392 """ From an obs-marker relation, compute what changed between the
394 """ From an obs-marker relation, compute what changed between the
393 predecessor and the successor.
395 predecessor and the successor.
394 """
396 """
395 effects = 0
397 effects = 0
396
398
397 source = relation[0]
399 source = relation[0]
398
400
399 for changectx in relation[1]:
401 for changectx in relation[1]:
400 # Check if description has changed
402 # Check if description has changed
401 if changectx.description() != source.description():
403 if changectx.description() != source.description():
402 effects |= DESCCHANGED
404 effects |= DESCCHANGED
403
405
404 # Check if user has changed
406 # Check if user has changed
405 if changectx.user() != source.user():
407 if changectx.user() != source.user():
406 effects |= USERCHANGED
408 effects |= USERCHANGED
407
409
408 # Check if date has changed
410 # Check if date has changed
409 if changectx.date() != source.date():
411 if changectx.date() != source.date():
410 effects |= DATECHANGED
412 effects |= DATECHANGED
411
413
412 # Check if branch has changed
414 # Check if branch has changed
413 if changectx.branch() != source.branch():
415 if changectx.branch() != source.branch():
414 effects |= BRANCHCHANGED
416 effects |= BRANCHCHANGED
415
417
416 # Check if at least one of the parent has changed
418 # Check if at least one of the parent has changed
417 if changectx.parents() != source.parents():
419 if changectx.parents() != source.parents():
418 effects |= PARENTCHANGED
420 effects |= PARENTCHANGED
419
421
420 # Check if other meta has changed
422 # Check if other meta has changed
421 changeextra = changectx.extra().items()
423 changeextra = changectx.extra().items()
422 ctxmeta = filter(metanotblacklisted, changeextra)
424 ctxmeta = filter(metanotblacklisted, changeextra)
423
425
424 sourceextra = source.extra().items()
426 sourceextra = source.extra().items()
425 srcmeta = filter(metanotblacklisted, sourceextra)
427 srcmeta = filter(metanotblacklisted, sourceextra)
426
428
427 if ctxmeta != srcmeta:
429 if ctxmeta != srcmeta:
428 effects |= METACHANGED
430 effects |= METACHANGED
429
431
430 # Check if the diff has changed
432 # Check if the diff has changed
431 if not _cmpdiff(source, changectx):
433 if not _cmpdiff(source, changectx):
432 effects |= DIFFCHANGED
434 effects |= DIFFCHANGED
433
435
434 return effects
436 return effects
435
437
436 def getobsoleted(repo, tr):
438 def getobsoleted(repo, tr):
437 """return the set of pre-existing revisions obsoleted by a transaction"""
439 """return the set of pre-existing revisions obsoleted by a transaction"""
438 torev = repo.unfiltered().changelog.nodemap.get
440 torev = repo.unfiltered().changelog.nodemap.get
439 phase = repo._phasecache.phase
441 phase = repo._phasecache.phase
440 succsmarkers = repo.obsstore.successors.get
442 succsmarkers = repo.obsstore.successors.get
441 public = phases.public
443 public = phases.public
442 addedmarkers = tr.changes.get('obsmarkers')
444 addedmarkers = tr.changes.get('obsmarkers')
443 addedrevs = tr.changes.get('revs')
445 addedrevs = tr.changes.get('revs')
444 seenrevs = set()
446 seenrevs = set()
445 obsoleted = set()
447 obsoleted = set()
446 for mark in addedmarkers:
448 for mark in addedmarkers:
447 node = mark[0]
449 node = mark[0]
448 rev = torev(node)
450 rev = torev(node)
449 if rev is None or rev in seenrevs or rev in addedrevs:
451 if rev is None or rev in seenrevs or rev in addedrevs:
450 continue
452 continue
451 seenrevs.add(rev)
453 seenrevs.add(rev)
452 if phase(repo, rev) == public:
454 if phase(repo, rev) == public:
453 continue
455 continue
454 if set(succsmarkers(node) or []).issubset(addedmarkers):
456 if set(succsmarkers(node) or []).issubset(addedmarkers):
455 obsoleted.add(rev)
457 obsoleted.add(rev)
456 return obsoleted
458 return obsoleted
457
459
458 class _succs(list):
460 class _succs(list):
459 """small class to represent a successors with some metadata about it"""
461 """small class to represent a successors with some metadata about it"""
460
462
461 def __init__(self, *args, **kwargs):
463 def __init__(self, *args, **kwargs):
462 super(_succs, self).__init__(*args, **kwargs)
464 super(_succs, self).__init__(*args, **kwargs)
463 self.markers = set()
465 self.markers = set()
464
466
465 def copy(self):
467 def copy(self):
466 new = _succs(self)
468 new = _succs(self)
467 new.markers = self.markers.copy()
469 new.markers = self.markers.copy()
468 return new
470 return new
469
471
470 @util.propertycache
472 @util.propertycache
471 def _set(self):
473 def _set(self):
472 # immutable
474 # immutable
473 return set(self)
475 return set(self)
474
476
475 def canmerge(self, other):
477 def canmerge(self, other):
476 return self._set.issubset(other._set)
478 return self._set.issubset(other._set)
477
479
478 def successorssets(repo, initialnode, closest=False, cache=None):
480 def successorssets(repo, initialnode, closest=False, cache=None):
479 """Return set of all latest successors of initial nodes
481 """Return set of all latest successors of initial nodes
480
482
481 The successors set of a changeset A are the group of revisions that succeed
483 The successors set of a changeset A are the group of revisions that succeed
482 A. It succeeds A as a consistent whole, each revision being only a partial
484 A. It succeeds A as a consistent whole, each revision being only a partial
483 replacement. By default, the successors set contains non-obsolete
485 replacement. By default, the successors set contains non-obsolete
484 changesets only, walking the obsolescence graph until reaching a leaf. If
486 changesets only, walking the obsolescence graph until reaching a leaf. If
485 'closest' is set to True, closest successors-sets are return (the
487 'closest' is set to True, closest successors-sets are return (the
486 obsolescence walk stops on known changesets).
488 obsolescence walk stops on known changesets).
487
489
488 This function returns the full list of successor sets which is why it
490 This function returns the full list of successor sets which is why it
489 returns a list of tuples and not just a single tuple. Each tuple is a valid
491 returns a list of tuples and not just a single tuple. Each tuple is a valid
490 successors set. Note that (A,) may be a valid successors set for changeset A
492 successors set. Note that (A,) may be a valid successors set for changeset A
491 (see below).
493 (see below).
492
494
493 In most cases, a changeset A will have a single element (e.g. the changeset
495 In most cases, a changeset A will have a single element (e.g. the changeset
494 A is replaced by A') in its successors set. Though, it is also common for a
496 A is replaced by A') in its successors set. Though, it is also common for a
495 changeset A to have no elements in its successor set (e.g. the changeset
497 changeset A to have no elements in its successor set (e.g. the changeset
496 has been pruned). Therefore, the returned list of successors sets will be
498 has been pruned). Therefore, the returned list of successors sets will be
497 [(A',)] or [], respectively.
499 [(A',)] or [], respectively.
498
500
499 When a changeset A is split into A' and B', however, it will result in a
501 When a changeset A is split into A' and B', however, it will result in a
500 successors set containing more than a single element, i.e. [(A',B')].
502 successors set containing more than a single element, i.e. [(A',B')].
501 Divergent changesets will result in multiple successors sets, i.e. [(A',),
503 Divergent changesets will result in multiple successors sets, i.e. [(A',),
502 (A'')].
504 (A'')].
503
505
504 If a changeset A is not obsolete, then it will conceptually have no
506 If a changeset A is not obsolete, then it will conceptually have no
505 successors set. To distinguish this from a pruned changeset, the successor
507 successors set. To distinguish this from a pruned changeset, the successor
506 set will contain itself only, i.e. [(A,)].
508 set will contain itself only, i.e. [(A,)].
507
509
508 Finally, final successors unknown locally are considered to be pruned
510 Finally, final successors unknown locally are considered to be pruned
509 (pruned: obsoleted without any successors). (Final: successors not affected
511 (pruned: obsoleted without any successors). (Final: successors not affected
510 by markers).
512 by markers).
511
513
512 The 'closest' mode respect the repoview filtering. For example, without
514 The 'closest' mode respect the repoview filtering. For example, without
513 filter it will stop at the first locally known changeset, with 'visible'
515 filter it will stop at the first locally known changeset, with 'visible'
514 filter it will stop on visible changesets).
516 filter it will stop on visible changesets).
515
517
516 The optional `cache` parameter is a dictionary that may contains
518 The optional `cache` parameter is a dictionary that may contains
517 precomputed successors sets. It is meant to reuse the computation of a
519 precomputed successors sets. It is meant to reuse the computation of a
518 previous call to `successorssets` when multiple calls are made at the same
520 previous call to `successorssets` when multiple calls are made at the same
519 time. The cache dictionary is updated in place. The caller is responsible
521 time. The cache dictionary is updated in place. The caller is responsible
520 for its life span. Code that makes multiple calls to `successorssets`
522 for its life span. Code that makes multiple calls to `successorssets`
521 *should* use this cache mechanism or risk a performance hit.
523 *should* use this cache mechanism or risk a performance hit.
522
524
523 Since results are different depending of the 'closest' most, the same cache
525 Since results are different depending of the 'closest' most, the same cache
524 cannot be reused for both mode.
526 cannot be reused for both mode.
525 """
527 """
526
528
527 succmarkers = repo.obsstore.successors
529 succmarkers = repo.obsstore.successors
528
530
529 # Stack of nodes we search successors sets for
531 # Stack of nodes we search successors sets for
530 toproceed = [initialnode]
532 toproceed = [initialnode]
531 # set version of above list for fast loop detection
533 # set version of above list for fast loop detection
532 # element added to "toproceed" must be added here
534 # element added to "toproceed" must be added here
533 stackedset = set(toproceed)
535 stackedset = set(toproceed)
534 if cache is None:
536 if cache is None:
535 cache = {}
537 cache = {}
536
538
537 # This while loop is the flattened version of a recursive search for
539 # This while loop is the flattened version of a recursive search for
538 # successors sets
540 # successors sets
539 #
541 #
540 # def successorssets(x):
542 # def successorssets(x):
541 # successors = directsuccessors(x)
543 # successors = directsuccessors(x)
542 # ss = [[]]
544 # ss = [[]]
543 # for succ in directsuccessors(x):
545 # for succ in directsuccessors(x):
544 # # product as in itertools cartesian product
546 # # product as in itertools cartesian product
545 # ss = product(ss, successorssets(succ))
547 # ss = product(ss, successorssets(succ))
546 # return ss
548 # return ss
547 #
549 #
548 # But we can not use plain recursive calls here:
550 # But we can not use plain recursive calls here:
549 # - that would blow the python call stack
551 # - that would blow the python call stack
550 # - obsolescence markers may have cycles, we need to handle them.
552 # - obsolescence markers may have cycles, we need to handle them.
551 #
553 #
552 # The `toproceed` list act as our call stack. Every node we search
554 # The `toproceed` list act as our call stack. Every node we search
553 # successors set for are stacked there.
555 # successors set for are stacked there.
554 #
556 #
555 # The `stackedset` is set version of this stack used to check if a node is
557 # The `stackedset` is set version of this stack used to check if a node is
556 # already stacked. This check is used to detect cycles and prevent infinite
558 # already stacked. This check is used to detect cycles and prevent infinite
557 # loop.
559 # loop.
558 #
560 #
559 # successors set of all nodes are stored in the `cache` dictionary.
561 # successors set of all nodes are stored in the `cache` dictionary.
560 #
562 #
561 # After this while loop ends we use the cache to return the successors sets
563 # After this while loop ends we use the cache to return the successors sets
562 # for the node requested by the caller.
564 # for the node requested by the caller.
563 while toproceed:
565 while toproceed:
564 # Every iteration tries to compute the successors sets of the topmost
566 # Every iteration tries to compute the successors sets of the topmost
565 # node of the stack: CURRENT.
567 # node of the stack: CURRENT.
566 #
568 #
567 # There are four possible outcomes:
569 # There are four possible outcomes:
568 #
570 #
569 # 1) We already know the successors sets of CURRENT:
571 # 1) We already know the successors sets of CURRENT:
570 # -> mission accomplished, pop it from the stack.
572 # -> mission accomplished, pop it from the stack.
571 # 2) Stop the walk:
573 # 2) Stop the walk:
572 # default case: Node is not obsolete
574 # default case: Node is not obsolete
573 # closest case: Node is known at this repo filter level
575 # closest case: Node is known at this repo filter level
574 # -> the node is its own successors sets. Add it to the cache.
576 # -> the node is its own successors sets. Add it to the cache.
575 # 3) We do not know successors set of direct successors of CURRENT:
577 # 3) We do not know successors set of direct successors of CURRENT:
576 # -> We add those successors to the stack.
578 # -> We add those successors to the stack.
577 # 4) We know successors sets of all direct successors of CURRENT:
579 # 4) We know successors sets of all direct successors of CURRENT:
578 # -> We can compute CURRENT successors set and add it to the
580 # -> We can compute CURRENT successors set and add it to the
579 # cache.
581 # cache.
580 #
582 #
581 current = toproceed[-1]
583 current = toproceed[-1]
582
584
583 # case 2 condition is a bit hairy because of closest,
585 # case 2 condition is a bit hairy because of closest,
584 # we compute it on its own
586 # we compute it on its own
585 case2condition = ((current not in succmarkers)
587 case2condition = ((current not in succmarkers)
586 or (closest and current != initialnode
588 or (closest and current != initialnode
587 and current in repo))
589 and current in repo))
588
590
589 if current in cache:
591 if current in cache:
590 # case (1): We already know the successors sets
592 # case (1): We already know the successors sets
591 stackedset.remove(toproceed.pop())
593 stackedset.remove(toproceed.pop())
592 elif case2condition:
594 elif case2condition:
593 # case (2): end of walk.
595 # case (2): end of walk.
594 if current in repo:
596 if current in repo:
595 # We have a valid successors.
597 # We have a valid successors.
596 cache[current] = [_succs((current,))]
598 cache[current] = [_succs((current,))]
597 else:
599 else:
598 # Final obsolete version is unknown locally.
600 # Final obsolete version is unknown locally.
599 # Do not count that as a valid successors
601 # Do not count that as a valid successors
600 cache[current] = []
602 cache[current] = []
601 else:
603 else:
602 # cases (3) and (4)
604 # cases (3) and (4)
603 #
605 #
604 # We proceed in two phases. Phase 1 aims to distinguish case (3)
606 # We proceed in two phases. Phase 1 aims to distinguish case (3)
605 # from case (4):
607 # from case (4):
606 #
608 #
607 # For each direct successors of CURRENT, we check whether its
609 # For each direct successors of CURRENT, we check whether its
608 # successors sets are known. If they are not, we stack the
610 # successors sets are known. If they are not, we stack the
609 # unknown node and proceed to the next iteration of the while
611 # unknown node and proceed to the next iteration of the while
610 # loop. (case 3)
612 # loop. (case 3)
611 #
613 #
612 # During this step, we may detect obsolescence cycles: a node
614 # During this step, we may detect obsolescence cycles: a node
613 # with unknown successors sets but already in the call stack.
615 # with unknown successors sets but already in the call stack.
614 # In such a situation, we arbitrary set the successors sets of
616 # In such a situation, we arbitrary set the successors sets of
615 # the node to nothing (node pruned) to break the cycle.
617 # the node to nothing (node pruned) to break the cycle.
616 #
618 #
617 # If no break was encountered we proceed to phase 2.
619 # If no break was encountered we proceed to phase 2.
618 #
620 #
619 # Phase 2 computes successors sets of CURRENT (case 4); see details
621 # Phase 2 computes successors sets of CURRENT (case 4); see details
620 # in phase 2 itself.
622 # in phase 2 itself.
621 #
623 #
622 # Note the two levels of iteration in each phase.
624 # Note the two levels of iteration in each phase.
623 # - The first one handles obsolescence markers using CURRENT as
625 # - The first one handles obsolescence markers using CURRENT as
624 # precursor (successors markers of CURRENT).
626 # precursor (successors markers of CURRENT).
625 #
627 #
626 # Having multiple entry here means divergence.
628 # Having multiple entry here means divergence.
627 #
629 #
628 # - The second one handles successors defined in each marker.
630 # - The second one handles successors defined in each marker.
629 #
631 #
630 # Having none means pruned node, multiple successors means split,
632 # Having none means pruned node, multiple successors means split,
631 # single successors are standard replacement.
633 # single successors are standard replacement.
632 #
634 #
633 for mark in sorted(succmarkers[current]):
635 for mark in sorted(succmarkers[current]):
634 for suc in mark[1]:
636 for suc in mark[1]:
635 if suc not in cache:
637 if suc not in cache:
636 if suc in stackedset:
638 if suc in stackedset:
637 # cycle breaking
639 # cycle breaking
638 cache[suc] = []
640 cache[suc] = []
639 else:
641 else:
640 # case (3) If we have not computed successors sets
642 # case (3) If we have not computed successors sets
641 # of one of those successors we add it to the
643 # of one of those successors we add it to the
642 # `toproceed` stack and stop all work for this
644 # `toproceed` stack and stop all work for this
643 # iteration.
645 # iteration.
644 toproceed.append(suc)
646 toproceed.append(suc)
645 stackedset.add(suc)
647 stackedset.add(suc)
646 break
648 break
647 else:
649 else:
648 continue
650 continue
649 break
651 break
650 else:
652 else:
651 # case (4): we know all successors sets of all direct
653 # case (4): we know all successors sets of all direct
652 # successors
654 # successors
653 #
655 #
654 # Successors set contributed by each marker depends on the
656 # Successors set contributed by each marker depends on the
655 # successors sets of all its "successors" node.
657 # successors sets of all its "successors" node.
656 #
658 #
657 # Each different marker is a divergence in the obsolescence
659 # Each different marker is a divergence in the obsolescence
658 # history. It contributes successors sets distinct from other
660 # history. It contributes successors sets distinct from other
659 # markers.
661 # markers.
660 #
662 #
661 # Within a marker, a successor may have divergent successors
663 # Within a marker, a successor may have divergent successors
662 # sets. In such a case, the marker will contribute multiple
664 # sets. In such a case, the marker will contribute multiple
663 # divergent successors sets. If multiple successors have
665 # divergent successors sets. If multiple successors have
664 # divergent successors sets, a Cartesian product is used.
666 # divergent successors sets, a Cartesian product is used.
665 #
667 #
666 # At the end we post-process successors sets to remove
668 # At the end we post-process successors sets to remove
667 # duplicated entry and successors set that are strict subset of
669 # duplicated entry and successors set that are strict subset of
668 # another one.
670 # another one.
669 succssets = []
671 succssets = []
670 for mark in sorted(succmarkers[current]):
672 for mark in sorted(succmarkers[current]):
671 # successors sets contributed by this marker
673 # successors sets contributed by this marker
672 base = _succs()
674 base = _succs()
673 base.markers.add(mark)
675 base.markers.add(mark)
674 markss = [base]
676 markss = [base]
675 for suc in mark[1]:
677 for suc in mark[1]:
676 # cardinal product with previous successors
678 # cardinal product with previous successors
677 productresult = []
679 productresult = []
678 for prefix in markss:
680 for prefix in markss:
679 for suffix in cache[suc]:
681 for suffix in cache[suc]:
680 newss = prefix.copy()
682 newss = prefix.copy()
681 newss.markers.update(suffix.markers)
683 newss.markers.update(suffix.markers)
682 for part in suffix:
684 for part in suffix:
683 # do not duplicated entry in successors set
685 # do not duplicated entry in successors set
684 # first entry wins.
686 # first entry wins.
685 if part not in newss:
687 if part not in newss:
686 newss.append(part)
688 newss.append(part)
687 productresult.append(newss)
689 productresult.append(newss)
688 markss = productresult
690 markss = productresult
689 succssets.extend(markss)
691 succssets.extend(markss)
690 # remove duplicated and subset
692 # remove duplicated and subset
691 seen = []
693 seen = []
692 final = []
694 final = []
693 candidates = sorted((s for s in succssets if s),
695 candidates = sorted((s for s in succssets if s),
694 key=len, reverse=True)
696 key=len, reverse=True)
695 for cand in candidates:
697 for cand in candidates:
696 for seensuccs in seen:
698 for seensuccs in seen:
697 if cand.canmerge(seensuccs):
699 if cand.canmerge(seensuccs):
698 seensuccs.markers.update(cand.markers)
700 seensuccs.markers.update(cand.markers)
699 break
701 break
700 else:
702 else:
701 final.append(cand)
703 final.append(cand)
702 seen.append(cand)
704 seen.append(cand)
703 final.reverse() # put small successors set first
705 final.reverse() # put small successors set first
704 cache[current] = final
706 cache[current] = final
705 return cache[initialnode]
707 return cache[initialnode]
706
708
707 def successorsandmarkers(repo, ctx):
709 def successorsandmarkers(repo, ctx):
708 """compute the raw data needed for computing obsfate
710 """compute the raw data needed for computing obsfate
709 Returns a list of dict, one dict per successors set
711 Returns a list of dict, one dict per successors set
710 """
712 """
711 if not ctx.obsolete():
713 if not ctx.obsolete():
712 return None
714 return None
713
715
714 ssets = successorssets(repo, ctx.node(), closest=True)
716 ssets = successorssets(repo, ctx.node(), closest=True)
715
717
716 # closestsuccessors returns an empty list for pruned revisions, remap it
718 # closestsuccessors returns an empty list for pruned revisions, remap it
717 # into a list containing an empty list for future processing
719 # into a list containing an empty list for future processing
718 if ssets == []:
720 if ssets == []:
719 ssets = [[]]
721 ssets = [[]]
720
722
721 # Try to recover pruned markers
723 # Try to recover pruned markers
722 succsmap = repo.obsstore.successors
724 succsmap = repo.obsstore.successors
723 fullsuccessorsets = [] # successor set + markers
725 fullsuccessorsets = [] # successor set + markers
724 for sset in ssets:
726 for sset in ssets:
725 if sset:
727 if sset:
726 fullsuccessorsets.append(sset)
728 fullsuccessorsets.append(sset)
727 else:
729 else:
728 # successorsset return an empty set() when ctx or one of its
730 # successorsset return an empty set() when ctx or one of its
729 # successors is pruned.
731 # successors is pruned.
730 # In this case, walk the obs-markers tree again starting with ctx
732 # In this case, walk the obs-markers tree again starting with ctx
731 # and find the relevant pruning obs-makers, the ones without
733 # and find the relevant pruning obs-makers, the ones without
732 # successors.
734 # successors.
733 # Having these markers allow us to compute some information about
735 # Having these markers allow us to compute some information about
734 # its fate, like who pruned this changeset and when.
736 # its fate, like who pruned this changeset and when.
735
737
736 # XXX we do not catch all prune markers (eg rewritten then pruned)
738 # XXX we do not catch all prune markers (eg rewritten then pruned)
737 # (fix me later)
739 # (fix me later)
738 foundany = False
740 foundany = False
739 for mark in succsmap.get(ctx.node(), ()):
741 for mark in succsmap.get(ctx.node(), ()):
740 if not mark[1]:
742 if not mark[1]:
741 foundany = True
743 foundany = True
742 sset = _succs()
744 sset = _succs()
743 sset.markers.add(mark)
745 sset.markers.add(mark)
744 fullsuccessorsets.append(sset)
746 fullsuccessorsets.append(sset)
745 if not foundany:
747 if not foundany:
746 fullsuccessorsets.append(_succs())
748 fullsuccessorsets.append(_succs())
747
749
748 values = []
750 values = []
749 for sset in fullsuccessorsets:
751 for sset in fullsuccessorsets:
750 values.append({'successors': sset, 'markers': sset.markers})
752 values.append({'successors': sset, 'markers': sset.markers})
751
753
752 return values
754 return values
753
755
756 def _getobsfate(successorssets):
757 """ Compute a changeset obsolescence fate based on its successorssets.
758 Successors can be the tipmost ones or the immediate ones. This function
759 return values are not meant to be shown directly to users, it is meant to
760 be used by internal functions only.
761 Returns one fate from the following values:
762 - pruned
763 - diverged
764 - superseded
765 - superseded_split
766 """
767
768 if len(successorssets) == 0:
769 # The commit has been pruned
770 return 'pruned'
771 elif len(successorssets) > 1:
772 return 'diverged'
773 else:
774 # No divergence, only one set of successors
775 successors = successorssets[0]
776
777 if len(successors) == 1:
778 return 'superseded'
779 else:
780 return 'superseded_split'
781
754 def obsfateverb(successorset, markers):
782 def obsfateverb(successorset, markers):
755 """ Return the verb summarizing the successorset and potentially using
783 """ Return the verb summarizing the successorset and potentially using
756 information from the markers
784 information from the markers
757 """
785 """
758 if not successorset:
786 if not successorset:
759 verb = 'pruned'
787 verb = 'pruned'
760 elif len(successorset) == 1:
788 elif len(successorset) == 1:
761 verb = 'rewritten'
789 verb = 'rewritten'
762 else:
790 else:
763 verb = 'split'
791 verb = 'split'
764 return verb
792 return verb
765
793
766 def markersdates(markers):
794 def markersdates(markers):
767 """returns the list of dates for a list of markers
795 """returns the list of dates for a list of markers
768 """
796 """
769 return [m[4] for m in markers]
797 return [m[4] for m in markers]
770
798
771 def markersusers(markers):
799 def markersusers(markers):
772 """ Returns a sorted list of markers users without duplicates
800 """ Returns a sorted list of markers users without duplicates
773 """
801 """
774 markersmeta = [dict(m[3]) for m in markers]
802 markersmeta = [dict(m[3]) for m in markers]
775 users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
803 users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
776
804
777 return sorted(users)
805 return sorted(users)
778
806
779 def markersoperations(markers):
807 def markersoperations(markers):
780 """ Returns a sorted list of markers operations without duplicates
808 """ Returns a sorted list of markers operations without duplicates
781 """
809 """
782 markersmeta = [dict(m[3]) for m in markers]
810 markersmeta = [dict(m[3]) for m in markers]
783 operations = set(meta.get('operation') for meta in markersmeta
811 operations = set(meta.get('operation') for meta in markersmeta
784 if meta.get('operation'))
812 if meta.get('operation'))
785
813
786 return sorted(operations)
814 return sorted(operations)
787
815
788 def obsfateprinter(successors, markers, ui):
816 def obsfateprinter(successors, markers, ui):
789 """ Build a obsfate string for a single successorset using all obsfate
817 """ Build a obsfate string for a single successorset using all obsfate
790 related function defined in obsutil
818 related function defined in obsutil
791 """
819 """
792 quiet = ui.quiet
820 quiet = ui.quiet
793 verbose = ui.verbose
821 verbose = ui.verbose
794 normal = not verbose and not quiet
822 normal = not verbose and not quiet
795
823
796 line = []
824 line = []
797
825
798 # Verb
826 # Verb
799 line.append(obsfateverb(successors, markers))
827 line.append(obsfateverb(successors, markers))
800
828
801 # Operations
829 # Operations
802 operations = markersoperations(markers)
830 operations = markersoperations(markers)
803 if operations:
831 if operations:
804 line.append(" using %s" % ", ".join(operations))
832 line.append(" using %s" % ", ".join(operations))
805
833
806 # Successors
834 # Successors
807 if successors:
835 if successors:
808 fmtsuccessors = [successors.joinfmt(succ) for succ in successors]
836 fmtsuccessors = [successors.joinfmt(succ) for succ in successors]
809 line.append(" as %s" % ", ".join(fmtsuccessors))
837 line.append(" as %s" % ", ".join(fmtsuccessors))
810
838
811 # Users
839 # Users
812 users = markersusers(markers)
840 users = markersusers(markers)
813 # Filter out current user in not verbose mode to reduce amount of
841 # Filter out current user in not verbose mode to reduce amount of
814 # information
842 # information
815 if not verbose:
843 if not verbose:
816 currentuser = ui.username(acceptempty=True)
844 currentuser = ui.username(acceptempty=True)
817 if len(users) == 1 and currentuser in users:
845 if len(users) == 1 and currentuser in users:
818 users = None
846 users = None
819
847
820 if (verbose or normal) and users:
848 if (verbose or normal) and users:
821 line.append(" by %s" % ", ".join(users))
849 line.append(" by %s" % ", ".join(users))
822
850
823 # Date
851 # Date
824 dates = markersdates(markers)
852 dates = markersdates(markers)
825
853
826 if dates and verbose:
854 if dates and verbose:
827 min_date = min(dates)
855 min_date = min(dates)
828 max_date = max(dates)
856 max_date = max(dates)
829
857
830 if min_date == max_date:
858 if min_date == max_date:
831 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
859 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
832 line.append(" (at %s)" % fmtmin_date)
860 line.append(" (at %s)" % fmtmin_date)
833 else:
861 else:
834 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
862 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
835 fmtmax_date = util.datestr(max_date, '%Y-%m-%d %H:%M %1%2')
863 fmtmax_date = util.datestr(max_date, '%Y-%m-%d %H:%M %1%2')
836 line.append(" (between %s and %s)" % (fmtmin_date, fmtmax_date))
864 line.append(" (between %s and %s)" % (fmtmin_date, fmtmax_date))
837
865
838 return "".join(line)
866 return "".join(line)
867
868 def _getfilteredreason(unfilteredrepo, ctx):
869 """return a human-friendly string on why a obsolete changeset is hidden
870 """
871 successors = successorssets(unfilteredrepo, ctx.node())
872 fate = _getobsfate(successors)
873
874 # Be more precise in case the revision is superseded
875 if fate == 'pruned':
876 reason = _('is pruned')
877 elif fate == 'diverged':
878 reason = _('has diverged')
879 elif fate == 'superseded':
880 reason = _("was rewritten as: %s") % nodemod.short(successors[0][0])
881 elif fate == 'superseded_split':
882
883 succs = []
884 for node_id in successors[0]:
885 succs.append(nodemod.short(node_id))
886
887 if len(succs) <= 2:
888 reason = _("was split as: %s") % ", ".join(succs)
889 else:
890 firstsuccessors = ", ".join(succs[:2])
891 remainingnumber = len(succs) - 2
892
893 args = (firstsuccessors, remainingnumber)
894 successorsmsg = _("%s and %d more") % args
895 reason = _("was split as: %s") % successorsmsg
896
897 return reason
@@ -1,188 +1,188 b''
1 Tests for access level on hidden commits by various commands on based of their
1 Tests for access level on hidden commits by various commands on based of their
2 type.
2 type.
3
3
4 Setting the required config to start this
4 Setting the required config to start this
5
5
6 $ cat >> $HGRCPATH <<EOF
6 $ cat >> $HGRCPATH <<EOF
7 > [experimental]
7 > [experimental]
8 > evolution=createmarkers, allowunstable
8 > evolution=createmarkers, allowunstable
9 > directaccess=True
9 > directaccess=True
10 > directaccess.revnums=True
10 > directaccess.revnums=True
11 > [extensions]
11 > [extensions]
12 > amend =
12 > amend =
13 > EOF
13 > EOF
14
14
15 $ hg init repo
15 $ hg init repo
16 $ cd repo
16 $ cd repo
17 $ for ch in a b c; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
17 $ for ch in a b c; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
18
18
19 $ hg log -G -T '{rev}:{node} {desc}' --hidden
19 $ hg log -G -T '{rev}:{node} {desc}' --hidden
20 @ 2:28ad74487de9599d00d81085be739c61fc340652 Added c
20 @ 2:28ad74487de9599d00d81085be739c61fc340652 Added c
21 |
21 |
22 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
22 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
23 |
23 |
24 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
24 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
25
25
26 $ echo "bar" >> c
26 $ echo "bar" >> c
27 $ hg amend
27 $ hg amend
28
28
29 $ hg log -G -T '{rev}:{node} {desc}' --hidden
29 $ hg log -G -T '{rev}:{node} {desc}' --hidden
30 @ 3:2443a0e664694756d8b435d06b6ad84f941b6fc0 Added c
30 @ 3:2443a0e664694756d8b435d06b6ad84f941b6fc0 Added c
31 |
31 |
32 | x 2:28ad74487de9599d00d81085be739c61fc340652 Added c
32 | x 2:28ad74487de9599d00d81085be739c61fc340652 Added c
33 |/
33 |/
34 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
34 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
35 |
35 |
36 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
36 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
37
37
38 Testing read only commands on the hidden revision
38 Testing read only commands on the hidden revision
39
39
40 Testing with rev number
40 Testing with rev number
41
41
42 $ hg exp 2 --config experimental.directaccess.revnums=False
42 $ hg exp 2 --config experimental.directaccess.revnums=False
43 abort: hidden revision '2'!
43 abort: hidden revision '2' was rewritten as: 2443a0e66469!
44 (use --hidden to access hidden revisions)
44 (use --hidden to access hidden revisions)
45 [255]
45 [255]
46
46
47 $ hg exp 2
47 $ hg exp 2
48 # HG changeset patch
48 # HG changeset patch
49 # User test
49 # User test
50 # Date 0 0
50 # Date 0 0
51 # Thu Jan 01 00:00:00 1970 +0000
51 # Thu Jan 01 00:00:00 1970 +0000
52 # Node ID 28ad74487de9599d00d81085be739c61fc340652
52 # Node ID 28ad74487de9599d00d81085be739c61fc340652
53 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
53 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
54 Added c
54 Added c
55
55
56 diff -r 29becc82797a -r 28ad74487de9 c
56 diff -r 29becc82797a -r 28ad74487de9 c
57 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58 +++ b/c Thu Jan 01 00:00:00 1970 +0000
58 +++ b/c Thu Jan 01 00:00:00 1970 +0000
59 @@ -0,0 +1,1 @@
59 @@ -0,0 +1,1 @@
60 +foo
60 +foo
61
61
62 $ hg log -r 2
62 $ hg log -r 2
63 changeset: 2:28ad74487de9
63 changeset: 2:28ad74487de9
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:00 1970 +0000
65 date: Thu Jan 01 00:00:00 1970 +0000
66 obsolete: rewritten using amend as 3:2443a0e66469
66 obsolete: rewritten using amend as 3:2443a0e66469
67 summary: Added c
67 summary: Added c
68
68
69 $ hg identify -r 2
69 $ hg identify -r 2
70 28ad74487de9
70 28ad74487de9
71
71
72 $ hg status --change 2
72 $ hg status --change 2
73 A c
73 A c
74
74
75 $ hg status --change 2 --config experimental.directaccess.revnums=False
75 $ hg status --change 2 --config experimental.directaccess.revnums=False
76 abort: hidden revision '2'!
76 abort: hidden revision '2' was rewritten as: 2443a0e66469!
77 (use --hidden to access hidden revisions)
77 (use --hidden to access hidden revisions)
78 [255]
78 [255]
79
79
80 $ hg diff -c 2
80 $ hg diff -c 2
81 diff -r 29becc82797a -r 28ad74487de9 c
81 diff -r 29becc82797a -r 28ad74487de9 c
82 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83 +++ b/c Thu Jan 01 00:00:00 1970 +0000
83 +++ b/c Thu Jan 01 00:00:00 1970 +0000
84 @@ -0,0 +1,1 @@
84 @@ -0,0 +1,1 @@
85 +foo
85 +foo
86
86
87 Testing with hash
87 Testing with hash
88
88
89 `hg export`
89 `hg export`
90
90
91 $ hg exp 28ad74
91 $ hg exp 28ad74
92 # HG changeset patch
92 # HG changeset patch
93 # User test
93 # User test
94 # Date 0 0
94 # Date 0 0
95 # Thu Jan 01 00:00:00 1970 +0000
95 # Thu Jan 01 00:00:00 1970 +0000
96 # Node ID 28ad74487de9599d00d81085be739c61fc340652
96 # Node ID 28ad74487de9599d00d81085be739c61fc340652
97 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
97 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
98 Added c
98 Added c
99
99
100 diff -r 29becc82797a -r 28ad74487de9 c
100 diff -r 29becc82797a -r 28ad74487de9 c
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102 +++ b/c Thu Jan 01 00:00:00 1970 +0000
102 +++ b/c Thu Jan 01 00:00:00 1970 +0000
103 @@ -0,0 +1,1 @@
103 @@ -0,0 +1,1 @@
104 +foo
104 +foo
105
105
106 `hg log`
106 `hg log`
107
107
108 $ hg log -r 28ad74
108 $ hg log -r 28ad74
109 changeset: 2:28ad74487de9
109 changeset: 2:28ad74487de9
110 user: test
110 user: test
111 date: Thu Jan 01 00:00:00 1970 +0000
111 date: Thu Jan 01 00:00:00 1970 +0000
112 obsolete: rewritten using amend as 3:2443a0e66469
112 obsolete: rewritten using amend as 3:2443a0e66469
113 summary: Added c
113 summary: Added c
114
114
115 `hg cat`
115 `hg cat`
116
116
117 $ hg cat -r 28ad74 c
117 $ hg cat -r 28ad74 c
118 foo
118 foo
119
119
120 `hg diff`
120 `hg diff`
121
121
122 $ hg diff -c 28ad74
122 $ hg diff -c 28ad74
123 diff -r 29becc82797a -r 28ad74487de9 c
123 diff -r 29becc82797a -r 28ad74487de9 c
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125 +++ b/c Thu Jan 01 00:00:00 1970 +0000
125 +++ b/c Thu Jan 01 00:00:00 1970 +0000
126 @@ -0,0 +1,1 @@
126 @@ -0,0 +1,1 @@
127 +foo
127 +foo
128
128
129 `hg files`
129 `hg files`
130
130
131 $ hg files -r 28ad74
131 $ hg files -r 28ad74
132 a
132 a
133 b
133 b
134 c
134 c
135
135
136 `hg identify`
136 `hg identify`
137
137
138 $ hg identify -r 28ad74
138 $ hg identify -r 28ad74
139 28ad74487de9
139 28ad74487de9
140
140
141 `hg annotate`
141 `hg annotate`
142
142
143 $ hg annotate -r 28ad74 a
143 $ hg annotate -r 28ad74 a
144 0: foo
144 0: foo
145
145
146 `hg status`
146 `hg status`
147
147
148 $ hg status --change 28ad74
148 $ hg status --change 28ad74
149 A c
149 A c
150
150
151 `hg archive`
151 `hg archive`
152
152
153 This should not throw error
153 This should not throw error
154 $ hg archive -r 28ad74 foo
154 $ hg archive -r 28ad74 foo
155
155
156 `hg update`
156 `hg update`
157
157
158 $ hg up 28ad74
158 $ hg up 28ad74
159 updating to a hidden changeset 28ad74487de9
159 updating to a hidden changeset 28ad74487de9
160 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
161
161
162 $ hg up 3
162 $ hg up 3
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
164
164
165 `hg revert`
165 `hg revert`
166
166
167 $ hg revert -r 28ad74 --all
167 $ hg revert -r 28ad74 --all
168 reverting c
168 reverting c
169
169
170 $ hg diff
170 $ hg diff
171 diff -r 2443a0e66469 c
171 diff -r 2443a0e66469 c
172 --- a/c Thu Jan 01 00:00:00 1970 +0000
172 --- a/c Thu Jan 01 00:00:00 1970 +0000
173 +++ b/c Thu Jan 01 00:00:00 1970 +0000
173 +++ b/c Thu Jan 01 00:00:00 1970 +0000
174 @@ -1,2 +1,1 @@
174 @@ -1,2 +1,1 @@
175 foo
175 foo
176 -bar
176 -bar
177
177
178 Commands with undefined cmdtype should not work right now
178 Commands with undefined cmdtype should not work right now
179
179
180 $ hg phase -r 28ad74
180 $ hg phase -r 28ad74
181 abort: hidden revision '28ad74'!
181 abort: hidden revision '28ad74' was rewritten as: 2443a0e66469!
182 (use --hidden to access hidden revisions)
182 (use --hidden to access hidden revisions)
183 [255]
183 [255]
184
184
185 $ hg phase -r 2
185 $ hg phase -r 2
186 abort: hidden revision '2'!
186 abort: hidden revision '2' was rewritten as: 2443a0e66469!
187 (use --hidden to access hidden revisions)
187 (use --hidden to access hidden revisions)
188 [255]
188 [255]
@@ -1,2506 +1,2506 b''
1 Log on empty repository: checking consistency
1 Log on empty repository: checking consistency
2
2
3 $ hg init empty
3 $ hg init empty
4 $ cd empty
4 $ cd empty
5 $ hg log
5 $ hg log
6 $ hg log -r 1
6 $ hg log -r 1
7 abort: unknown revision '1'!
7 abort: unknown revision '1'!
8 [255]
8 [255]
9 $ hg log -r -1:0
9 $ hg log -r -1:0
10 abort: unknown revision '-1'!
10 abort: unknown revision '-1'!
11 [255]
11 [255]
12 $ hg log -r 'branch(name)'
12 $ hg log -r 'branch(name)'
13 abort: unknown revision 'name'!
13 abort: unknown revision 'name'!
14 [255]
14 [255]
15 $ hg log -r null -q
15 $ hg log -r null -q
16 -1:000000000000
16 -1:000000000000
17
17
18 $ cd ..
18 $ cd ..
19
19
20 The g is crafted to have 2 filelog topological heads in a linear
20 The g is crafted to have 2 filelog topological heads in a linear
21 changeset graph
21 changeset graph
22
22
23 $ hg init a
23 $ hg init a
24 $ cd a
24 $ cd a
25 $ echo a > a
25 $ echo a > a
26 $ echo f > f
26 $ echo f > f
27 $ hg ci -Ama -d '1 0'
27 $ hg ci -Ama -d '1 0'
28 adding a
28 adding a
29 adding f
29 adding f
30
30
31 $ hg cp a b
31 $ hg cp a b
32 $ hg cp f g
32 $ hg cp f g
33 $ hg ci -mb -d '2 0'
33 $ hg ci -mb -d '2 0'
34
34
35 $ mkdir dir
35 $ mkdir dir
36 $ hg mv b dir
36 $ hg mv b dir
37 $ echo g >> g
37 $ echo g >> g
38 $ echo f >> f
38 $ echo f >> f
39 $ hg ci -mc -d '3 0'
39 $ hg ci -mc -d '3 0'
40
40
41 $ hg mv a b
41 $ hg mv a b
42 $ hg cp -f f g
42 $ hg cp -f f g
43 $ echo a > d
43 $ echo a > d
44 $ hg add d
44 $ hg add d
45 $ hg ci -md -d '4 0'
45 $ hg ci -md -d '4 0'
46
46
47 $ hg mv dir/b e
47 $ hg mv dir/b e
48 $ hg ci -me -d '5 0'
48 $ hg ci -me -d '5 0'
49
49
50 Make sure largefiles doesn't interfere with logging a regular file
50 Make sure largefiles doesn't interfere with logging a regular file
51 $ hg --debug log a -T '{rev}: {desc}\n' --config extensions.largefiles=
51 $ hg --debug log a -T '{rev}: {desc}\n' --config extensions.largefiles=
52 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
52 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
53 updated patterns: .hglf/a, a
53 updated patterns: .hglf/a, a
54 0: a
54 0: a
55 $ hg log a
55 $ hg log a
56 changeset: 0:9161b9aeaf16
56 changeset: 0:9161b9aeaf16
57 user: test
57 user: test
58 date: Thu Jan 01 00:00:01 1970 +0000
58 date: Thu Jan 01 00:00:01 1970 +0000
59 summary: a
59 summary: a
60
60
61 $ hg log glob:a*
61 $ hg log glob:a*
62 changeset: 3:2ca5ba701980
62 changeset: 3:2ca5ba701980
63 user: test
63 user: test
64 date: Thu Jan 01 00:00:04 1970 +0000
64 date: Thu Jan 01 00:00:04 1970 +0000
65 summary: d
65 summary: d
66
66
67 changeset: 0:9161b9aeaf16
67 changeset: 0:9161b9aeaf16
68 user: test
68 user: test
69 date: Thu Jan 01 00:00:01 1970 +0000
69 date: Thu Jan 01 00:00:01 1970 +0000
70 summary: a
70 summary: a
71
71
72 $ hg --debug log glob:a* -T '{rev}: {desc}\n' --config extensions.largefiles=
72 $ hg --debug log glob:a* -T '{rev}: {desc}\n' --config extensions.largefiles=
73 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
73 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
74 updated patterns: glob:.hglf/a*, glob:a*
74 updated patterns: glob:.hglf/a*, glob:a*
75 3: d
75 3: d
76 0: a
76 0: a
77
77
78 log on directory
78 log on directory
79
79
80 $ hg log dir
80 $ hg log dir
81 changeset: 4:7e4639b4691b
81 changeset: 4:7e4639b4691b
82 tag: tip
82 tag: tip
83 user: test
83 user: test
84 date: Thu Jan 01 00:00:05 1970 +0000
84 date: Thu Jan 01 00:00:05 1970 +0000
85 summary: e
85 summary: e
86
86
87 changeset: 2:f8954cd4dc1f
87 changeset: 2:f8954cd4dc1f
88 user: test
88 user: test
89 date: Thu Jan 01 00:00:03 1970 +0000
89 date: Thu Jan 01 00:00:03 1970 +0000
90 summary: c
90 summary: c
91
91
92 $ hg log somethingthatdoesntexist dir
92 $ hg log somethingthatdoesntexist dir
93 changeset: 4:7e4639b4691b
93 changeset: 4:7e4639b4691b
94 tag: tip
94 tag: tip
95 user: test
95 user: test
96 date: Thu Jan 01 00:00:05 1970 +0000
96 date: Thu Jan 01 00:00:05 1970 +0000
97 summary: e
97 summary: e
98
98
99 changeset: 2:f8954cd4dc1f
99 changeset: 2:f8954cd4dc1f
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:03 1970 +0000
101 date: Thu Jan 01 00:00:03 1970 +0000
102 summary: c
102 summary: c
103
103
104
104
105 -f, non-existent directory
105 -f, non-existent directory
106
106
107 $ hg log -f dir
107 $ hg log -f dir
108 abort: cannot follow file not in parent revision: "dir"
108 abort: cannot follow file not in parent revision: "dir"
109 [255]
109 [255]
110
110
111 -f, directory
111 -f, directory
112
112
113 $ hg up -q 3
113 $ hg up -q 3
114 $ hg log -f dir
114 $ hg log -f dir
115 changeset: 2:f8954cd4dc1f
115 changeset: 2:f8954cd4dc1f
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:03 1970 +0000
117 date: Thu Jan 01 00:00:03 1970 +0000
118 summary: c
118 summary: c
119
119
120 -f, directory with --patch
120 -f, directory with --patch
121
121
122 $ hg log -f dir -p
122 $ hg log -f dir -p
123 changeset: 2:f8954cd4dc1f
123 changeset: 2:f8954cd4dc1f
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:03 1970 +0000
125 date: Thu Jan 01 00:00:03 1970 +0000
126 summary: c
126 summary: c
127
127
128 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
128 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
129 --- /dev/null* (glob)
129 --- /dev/null* (glob)
130 +++ b/dir/b* (glob)
130 +++ b/dir/b* (glob)
131 @@ -0,0 +1,1 @@
131 @@ -0,0 +1,1 @@
132 +a
132 +a
133
133
134
134
135 -f, pattern
135 -f, pattern
136
136
137 $ hg log -f -I 'dir**' -p
137 $ hg log -f -I 'dir**' -p
138 changeset: 2:f8954cd4dc1f
138 changeset: 2:f8954cd4dc1f
139 user: test
139 user: test
140 date: Thu Jan 01 00:00:03 1970 +0000
140 date: Thu Jan 01 00:00:03 1970 +0000
141 summary: c
141 summary: c
142
142
143 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
143 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
144 --- /dev/null* (glob)
144 --- /dev/null* (glob)
145 +++ b/dir/b* (glob)
145 +++ b/dir/b* (glob)
146 @@ -0,0 +1,1 @@
146 @@ -0,0 +1,1 @@
147 +a
147 +a
148
148
149 $ hg up -q 4
149 $ hg up -q 4
150
150
151 -f, a wrong style
151 -f, a wrong style
152
152
153 $ hg log -f -l1 --style something
153 $ hg log -f -l1 --style something
154 abort: style 'something' not found
154 abort: style 'something' not found
155 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
155 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
156 [255]
156 [255]
157
157
158 -f, phases style
158 -f, phases style
159
159
160
160
161 $ hg log -f -l1 --style phases
161 $ hg log -f -l1 --style phases
162 changeset: 4:7e4639b4691b
162 changeset: 4:7e4639b4691b
163 tag: tip
163 tag: tip
164 phase: draft
164 phase: draft
165 user: test
165 user: test
166 date: Thu Jan 01 00:00:05 1970 +0000
166 date: Thu Jan 01 00:00:05 1970 +0000
167 summary: e
167 summary: e
168
168
169
169
170 $ hg log -f -l1 --style phases -q
170 $ hg log -f -l1 --style phases -q
171 4:7e4639b4691b
171 4:7e4639b4691b
172
172
173 -f, but no args
173 -f, but no args
174
174
175 $ hg log -f
175 $ hg log -f
176 changeset: 4:7e4639b4691b
176 changeset: 4:7e4639b4691b
177 tag: tip
177 tag: tip
178 user: test
178 user: test
179 date: Thu Jan 01 00:00:05 1970 +0000
179 date: Thu Jan 01 00:00:05 1970 +0000
180 summary: e
180 summary: e
181
181
182 changeset: 3:2ca5ba701980
182 changeset: 3:2ca5ba701980
183 user: test
183 user: test
184 date: Thu Jan 01 00:00:04 1970 +0000
184 date: Thu Jan 01 00:00:04 1970 +0000
185 summary: d
185 summary: d
186
186
187 changeset: 2:f8954cd4dc1f
187 changeset: 2:f8954cd4dc1f
188 user: test
188 user: test
189 date: Thu Jan 01 00:00:03 1970 +0000
189 date: Thu Jan 01 00:00:03 1970 +0000
190 summary: c
190 summary: c
191
191
192 changeset: 1:d89b0a12d229
192 changeset: 1:d89b0a12d229
193 user: test
193 user: test
194 date: Thu Jan 01 00:00:02 1970 +0000
194 date: Thu Jan 01 00:00:02 1970 +0000
195 summary: b
195 summary: b
196
196
197 changeset: 0:9161b9aeaf16
197 changeset: 0:9161b9aeaf16
198 user: test
198 user: test
199 date: Thu Jan 01 00:00:01 1970 +0000
199 date: Thu Jan 01 00:00:01 1970 +0000
200 summary: a
200 summary: a
201
201
202
202
203 one rename
203 one rename
204
204
205 $ hg up -q 2
205 $ hg up -q 2
206 $ hg log -vf a
206 $ hg log -vf a
207 changeset: 0:9161b9aeaf16
207 changeset: 0:9161b9aeaf16
208 user: test
208 user: test
209 date: Thu Jan 01 00:00:01 1970 +0000
209 date: Thu Jan 01 00:00:01 1970 +0000
210 files: a f
210 files: a f
211 description:
211 description:
212 a
212 a
213
213
214
214
215
215
216 many renames
216 many renames
217
217
218 $ hg up -q tip
218 $ hg up -q tip
219 $ hg log -vf e
219 $ hg log -vf e
220 changeset: 4:7e4639b4691b
220 changeset: 4:7e4639b4691b
221 tag: tip
221 tag: tip
222 user: test
222 user: test
223 date: Thu Jan 01 00:00:05 1970 +0000
223 date: Thu Jan 01 00:00:05 1970 +0000
224 files: dir/b e
224 files: dir/b e
225 description:
225 description:
226 e
226 e
227
227
228
228
229 changeset: 2:f8954cd4dc1f
229 changeset: 2:f8954cd4dc1f
230 user: test
230 user: test
231 date: Thu Jan 01 00:00:03 1970 +0000
231 date: Thu Jan 01 00:00:03 1970 +0000
232 files: b dir/b f g
232 files: b dir/b f g
233 description:
233 description:
234 c
234 c
235
235
236
236
237 changeset: 1:d89b0a12d229
237 changeset: 1:d89b0a12d229
238 user: test
238 user: test
239 date: Thu Jan 01 00:00:02 1970 +0000
239 date: Thu Jan 01 00:00:02 1970 +0000
240 files: b g
240 files: b g
241 description:
241 description:
242 b
242 b
243
243
244
244
245 changeset: 0:9161b9aeaf16
245 changeset: 0:9161b9aeaf16
246 user: test
246 user: test
247 date: Thu Jan 01 00:00:01 1970 +0000
247 date: Thu Jan 01 00:00:01 1970 +0000
248 files: a f
248 files: a f
249 description:
249 description:
250 a
250 a
251
251
252
252
253
253
254
254
255 log -pf dir/b
255 log -pf dir/b
256
256
257 $ hg up -q 3
257 $ hg up -q 3
258 $ hg log -pf dir/b
258 $ hg log -pf dir/b
259 changeset: 2:f8954cd4dc1f
259 changeset: 2:f8954cd4dc1f
260 user: test
260 user: test
261 date: Thu Jan 01 00:00:03 1970 +0000
261 date: Thu Jan 01 00:00:03 1970 +0000
262 summary: c
262 summary: c
263
263
264 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
264 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
265 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
265 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
266 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
266 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
267 @@ -0,0 +1,1 @@
267 @@ -0,0 +1,1 @@
268 +a
268 +a
269
269
270 changeset: 1:d89b0a12d229
270 changeset: 1:d89b0a12d229
271 user: test
271 user: test
272 date: Thu Jan 01 00:00:02 1970 +0000
272 date: Thu Jan 01 00:00:02 1970 +0000
273 summary: b
273 summary: b
274
274
275 diff -r 9161b9aeaf16 -r d89b0a12d229 b
275 diff -r 9161b9aeaf16 -r d89b0a12d229 b
276 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
277 +++ b/b Thu Jan 01 00:00:02 1970 +0000
277 +++ b/b Thu Jan 01 00:00:02 1970 +0000
278 @@ -0,0 +1,1 @@
278 @@ -0,0 +1,1 @@
279 +a
279 +a
280
280
281 changeset: 0:9161b9aeaf16
281 changeset: 0:9161b9aeaf16
282 user: test
282 user: test
283 date: Thu Jan 01 00:00:01 1970 +0000
283 date: Thu Jan 01 00:00:01 1970 +0000
284 summary: a
284 summary: a
285
285
286 diff -r 000000000000 -r 9161b9aeaf16 a
286 diff -r 000000000000 -r 9161b9aeaf16 a
287 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
287 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
288 +++ b/a Thu Jan 01 00:00:01 1970 +0000
288 +++ b/a Thu Jan 01 00:00:01 1970 +0000
289 @@ -0,0 +1,1 @@
289 @@ -0,0 +1,1 @@
290 +a
290 +a
291
291
292
292
293 log -pf b inside dir
293 log -pf b inside dir
294
294
295 $ hg --cwd=dir log -pf b
295 $ hg --cwd=dir log -pf b
296 changeset: 2:f8954cd4dc1f
296 changeset: 2:f8954cd4dc1f
297 user: test
297 user: test
298 date: Thu Jan 01 00:00:03 1970 +0000
298 date: Thu Jan 01 00:00:03 1970 +0000
299 summary: c
299 summary: c
300
300
301 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
301 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
302 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
302 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
303 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
303 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
304 @@ -0,0 +1,1 @@
304 @@ -0,0 +1,1 @@
305 +a
305 +a
306
306
307 changeset: 1:d89b0a12d229
307 changeset: 1:d89b0a12d229
308 user: test
308 user: test
309 date: Thu Jan 01 00:00:02 1970 +0000
309 date: Thu Jan 01 00:00:02 1970 +0000
310 summary: b
310 summary: b
311
311
312 diff -r 9161b9aeaf16 -r d89b0a12d229 b
312 diff -r 9161b9aeaf16 -r d89b0a12d229 b
313 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
313 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
314 +++ b/b Thu Jan 01 00:00:02 1970 +0000
314 +++ b/b Thu Jan 01 00:00:02 1970 +0000
315 @@ -0,0 +1,1 @@
315 @@ -0,0 +1,1 @@
316 +a
316 +a
317
317
318 changeset: 0:9161b9aeaf16
318 changeset: 0:9161b9aeaf16
319 user: test
319 user: test
320 date: Thu Jan 01 00:00:01 1970 +0000
320 date: Thu Jan 01 00:00:01 1970 +0000
321 summary: a
321 summary: a
322
322
323 diff -r 000000000000 -r 9161b9aeaf16 a
323 diff -r 000000000000 -r 9161b9aeaf16 a
324 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
324 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
325 +++ b/a Thu Jan 01 00:00:01 1970 +0000
325 +++ b/a Thu Jan 01 00:00:01 1970 +0000
326 @@ -0,0 +1,1 @@
326 @@ -0,0 +1,1 @@
327 +a
327 +a
328
328
329
329
330 log -pf, but no args
330 log -pf, but no args
331
331
332 $ hg log -pf
332 $ hg log -pf
333 changeset: 3:2ca5ba701980
333 changeset: 3:2ca5ba701980
334 user: test
334 user: test
335 date: Thu Jan 01 00:00:04 1970 +0000
335 date: Thu Jan 01 00:00:04 1970 +0000
336 summary: d
336 summary: d
337
337
338 diff -r f8954cd4dc1f -r 2ca5ba701980 a
338 diff -r f8954cd4dc1f -r 2ca5ba701980 a
339 --- a/a Thu Jan 01 00:00:03 1970 +0000
339 --- a/a Thu Jan 01 00:00:03 1970 +0000
340 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
340 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
341 @@ -1,1 +0,0 @@
341 @@ -1,1 +0,0 @@
342 -a
342 -a
343 diff -r f8954cd4dc1f -r 2ca5ba701980 b
343 diff -r f8954cd4dc1f -r 2ca5ba701980 b
344 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
344 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
345 +++ b/b Thu Jan 01 00:00:04 1970 +0000
345 +++ b/b Thu Jan 01 00:00:04 1970 +0000
346 @@ -0,0 +1,1 @@
346 @@ -0,0 +1,1 @@
347 +a
347 +a
348 diff -r f8954cd4dc1f -r 2ca5ba701980 d
348 diff -r f8954cd4dc1f -r 2ca5ba701980 d
349 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
349 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
350 +++ b/d Thu Jan 01 00:00:04 1970 +0000
350 +++ b/d Thu Jan 01 00:00:04 1970 +0000
351 @@ -0,0 +1,1 @@
351 @@ -0,0 +1,1 @@
352 +a
352 +a
353 diff -r f8954cd4dc1f -r 2ca5ba701980 g
353 diff -r f8954cd4dc1f -r 2ca5ba701980 g
354 --- a/g Thu Jan 01 00:00:03 1970 +0000
354 --- a/g Thu Jan 01 00:00:03 1970 +0000
355 +++ b/g Thu Jan 01 00:00:04 1970 +0000
355 +++ b/g Thu Jan 01 00:00:04 1970 +0000
356 @@ -1,2 +1,2 @@
356 @@ -1,2 +1,2 @@
357 f
357 f
358 -g
358 -g
359 +f
359 +f
360
360
361 changeset: 2:f8954cd4dc1f
361 changeset: 2:f8954cd4dc1f
362 user: test
362 user: test
363 date: Thu Jan 01 00:00:03 1970 +0000
363 date: Thu Jan 01 00:00:03 1970 +0000
364 summary: c
364 summary: c
365
365
366 diff -r d89b0a12d229 -r f8954cd4dc1f b
366 diff -r d89b0a12d229 -r f8954cd4dc1f b
367 --- a/b Thu Jan 01 00:00:02 1970 +0000
367 --- a/b Thu Jan 01 00:00:02 1970 +0000
368 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
368 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
369 @@ -1,1 +0,0 @@
369 @@ -1,1 +0,0 @@
370 -a
370 -a
371 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
371 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
372 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
372 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
373 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
373 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
374 @@ -0,0 +1,1 @@
374 @@ -0,0 +1,1 @@
375 +a
375 +a
376 diff -r d89b0a12d229 -r f8954cd4dc1f f
376 diff -r d89b0a12d229 -r f8954cd4dc1f f
377 --- a/f Thu Jan 01 00:00:02 1970 +0000
377 --- a/f Thu Jan 01 00:00:02 1970 +0000
378 +++ b/f Thu Jan 01 00:00:03 1970 +0000
378 +++ b/f Thu Jan 01 00:00:03 1970 +0000
379 @@ -1,1 +1,2 @@
379 @@ -1,1 +1,2 @@
380 f
380 f
381 +f
381 +f
382 diff -r d89b0a12d229 -r f8954cd4dc1f g
382 diff -r d89b0a12d229 -r f8954cd4dc1f g
383 --- a/g Thu Jan 01 00:00:02 1970 +0000
383 --- a/g Thu Jan 01 00:00:02 1970 +0000
384 +++ b/g Thu Jan 01 00:00:03 1970 +0000
384 +++ b/g Thu Jan 01 00:00:03 1970 +0000
385 @@ -1,1 +1,2 @@
385 @@ -1,1 +1,2 @@
386 f
386 f
387 +g
387 +g
388
388
389 changeset: 1:d89b0a12d229
389 changeset: 1:d89b0a12d229
390 user: test
390 user: test
391 date: Thu Jan 01 00:00:02 1970 +0000
391 date: Thu Jan 01 00:00:02 1970 +0000
392 summary: b
392 summary: b
393
393
394 diff -r 9161b9aeaf16 -r d89b0a12d229 b
394 diff -r 9161b9aeaf16 -r d89b0a12d229 b
395 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
395 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
396 +++ b/b Thu Jan 01 00:00:02 1970 +0000
396 +++ b/b Thu Jan 01 00:00:02 1970 +0000
397 @@ -0,0 +1,1 @@
397 @@ -0,0 +1,1 @@
398 +a
398 +a
399 diff -r 9161b9aeaf16 -r d89b0a12d229 g
399 diff -r 9161b9aeaf16 -r d89b0a12d229 g
400 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
400 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
401 +++ b/g Thu Jan 01 00:00:02 1970 +0000
401 +++ b/g Thu Jan 01 00:00:02 1970 +0000
402 @@ -0,0 +1,1 @@
402 @@ -0,0 +1,1 @@
403 +f
403 +f
404
404
405 changeset: 0:9161b9aeaf16
405 changeset: 0:9161b9aeaf16
406 user: test
406 user: test
407 date: Thu Jan 01 00:00:01 1970 +0000
407 date: Thu Jan 01 00:00:01 1970 +0000
408 summary: a
408 summary: a
409
409
410 diff -r 000000000000 -r 9161b9aeaf16 a
410 diff -r 000000000000 -r 9161b9aeaf16 a
411 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
411 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
412 +++ b/a Thu Jan 01 00:00:01 1970 +0000
412 +++ b/a Thu Jan 01 00:00:01 1970 +0000
413 @@ -0,0 +1,1 @@
413 @@ -0,0 +1,1 @@
414 +a
414 +a
415 diff -r 000000000000 -r 9161b9aeaf16 f
415 diff -r 000000000000 -r 9161b9aeaf16 f
416 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
416 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
417 +++ b/f Thu Jan 01 00:00:01 1970 +0000
417 +++ b/f Thu Jan 01 00:00:01 1970 +0000
418 @@ -0,0 +1,1 @@
418 @@ -0,0 +1,1 @@
419 +f
419 +f
420
420
421
421
422 log -vf dir/b
422 log -vf dir/b
423
423
424 $ hg log -vf dir/b
424 $ hg log -vf dir/b
425 changeset: 2:f8954cd4dc1f
425 changeset: 2:f8954cd4dc1f
426 user: test
426 user: test
427 date: Thu Jan 01 00:00:03 1970 +0000
427 date: Thu Jan 01 00:00:03 1970 +0000
428 files: b dir/b f g
428 files: b dir/b f g
429 description:
429 description:
430 c
430 c
431
431
432
432
433 changeset: 1:d89b0a12d229
433 changeset: 1:d89b0a12d229
434 user: test
434 user: test
435 date: Thu Jan 01 00:00:02 1970 +0000
435 date: Thu Jan 01 00:00:02 1970 +0000
436 files: b g
436 files: b g
437 description:
437 description:
438 b
438 b
439
439
440
440
441 changeset: 0:9161b9aeaf16
441 changeset: 0:9161b9aeaf16
442 user: test
442 user: test
443 date: Thu Jan 01 00:00:01 1970 +0000
443 date: Thu Jan 01 00:00:01 1970 +0000
444 files: a f
444 files: a f
445 description:
445 description:
446 a
446 a
447
447
448
448
449
449
450
450
451 -f and multiple filelog heads
451 -f and multiple filelog heads
452
452
453 $ hg up -q 2
453 $ hg up -q 2
454 $ hg log -f g --template '{rev}\n'
454 $ hg log -f g --template '{rev}\n'
455 2
455 2
456 1
456 1
457 0
457 0
458 $ hg up -q tip
458 $ hg up -q tip
459 $ hg log -f g --template '{rev}\n'
459 $ hg log -f g --template '{rev}\n'
460 3
460 3
461 2
461 2
462 0
462 0
463
463
464
464
465 log copies with --copies
465 log copies with --copies
466
466
467 $ hg log -vC --template '{rev} {file_copies}\n'
467 $ hg log -vC --template '{rev} {file_copies}\n'
468 4 e (dir/b)
468 4 e (dir/b)
469 3 b (a)g (f)
469 3 b (a)g (f)
470 2 dir/b (b)
470 2 dir/b (b)
471 1 b (a)g (f)
471 1 b (a)g (f)
472 0
472 0
473
473
474 log copies switch without --copies, with old filecopy template
474 log copies switch without --copies, with old filecopy template
475
475
476 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
476 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
477 4
477 4
478 3
478 3
479 2
479 2
480 1
480 1
481 0
481 0
482
482
483 log copies switch with --copies
483 log copies switch with --copies
484
484
485 $ hg log -vC --template '{rev} {file_copies_switch}\n'
485 $ hg log -vC --template '{rev} {file_copies_switch}\n'
486 4 e (dir/b)
486 4 e (dir/b)
487 3 b (a)g (f)
487 3 b (a)g (f)
488 2 dir/b (b)
488 2 dir/b (b)
489 1 b (a)g (f)
489 1 b (a)g (f)
490 0
490 0
491
491
492
492
493 log copies with hardcoded style and with --style=default
493 log copies with hardcoded style and with --style=default
494
494
495 $ hg log -vC -r4
495 $ hg log -vC -r4
496 changeset: 4:7e4639b4691b
496 changeset: 4:7e4639b4691b
497 tag: tip
497 tag: tip
498 user: test
498 user: test
499 date: Thu Jan 01 00:00:05 1970 +0000
499 date: Thu Jan 01 00:00:05 1970 +0000
500 files: dir/b e
500 files: dir/b e
501 copies: e (dir/b)
501 copies: e (dir/b)
502 description:
502 description:
503 e
503 e
504
504
505
505
506 $ hg log -vC -r4 --style=default
506 $ hg log -vC -r4 --style=default
507 changeset: 4:7e4639b4691b
507 changeset: 4:7e4639b4691b
508 tag: tip
508 tag: tip
509 user: test
509 user: test
510 date: Thu Jan 01 00:00:05 1970 +0000
510 date: Thu Jan 01 00:00:05 1970 +0000
511 files: dir/b e
511 files: dir/b e
512 copies: e (dir/b)
512 copies: e (dir/b)
513 description:
513 description:
514 e
514 e
515
515
516
516
517 $ hg log -vC -r4 -Tjson
517 $ hg log -vC -r4 -Tjson
518 [
518 [
519 {
519 {
520 "rev": 4,
520 "rev": 4,
521 "node": "7e4639b4691b9f84b81036a8d4fb218ce3c5e3a3",
521 "node": "7e4639b4691b9f84b81036a8d4fb218ce3c5e3a3",
522 "branch": "default",
522 "branch": "default",
523 "phase": "draft",
523 "phase": "draft",
524 "user": "test",
524 "user": "test",
525 "date": [5, 0],
525 "date": [5, 0],
526 "desc": "e",
526 "desc": "e",
527 "bookmarks": [],
527 "bookmarks": [],
528 "tags": ["tip"],
528 "tags": ["tip"],
529 "parents": ["2ca5ba7019804f1f597249caddf22a64d34df0ba"],
529 "parents": ["2ca5ba7019804f1f597249caddf22a64d34df0ba"],
530 "files": ["dir/b", "e"],
530 "files": ["dir/b", "e"],
531 "copies": {"e": "dir/b"}
531 "copies": {"e": "dir/b"}
532 }
532 }
533 ]
533 ]
534
534
535 log copies, non-linear manifest
535 log copies, non-linear manifest
536
536
537 $ hg up -C 3
537 $ hg up -C 3
538 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
538 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
539 $ hg mv dir/b e
539 $ hg mv dir/b e
540 $ echo foo > foo
540 $ echo foo > foo
541 $ hg ci -Ame2 -d '6 0'
541 $ hg ci -Ame2 -d '6 0'
542 adding foo
542 adding foo
543 created new head
543 created new head
544 $ hg log -v --template '{rev} {file_copies}\n' -r 5
544 $ hg log -v --template '{rev} {file_copies}\n' -r 5
545 5 e (dir/b)
545 5 e (dir/b)
546
546
547
547
548 log copies, execute bit set
548 log copies, execute bit set
549
549
550 #if execbit
550 #if execbit
551 $ chmod +x e
551 $ chmod +x e
552 $ hg ci -me3 -d '7 0'
552 $ hg ci -me3 -d '7 0'
553 $ hg log -v --template '{rev} {file_copies}\n' -r 6
553 $ hg log -v --template '{rev} {file_copies}\n' -r 6
554 6
554 6
555 #endif
555 #endif
556
556
557
557
558 log -p d
558 log -p d
559
559
560 $ hg log -pv d
560 $ hg log -pv d
561 changeset: 3:2ca5ba701980
561 changeset: 3:2ca5ba701980
562 user: test
562 user: test
563 date: Thu Jan 01 00:00:04 1970 +0000
563 date: Thu Jan 01 00:00:04 1970 +0000
564 files: a b d g
564 files: a b d g
565 description:
565 description:
566 d
566 d
567
567
568
568
569 diff -r f8954cd4dc1f -r 2ca5ba701980 d
569 diff -r f8954cd4dc1f -r 2ca5ba701980 d
570 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
570 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
571 +++ b/d Thu Jan 01 00:00:04 1970 +0000
571 +++ b/d Thu Jan 01 00:00:04 1970 +0000
572 @@ -0,0 +1,1 @@
572 @@ -0,0 +1,1 @@
573 +a
573 +a
574
574
575
575
576
576
577 log --removed file
577 log --removed file
578
578
579 $ hg log --removed -v a
579 $ hg log --removed -v a
580 changeset: 3:2ca5ba701980
580 changeset: 3:2ca5ba701980
581 user: test
581 user: test
582 date: Thu Jan 01 00:00:04 1970 +0000
582 date: Thu Jan 01 00:00:04 1970 +0000
583 files: a b d g
583 files: a b d g
584 description:
584 description:
585 d
585 d
586
586
587
587
588 changeset: 0:9161b9aeaf16
588 changeset: 0:9161b9aeaf16
589 user: test
589 user: test
590 date: Thu Jan 01 00:00:01 1970 +0000
590 date: Thu Jan 01 00:00:01 1970 +0000
591 files: a f
591 files: a f
592 description:
592 description:
593 a
593 a
594
594
595
595
596
596
597 log --removed revrange file
597 log --removed revrange file
598
598
599 $ hg log --removed -v -r0:2 a
599 $ hg log --removed -v -r0:2 a
600 changeset: 0:9161b9aeaf16
600 changeset: 0:9161b9aeaf16
601 user: test
601 user: test
602 date: Thu Jan 01 00:00:01 1970 +0000
602 date: Thu Jan 01 00:00:01 1970 +0000
603 files: a f
603 files: a f
604 description:
604 description:
605 a
605 a
606
606
607
607
608 $ cd ..
608 $ cd ..
609
609
610 log --follow tests
610 log --follow tests
611
611
612 $ hg init follow
612 $ hg init follow
613 $ cd follow
613 $ cd follow
614
614
615 $ echo base > base
615 $ echo base > base
616 $ hg ci -Ambase -d '1 0'
616 $ hg ci -Ambase -d '1 0'
617 adding base
617 adding base
618
618
619 $ echo r1 >> base
619 $ echo r1 >> base
620 $ hg ci -Amr1 -d '1 0'
620 $ hg ci -Amr1 -d '1 0'
621 $ echo r2 >> base
621 $ echo r2 >> base
622 $ hg ci -Amr2 -d '1 0'
622 $ hg ci -Amr2 -d '1 0'
623
623
624 $ hg up -C 1
624 $ hg up -C 1
625 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
626 $ echo b1 > b1
626 $ echo b1 > b1
627
627
628 log -r "follow('set:clean()')"
628 log -r "follow('set:clean()')"
629
629
630 $ hg log -r "follow('set:clean()')"
630 $ hg log -r "follow('set:clean()')"
631 changeset: 0:67e992f2c4f3
631 changeset: 0:67e992f2c4f3
632 user: test
632 user: test
633 date: Thu Jan 01 00:00:01 1970 +0000
633 date: Thu Jan 01 00:00:01 1970 +0000
634 summary: base
634 summary: base
635
635
636 changeset: 1:3d5bf5654eda
636 changeset: 1:3d5bf5654eda
637 user: test
637 user: test
638 date: Thu Jan 01 00:00:01 1970 +0000
638 date: Thu Jan 01 00:00:01 1970 +0000
639 summary: r1
639 summary: r1
640
640
641
641
642 $ hg ci -Amb1 -d '1 0'
642 $ hg ci -Amb1 -d '1 0'
643 adding b1
643 adding b1
644 created new head
644 created new head
645
645
646
646
647 log -f
647 log -f
648
648
649 $ hg log -f
649 $ hg log -f
650 changeset: 3:e62f78d544b4
650 changeset: 3:e62f78d544b4
651 tag: tip
651 tag: tip
652 parent: 1:3d5bf5654eda
652 parent: 1:3d5bf5654eda
653 user: test
653 user: test
654 date: Thu Jan 01 00:00:01 1970 +0000
654 date: Thu Jan 01 00:00:01 1970 +0000
655 summary: b1
655 summary: b1
656
656
657 changeset: 1:3d5bf5654eda
657 changeset: 1:3d5bf5654eda
658 user: test
658 user: test
659 date: Thu Jan 01 00:00:01 1970 +0000
659 date: Thu Jan 01 00:00:01 1970 +0000
660 summary: r1
660 summary: r1
661
661
662 changeset: 0:67e992f2c4f3
662 changeset: 0:67e992f2c4f3
663 user: test
663 user: test
664 date: Thu Jan 01 00:00:01 1970 +0000
664 date: Thu Jan 01 00:00:01 1970 +0000
665 summary: base
665 summary: base
666
666
667
667
668 log -r follow('glob:b*')
668 log -r follow('glob:b*')
669
669
670 $ hg log -r "follow('glob:b*')"
670 $ hg log -r "follow('glob:b*')"
671 changeset: 0:67e992f2c4f3
671 changeset: 0:67e992f2c4f3
672 user: test
672 user: test
673 date: Thu Jan 01 00:00:01 1970 +0000
673 date: Thu Jan 01 00:00:01 1970 +0000
674 summary: base
674 summary: base
675
675
676 changeset: 1:3d5bf5654eda
676 changeset: 1:3d5bf5654eda
677 user: test
677 user: test
678 date: Thu Jan 01 00:00:01 1970 +0000
678 date: Thu Jan 01 00:00:01 1970 +0000
679 summary: r1
679 summary: r1
680
680
681 changeset: 3:e62f78d544b4
681 changeset: 3:e62f78d544b4
682 tag: tip
682 tag: tip
683 parent: 1:3d5bf5654eda
683 parent: 1:3d5bf5654eda
684 user: test
684 user: test
685 date: Thu Jan 01 00:00:01 1970 +0000
685 date: Thu Jan 01 00:00:01 1970 +0000
686 summary: b1
686 summary: b1
687
687
688 log -f -r '1 + 4'
688 log -f -r '1 + 4'
689
689
690 $ hg up -C 0
690 $ hg up -C 0
691 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
691 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
692 $ echo b2 > b2
692 $ echo b2 > b2
693 $ hg ci -Amb2 -d '1 0'
693 $ hg ci -Amb2 -d '1 0'
694 adding b2
694 adding b2
695 created new head
695 created new head
696 $ hg log -f -r '1 + 4'
696 $ hg log -f -r '1 + 4'
697 changeset: 4:ddb82e70d1a1
697 changeset: 4:ddb82e70d1a1
698 tag: tip
698 tag: tip
699 parent: 0:67e992f2c4f3
699 parent: 0:67e992f2c4f3
700 user: test
700 user: test
701 date: Thu Jan 01 00:00:01 1970 +0000
701 date: Thu Jan 01 00:00:01 1970 +0000
702 summary: b2
702 summary: b2
703
703
704 changeset: 1:3d5bf5654eda
704 changeset: 1:3d5bf5654eda
705 user: test
705 user: test
706 date: Thu Jan 01 00:00:01 1970 +0000
706 date: Thu Jan 01 00:00:01 1970 +0000
707 summary: r1
707 summary: r1
708
708
709 changeset: 0:67e992f2c4f3
709 changeset: 0:67e992f2c4f3
710 user: test
710 user: test
711 date: Thu Jan 01 00:00:01 1970 +0000
711 date: Thu Jan 01 00:00:01 1970 +0000
712 summary: base
712 summary: base
713
713
714 log -r "follow('set:grep(b2)')"
714 log -r "follow('set:grep(b2)')"
715
715
716 $ hg log -r "follow('set:grep(b2)')"
716 $ hg log -r "follow('set:grep(b2)')"
717 changeset: 4:ddb82e70d1a1
717 changeset: 4:ddb82e70d1a1
718 tag: tip
718 tag: tip
719 parent: 0:67e992f2c4f3
719 parent: 0:67e992f2c4f3
720 user: test
720 user: test
721 date: Thu Jan 01 00:00:01 1970 +0000
721 date: Thu Jan 01 00:00:01 1970 +0000
722 summary: b2
722 summary: b2
723
723
724 log -r "follow('set:grep(b2)', 4)"
724 log -r "follow('set:grep(b2)', 4)"
725
725
726 $ hg up -qC 0
726 $ hg up -qC 0
727 $ hg log -r "follow('set:grep(b2)', 4)"
727 $ hg log -r "follow('set:grep(b2)', 4)"
728 changeset: 4:ddb82e70d1a1
728 changeset: 4:ddb82e70d1a1
729 tag: tip
729 tag: tip
730 parent: 0:67e992f2c4f3
730 parent: 0:67e992f2c4f3
731 user: test
731 user: test
732 date: Thu Jan 01 00:00:01 1970 +0000
732 date: Thu Jan 01 00:00:01 1970 +0000
733 summary: b2
733 summary: b2
734
734
735
735
736 follow files starting from multiple revisions:
736 follow files starting from multiple revisions:
737
737
738 $ hg log -T '{rev}: {files}\n' -r "follow('glob:b?', startrev=2+3+4)"
738 $ hg log -T '{rev}: {files}\n' -r "follow('glob:b?', startrev=2+3+4)"
739 3: b1
739 3: b1
740 4: b2
740 4: b2
741
741
742 follow files starting from empty revision:
742 follow files starting from empty revision:
743
743
744 $ hg log -T '{rev}: {files}\n' -r "follow('glob:*', startrev=.-.)"
744 $ hg log -T '{rev}: {files}\n' -r "follow('glob:*', startrev=.-.)"
745
745
746 follow starting from revisions:
746 follow starting from revisions:
747
747
748 $ hg log -Gq -r "follow(startrev=2+4)"
748 $ hg log -Gq -r "follow(startrev=2+4)"
749 o 4:ddb82e70d1a1
749 o 4:ddb82e70d1a1
750 |
750 |
751 | o 2:60c670bf5b30
751 | o 2:60c670bf5b30
752 | |
752 | |
753 | o 1:3d5bf5654eda
753 | o 1:3d5bf5654eda
754 |/
754 |/
755 @ 0:67e992f2c4f3
755 @ 0:67e992f2c4f3
756
756
757
757
758 follow the current revision:
758 follow the current revision:
759
759
760 $ hg log -Gq -r "follow()"
760 $ hg log -Gq -r "follow()"
761 @ 0:67e992f2c4f3
761 @ 0:67e992f2c4f3
762
762
763
763
764 $ hg up -qC 4
764 $ hg up -qC 4
765
765
766 log -f -r null
766 log -f -r null
767
767
768 $ hg log -f -r null
768 $ hg log -f -r null
769 changeset: -1:000000000000
769 changeset: -1:000000000000
770 user:
770 user:
771 date: Thu Jan 01 00:00:00 1970 +0000
771 date: Thu Jan 01 00:00:00 1970 +0000
772
772
773 $ hg log -f -r null -G
773 $ hg log -f -r null -G
774 o changeset: -1:000000000000
774 o changeset: -1:000000000000
775 user:
775 user:
776 date: Thu Jan 01 00:00:00 1970 +0000
776 date: Thu Jan 01 00:00:00 1970 +0000
777
777
778
778
779
779
780 log -f with null parent
780 log -f with null parent
781
781
782 $ hg up -C null
782 $ hg up -C null
783 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
783 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
784 $ hg log -f
784 $ hg log -f
785
785
786
786
787 log -r . with two parents
787 log -r . with two parents
788
788
789 $ hg up -C 3
789 $ hg up -C 3
790 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
790 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
791 $ hg merge tip
791 $ hg merge tip
792 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
792 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
793 (branch merge, don't forget to commit)
793 (branch merge, don't forget to commit)
794 $ hg log -r .
794 $ hg log -r .
795 changeset: 3:e62f78d544b4
795 changeset: 3:e62f78d544b4
796 parent: 1:3d5bf5654eda
796 parent: 1:3d5bf5654eda
797 user: test
797 user: test
798 date: Thu Jan 01 00:00:01 1970 +0000
798 date: Thu Jan 01 00:00:01 1970 +0000
799 summary: b1
799 summary: b1
800
800
801
801
802
802
803 log -r . with one parent
803 log -r . with one parent
804
804
805 $ hg ci -mm12 -d '1 0'
805 $ hg ci -mm12 -d '1 0'
806 $ hg log -r .
806 $ hg log -r .
807 changeset: 5:302e9dd6890d
807 changeset: 5:302e9dd6890d
808 tag: tip
808 tag: tip
809 parent: 3:e62f78d544b4
809 parent: 3:e62f78d544b4
810 parent: 4:ddb82e70d1a1
810 parent: 4:ddb82e70d1a1
811 user: test
811 user: test
812 date: Thu Jan 01 00:00:01 1970 +0000
812 date: Thu Jan 01 00:00:01 1970 +0000
813 summary: m12
813 summary: m12
814
814
815
815
816 $ echo postm >> b1
816 $ echo postm >> b1
817 $ hg ci -Amb1.1 -d'1 0'
817 $ hg ci -Amb1.1 -d'1 0'
818
818
819
819
820 log --follow-first
820 log --follow-first
821
821
822 $ hg log --follow-first
822 $ hg log --follow-first
823 changeset: 6:2404bbcab562
823 changeset: 6:2404bbcab562
824 tag: tip
824 tag: tip
825 user: test
825 user: test
826 date: Thu Jan 01 00:00:01 1970 +0000
826 date: Thu Jan 01 00:00:01 1970 +0000
827 summary: b1.1
827 summary: b1.1
828
828
829 changeset: 5:302e9dd6890d
829 changeset: 5:302e9dd6890d
830 parent: 3:e62f78d544b4
830 parent: 3:e62f78d544b4
831 parent: 4:ddb82e70d1a1
831 parent: 4:ddb82e70d1a1
832 user: test
832 user: test
833 date: Thu Jan 01 00:00:01 1970 +0000
833 date: Thu Jan 01 00:00:01 1970 +0000
834 summary: m12
834 summary: m12
835
835
836 changeset: 3:e62f78d544b4
836 changeset: 3:e62f78d544b4
837 parent: 1:3d5bf5654eda
837 parent: 1:3d5bf5654eda
838 user: test
838 user: test
839 date: Thu Jan 01 00:00:01 1970 +0000
839 date: Thu Jan 01 00:00:01 1970 +0000
840 summary: b1
840 summary: b1
841
841
842 changeset: 1:3d5bf5654eda
842 changeset: 1:3d5bf5654eda
843 user: test
843 user: test
844 date: Thu Jan 01 00:00:01 1970 +0000
844 date: Thu Jan 01 00:00:01 1970 +0000
845 summary: r1
845 summary: r1
846
846
847 changeset: 0:67e992f2c4f3
847 changeset: 0:67e992f2c4f3
848 user: test
848 user: test
849 date: Thu Jan 01 00:00:01 1970 +0000
849 date: Thu Jan 01 00:00:01 1970 +0000
850 summary: base
850 summary: base
851
851
852
852
853
853
854 log -P 2
854 log -P 2
855
855
856 $ hg log -P 2
856 $ hg log -P 2
857 changeset: 6:2404bbcab562
857 changeset: 6:2404bbcab562
858 tag: tip
858 tag: tip
859 user: test
859 user: test
860 date: Thu Jan 01 00:00:01 1970 +0000
860 date: Thu Jan 01 00:00:01 1970 +0000
861 summary: b1.1
861 summary: b1.1
862
862
863 changeset: 5:302e9dd6890d
863 changeset: 5:302e9dd6890d
864 parent: 3:e62f78d544b4
864 parent: 3:e62f78d544b4
865 parent: 4:ddb82e70d1a1
865 parent: 4:ddb82e70d1a1
866 user: test
866 user: test
867 date: Thu Jan 01 00:00:01 1970 +0000
867 date: Thu Jan 01 00:00:01 1970 +0000
868 summary: m12
868 summary: m12
869
869
870 changeset: 4:ddb82e70d1a1
870 changeset: 4:ddb82e70d1a1
871 parent: 0:67e992f2c4f3
871 parent: 0:67e992f2c4f3
872 user: test
872 user: test
873 date: Thu Jan 01 00:00:01 1970 +0000
873 date: Thu Jan 01 00:00:01 1970 +0000
874 summary: b2
874 summary: b2
875
875
876 changeset: 3:e62f78d544b4
876 changeset: 3:e62f78d544b4
877 parent: 1:3d5bf5654eda
877 parent: 1:3d5bf5654eda
878 user: test
878 user: test
879 date: Thu Jan 01 00:00:01 1970 +0000
879 date: Thu Jan 01 00:00:01 1970 +0000
880 summary: b1
880 summary: b1
881
881
882
882
883
883
884 log -r tip -p --git
884 log -r tip -p --git
885
885
886 $ hg log -r tip -p --git
886 $ hg log -r tip -p --git
887 changeset: 6:2404bbcab562
887 changeset: 6:2404bbcab562
888 tag: tip
888 tag: tip
889 user: test
889 user: test
890 date: Thu Jan 01 00:00:01 1970 +0000
890 date: Thu Jan 01 00:00:01 1970 +0000
891 summary: b1.1
891 summary: b1.1
892
892
893 diff --git a/b1 b/b1
893 diff --git a/b1 b/b1
894 --- a/b1
894 --- a/b1
895 +++ b/b1
895 +++ b/b1
896 @@ -1,1 +1,2 @@
896 @@ -1,1 +1,2 @@
897 b1
897 b1
898 +postm
898 +postm
899
899
900
900
901
901
902 log -r ""
902 log -r ""
903
903
904 $ hg log -r ''
904 $ hg log -r ''
905 hg: parse error: empty query
905 hg: parse error: empty query
906 [255]
906 [255]
907
907
908 log -r <some unknown node id>
908 log -r <some unknown node id>
909
909
910 $ hg log -r 1000000000000000000000000000000000000000
910 $ hg log -r 1000000000000000000000000000000000000000
911 abort: unknown revision '1000000000000000000000000000000000000000'!
911 abort: unknown revision '1000000000000000000000000000000000000000'!
912 [255]
912 [255]
913
913
914 log -k r1
914 log -k r1
915
915
916 $ hg log -k r1
916 $ hg log -k r1
917 changeset: 1:3d5bf5654eda
917 changeset: 1:3d5bf5654eda
918 user: test
918 user: test
919 date: Thu Jan 01 00:00:01 1970 +0000
919 date: Thu Jan 01 00:00:01 1970 +0000
920 summary: r1
920 summary: r1
921
921
922 log -p -l2 --color=always
922 log -p -l2 --color=always
923
923
924 $ hg --config extensions.color= --config color.mode=ansi \
924 $ hg --config extensions.color= --config color.mode=ansi \
925 > log -p -l2 --color=always
925 > log -p -l2 --color=always
926 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
926 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
927 tag: tip
927 tag: tip
928 user: test
928 user: test
929 date: Thu Jan 01 00:00:01 1970 +0000
929 date: Thu Jan 01 00:00:01 1970 +0000
930 summary: b1.1
930 summary: b1.1
931
931
932 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
932 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
933 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
933 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
934 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
934 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
935 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
935 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
936 b1
936 b1
937 \x1b[0;32m+postm\x1b[0m (esc)
937 \x1b[0;32m+postm\x1b[0m (esc)
938
938
939 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
939 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
940 parent: 3:e62f78d544b4
940 parent: 3:e62f78d544b4
941 parent: 4:ddb82e70d1a1
941 parent: 4:ddb82e70d1a1
942 user: test
942 user: test
943 date: Thu Jan 01 00:00:01 1970 +0000
943 date: Thu Jan 01 00:00:01 1970 +0000
944 summary: m12
944 summary: m12
945
945
946 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
946 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
947 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
947 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
948 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
948 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
949 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
949 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
950 \x1b[0;32m+b2\x1b[0m (esc)
950 \x1b[0;32m+b2\x1b[0m (esc)
951
951
952
952
953
953
954 log -r tip --stat
954 log -r tip --stat
955
955
956 $ hg log -r tip --stat
956 $ hg log -r tip --stat
957 changeset: 6:2404bbcab562
957 changeset: 6:2404bbcab562
958 tag: tip
958 tag: tip
959 user: test
959 user: test
960 date: Thu Jan 01 00:00:01 1970 +0000
960 date: Thu Jan 01 00:00:01 1970 +0000
961 summary: b1.1
961 summary: b1.1
962
962
963 b1 | 1 +
963 b1 | 1 +
964 1 files changed, 1 insertions(+), 0 deletions(-)
964 1 files changed, 1 insertions(+), 0 deletions(-)
965
965
966
966
967 $ cd ..
967 $ cd ..
968
968
969 log --follow --patch FILE in repository where linkrev isn't trustworthy
969 log --follow --patch FILE in repository where linkrev isn't trustworthy
970 (issue5376)
970 (issue5376)
971
971
972 $ hg init follow-dup
972 $ hg init follow-dup
973 $ cd follow-dup
973 $ cd follow-dup
974 $ cat <<EOF >> .hg/hgrc
974 $ cat <<EOF >> .hg/hgrc
975 > [ui]
975 > [ui]
976 > logtemplate = '=== {rev}: {desc}\n'
976 > logtemplate = '=== {rev}: {desc}\n'
977 > [diff]
977 > [diff]
978 > nodates = True
978 > nodates = True
979 > EOF
979 > EOF
980 $ echo 0 >> a
980 $ echo 0 >> a
981 $ hg ci -qAm 'a0'
981 $ hg ci -qAm 'a0'
982 $ echo 1 >> a
982 $ echo 1 >> a
983 $ hg ci -m 'a1'
983 $ hg ci -m 'a1'
984 $ hg up -q 0
984 $ hg up -q 0
985 $ echo 1 >> a
985 $ echo 1 >> a
986 $ touch b
986 $ touch b
987 $ hg ci -qAm 'a1 with b'
987 $ hg ci -qAm 'a1 with b'
988 $ echo 3 >> a
988 $ echo 3 >> a
989 $ hg ci -m 'a3'
989 $ hg ci -m 'a3'
990
990
991 fctx.rev() == 2, but fctx.linkrev() == 1
991 fctx.rev() == 2, but fctx.linkrev() == 1
992
992
993 $ hg log -pf a
993 $ hg log -pf a
994 === 3: a3
994 === 3: a3
995 diff -r 4ea02ba94d66 -r e7a6331a34f0 a
995 diff -r 4ea02ba94d66 -r e7a6331a34f0 a
996 --- a/a
996 --- a/a
997 +++ b/a
997 +++ b/a
998 @@ -1,2 +1,3 @@
998 @@ -1,2 +1,3 @@
999 0
999 0
1000 1
1000 1
1001 +3
1001 +3
1002
1002
1003 === 2: a1 with b
1003 === 2: a1 with b
1004 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1004 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1005 --- a/a
1005 --- a/a
1006 +++ b/a
1006 +++ b/a
1007 @@ -1,1 +1,2 @@
1007 @@ -1,1 +1,2 @@
1008 0
1008 0
1009 +1
1009 +1
1010
1010
1011 === 0: a0
1011 === 0: a0
1012 diff -r 000000000000 -r 49b5e81287e2 a
1012 diff -r 000000000000 -r 49b5e81287e2 a
1013 --- /dev/null
1013 --- /dev/null
1014 +++ b/a
1014 +++ b/a
1015 @@ -0,0 +1,1 @@
1015 @@ -0,0 +1,1 @@
1016 +0
1016 +0
1017
1017
1018
1018
1019 fctx.introrev() == 2, but fctx.linkrev() == 1
1019 fctx.introrev() == 2, but fctx.linkrev() == 1
1020
1020
1021 $ hg up -q 2
1021 $ hg up -q 2
1022 $ hg log -pf a
1022 $ hg log -pf a
1023 === 2: a1 with b
1023 === 2: a1 with b
1024 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1024 diff -r 49b5e81287e2 -r 4ea02ba94d66 a
1025 --- a/a
1025 --- a/a
1026 +++ b/a
1026 +++ b/a
1027 @@ -1,1 +1,2 @@
1027 @@ -1,1 +1,2 @@
1028 0
1028 0
1029 +1
1029 +1
1030
1030
1031 === 0: a0
1031 === 0: a0
1032 diff -r 000000000000 -r 49b5e81287e2 a
1032 diff -r 000000000000 -r 49b5e81287e2 a
1033 --- /dev/null
1033 --- /dev/null
1034 +++ b/a
1034 +++ b/a
1035 @@ -0,0 +1,1 @@
1035 @@ -0,0 +1,1 @@
1036 +0
1036 +0
1037
1037
1038
1038
1039 $ cd ..
1039 $ cd ..
1040
1040
1041 Multiple copy sources of a file:
1041 Multiple copy sources of a file:
1042
1042
1043 $ hg init follow-multi
1043 $ hg init follow-multi
1044 $ cd follow-multi
1044 $ cd follow-multi
1045 $ echo 0 >> a
1045 $ echo 0 >> a
1046 $ hg ci -qAm 'a'
1046 $ hg ci -qAm 'a'
1047 $ hg cp a b
1047 $ hg cp a b
1048 $ hg ci -m 'a->b'
1048 $ hg ci -m 'a->b'
1049 $ echo 2 >> a
1049 $ echo 2 >> a
1050 $ hg ci -m 'a'
1050 $ hg ci -m 'a'
1051 $ echo 3 >> b
1051 $ echo 3 >> b
1052 $ hg ci -m 'b'
1052 $ hg ci -m 'b'
1053 $ echo 4 >> a
1053 $ echo 4 >> a
1054 $ echo 4 >> b
1054 $ echo 4 >> b
1055 $ hg ci -m 'a,b'
1055 $ hg ci -m 'a,b'
1056 $ echo 5 >> a
1056 $ echo 5 >> a
1057 $ hg ci -m 'a0'
1057 $ hg ci -m 'a0'
1058 $ echo 6 >> b
1058 $ echo 6 >> b
1059 $ hg ci -m 'b0'
1059 $ hg ci -m 'b0'
1060 $ hg up -q 4
1060 $ hg up -q 4
1061 $ echo 7 >> b
1061 $ echo 7 >> b
1062 $ hg ci -m 'b1'
1062 $ hg ci -m 'b1'
1063 created new head
1063 created new head
1064 $ echo 8 >> a
1064 $ echo 8 >> a
1065 $ hg ci -m 'a1'
1065 $ hg ci -m 'a1'
1066 $ hg rm a
1066 $ hg rm a
1067 $ hg mv b a
1067 $ hg mv b a
1068 $ hg ci -m 'b1->a1'
1068 $ hg ci -m 'b1->a1'
1069 $ hg merge -qt :local
1069 $ hg merge -qt :local
1070 $ hg ci -m '(a0,b1->a1)->a'
1070 $ hg ci -m '(a0,b1->a1)->a'
1071
1071
1072 $ hg log -GT '{rev}: {desc}\n'
1072 $ hg log -GT '{rev}: {desc}\n'
1073 @ 10: (a0,b1->a1)->a
1073 @ 10: (a0,b1->a1)->a
1074 |\
1074 |\
1075 | o 9: b1->a1
1075 | o 9: b1->a1
1076 | |
1076 | |
1077 | o 8: a1
1077 | o 8: a1
1078 | |
1078 | |
1079 | o 7: b1
1079 | o 7: b1
1080 | |
1080 | |
1081 o | 6: b0
1081 o | 6: b0
1082 | |
1082 | |
1083 o | 5: a0
1083 o | 5: a0
1084 |/
1084 |/
1085 o 4: a,b
1085 o 4: a,b
1086 |
1086 |
1087 o 3: b
1087 o 3: b
1088 |
1088 |
1089 o 2: a
1089 o 2: a
1090 |
1090 |
1091 o 1: a->b
1091 o 1: a->b
1092 |
1092 |
1093 o 0: a
1093 o 0: a
1094
1094
1095
1095
1096 since file 'a' has multiple copy sources at the revision 4, ancestors can't
1096 since file 'a' has multiple copy sources at the revision 4, ancestors can't
1097 be indexed solely by fctx.linkrev().
1097 be indexed solely by fctx.linkrev().
1098
1098
1099 $ hg log -T '{rev}: {desc}\n' -f a
1099 $ hg log -T '{rev}: {desc}\n' -f a
1100 10: (a0,b1->a1)->a
1100 10: (a0,b1->a1)->a
1101 9: b1->a1
1101 9: b1->a1
1102 7: b1
1102 7: b1
1103 5: a0
1103 5: a0
1104 4: a,b
1104 4: a,b
1105 3: b
1105 3: b
1106 2: a
1106 2: a
1107 1: a->b
1107 1: a->b
1108 0: a
1108 0: a
1109
1109
1110 $ cd ..
1110 $ cd ..
1111
1111
1112 Test that log should respect the order of -rREV even if multiple OR conditions
1112 Test that log should respect the order of -rREV even if multiple OR conditions
1113 are specified (issue5100):
1113 are specified (issue5100):
1114
1114
1115 $ hg init revorder
1115 $ hg init revorder
1116 $ cd revorder
1116 $ cd revorder
1117
1117
1118 $ hg branch -q b0
1118 $ hg branch -q b0
1119 $ echo 0 >> f0
1119 $ echo 0 >> f0
1120 $ hg ci -qAm k0 -u u0
1120 $ hg ci -qAm k0 -u u0
1121 $ hg branch -q b1
1121 $ hg branch -q b1
1122 $ echo 1 >> f1
1122 $ echo 1 >> f1
1123 $ hg ci -qAm k1 -u u1
1123 $ hg ci -qAm k1 -u u1
1124 $ hg branch -q b2
1124 $ hg branch -q b2
1125 $ echo 2 >> f2
1125 $ echo 2 >> f2
1126 $ hg ci -qAm k2 -u u2
1126 $ hg ci -qAm k2 -u u2
1127
1127
1128 $ hg update -q b2
1128 $ hg update -q b2
1129 $ echo 3 >> f2
1129 $ echo 3 >> f2
1130 $ hg ci -qAm k2 -u u2
1130 $ hg ci -qAm k2 -u u2
1131 $ hg update -q b1
1131 $ hg update -q b1
1132 $ echo 4 >> f1
1132 $ echo 4 >> f1
1133 $ hg ci -qAm k1 -u u1
1133 $ hg ci -qAm k1 -u u1
1134 $ hg update -q b0
1134 $ hg update -q b0
1135 $ echo 5 >> f0
1135 $ echo 5 >> f0
1136 $ hg ci -qAm k0 -u u0
1136 $ hg ci -qAm k0 -u u0
1137
1137
1138 summary of revisions:
1138 summary of revisions:
1139
1139
1140 $ hg log -G -T '{rev} {branch} {author} {desc} {files}\n'
1140 $ hg log -G -T '{rev} {branch} {author} {desc} {files}\n'
1141 @ 5 b0 u0 k0 f0
1141 @ 5 b0 u0 k0 f0
1142 |
1142 |
1143 | o 4 b1 u1 k1 f1
1143 | o 4 b1 u1 k1 f1
1144 | |
1144 | |
1145 | | o 3 b2 u2 k2 f2
1145 | | o 3 b2 u2 k2 f2
1146 | | |
1146 | | |
1147 | | o 2 b2 u2 k2 f2
1147 | | o 2 b2 u2 k2 f2
1148 | |/
1148 | |/
1149 | o 1 b1 u1 k1 f1
1149 | o 1 b1 u1 k1 f1
1150 |/
1150 |/
1151 o 0 b0 u0 k0 f0
1151 o 0 b0 u0 k0 f0
1152
1152
1153
1153
1154 log -b BRANCH in ascending order:
1154 log -b BRANCH in ascending order:
1155
1155
1156 $ hg log -r0:tip -T '{rev} {branch}\n' -b b0 -b b1
1156 $ hg log -r0:tip -T '{rev} {branch}\n' -b b0 -b b1
1157 0 b0
1157 0 b0
1158 1 b1
1158 1 b1
1159 4 b1
1159 4 b1
1160 5 b0
1160 5 b0
1161 $ hg log -r0:tip -T '{rev} {branch}\n' -b b1 -b b0
1161 $ hg log -r0:tip -T '{rev} {branch}\n' -b b1 -b b0
1162 0 b0
1162 0 b0
1163 1 b1
1163 1 b1
1164 4 b1
1164 4 b1
1165 5 b0
1165 5 b0
1166
1166
1167 log --only-branch BRANCH in descending order:
1167 log --only-branch BRANCH in descending order:
1168
1168
1169 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b1 --only-branch b2
1169 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b1 --only-branch b2
1170 4 b1
1170 4 b1
1171 3 b2
1171 3 b2
1172 2 b2
1172 2 b2
1173 1 b1
1173 1 b1
1174 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b2 --only-branch b1
1174 $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b2 --only-branch b1
1175 4 b1
1175 4 b1
1176 3 b2
1176 3 b2
1177 2 b2
1177 2 b2
1178 1 b1
1178 1 b1
1179
1179
1180 log -u USER in ascending order, against compound set:
1180 log -u USER in ascending order, against compound set:
1181
1181
1182 $ hg log -r'::head()' -T '{rev} {author}\n' -u u0 -u u2
1182 $ hg log -r'::head()' -T '{rev} {author}\n' -u u0 -u u2
1183 0 u0
1183 0 u0
1184 2 u2
1184 2 u2
1185 3 u2
1185 3 u2
1186 5 u0
1186 5 u0
1187 $ hg log -r'::head()' -T '{rev} {author}\n' -u u2 -u u0
1187 $ hg log -r'::head()' -T '{rev} {author}\n' -u u2 -u u0
1188 0 u0
1188 0 u0
1189 2 u2
1189 2 u2
1190 3 u2
1190 3 u2
1191 5 u0
1191 5 u0
1192
1192
1193 log -k TEXT in descending order, against compound set:
1193 log -k TEXT in descending order, against compound set:
1194
1194
1195 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k0 -k k1 -k k2
1195 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k0 -k k1 -k k2
1196 5 k0
1196 5 k0
1197 3 k2
1197 3 k2
1198 2 k2
1198 2 k2
1199 1 k1
1199 1 k1
1200 0 k0
1200 0 k0
1201 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k2 -k k1 -k k0
1201 $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k2 -k k1 -k k0
1202 5 k0
1202 5 k0
1203 3 k2
1203 3 k2
1204 2 k2
1204 2 k2
1205 1 k1
1205 1 k1
1206 0 k0
1206 0 k0
1207
1207
1208 log FILE in ascending order, against dagrange:
1208 log FILE in ascending order, against dagrange:
1209
1209
1210 $ hg log -r1:: -T '{rev} {files}\n' f1 f2
1210 $ hg log -r1:: -T '{rev} {files}\n' f1 f2
1211 1 f1
1211 1 f1
1212 2 f2
1212 2 f2
1213 3 f2
1213 3 f2
1214 4 f1
1214 4 f1
1215 $ hg log -r1:: -T '{rev} {files}\n' f2 f1
1215 $ hg log -r1:: -T '{rev} {files}\n' f2 f1
1216 1 f1
1216 1 f1
1217 2 f2
1217 2 f2
1218 3 f2
1218 3 f2
1219 4 f1
1219 4 f1
1220
1220
1221 $ cd ..
1221 $ cd ..
1222
1222
1223 User
1223 User
1224
1224
1225 $ hg init usertest
1225 $ hg init usertest
1226 $ cd usertest
1226 $ cd usertest
1227
1227
1228 $ echo a > a
1228 $ echo a > a
1229 $ hg ci -A -m "a" -u "User One <user1@example.org>"
1229 $ hg ci -A -m "a" -u "User One <user1@example.org>"
1230 adding a
1230 adding a
1231 $ echo b > b
1231 $ echo b > b
1232 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
1232 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
1233 adding b
1233 adding b
1234
1234
1235 $ hg log -u "User One <user1@example.org>"
1235 $ hg log -u "User One <user1@example.org>"
1236 changeset: 0:29a4c94f1924
1236 changeset: 0:29a4c94f1924
1237 user: User One <user1@example.org>
1237 user: User One <user1@example.org>
1238 date: Thu Jan 01 00:00:00 1970 +0000
1238 date: Thu Jan 01 00:00:00 1970 +0000
1239 summary: a
1239 summary: a
1240
1240
1241 $ hg log -u "user1" -u "user2"
1241 $ hg log -u "user1" -u "user2"
1242 changeset: 1:e834b5e69c0e
1242 changeset: 1:e834b5e69c0e
1243 tag: tip
1243 tag: tip
1244 user: User Two <user2@example.org>
1244 user: User Two <user2@example.org>
1245 date: Thu Jan 01 00:00:00 1970 +0000
1245 date: Thu Jan 01 00:00:00 1970 +0000
1246 summary: b
1246 summary: b
1247
1247
1248 changeset: 0:29a4c94f1924
1248 changeset: 0:29a4c94f1924
1249 user: User One <user1@example.org>
1249 user: User One <user1@example.org>
1250 date: Thu Jan 01 00:00:00 1970 +0000
1250 date: Thu Jan 01 00:00:00 1970 +0000
1251 summary: a
1251 summary: a
1252
1252
1253 $ hg log -u "user3"
1253 $ hg log -u "user3"
1254
1254
1255 "-u USER" shouldn't be overridden by "user(USER)" alias
1255 "-u USER" shouldn't be overridden by "user(USER)" alias
1256
1256
1257 $ hg log --config 'revsetalias.user(x)=branch(x)' -u default
1257 $ hg log --config 'revsetalias.user(x)=branch(x)' -u default
1258 $ hg log --config 'revsetalias.user(x)=branch(x)' -u user1
1258 $ hg log --config 'revsetalias.user(x)=branch(x)' -u user1
1259 changeset: 0:29a4c94f1924
1259 changeset: 0:29a4c94f1924
1260 user: User One <user1@example.org>
1260 user: User One <user1@example.org>
1261 date: Thu Jan 01 00:00:00 1970 +0000
1261 date: Thu Jan 01 00:00:00 1970 +0000
1262 summary: a
1262 summary: a
1263
1263
1264
1264
1265 $ cd ..
1265 $ cd ..
1266
1266
1267 $ hg init branches
1267 $ hg init branches
1268 $ cd branches
1268 $ cd branches
1269
1269
1270 $ echo a > a
1270 $ echo a > a
1271 $ hg ci -A -m "commit on default"
1271 $ hg ci -A -m "commit on default"
1272 adding a
1272 adding a
1273 $ hg branch test
1273 $ hg branch test
1274 marked working directory as branch test
1274 marked working directory as branch test
1275 (branches are permanent and global, did you want a bookmark?)
1275 (branches are permanent and global, did you want a bookmark?)
1276 $ echo b > b
1276 $ echo b > b
1277 $ hg ci -A -m "commit on test"
1277 $ hg ci -A -m "commit on test"
1278 adding b
1278 adding b
1279
1279
1280 $ hg up default
1280 $ hg up default
1281 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1281 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1282 $ echo c > c
1282 $ echo c > c
1283 $ hg ci -A -m "commit on default"
1283 $ hg ci -A -m "commit on default"
1284 adding c
1284 adding c
1285 $ hg up test
1285 $ hg up test
1286 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1286 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1287 $ echo c > c
1287 $ echo c > c
1288 $ hg ci -A -m "commit on test"
1288 $ hg ci -A -m "commit on test"
1289 adding c
1289 adding c
1290
1290
1291
1291
1292 log -b default
1292 log -b default
1293
1293
1294 $ hg log -b default
1294 $ hg log -b default
1295 changeset: 2:c3a4f03cc9a7
1295 changeset: 2:c3a4f03cc9a7
1296 parent: 0:24427303d56f
1296 parent: 0:24427303d56f
1297 user: test
1297 user: test
1298 date: Thu Jan 01 00:00:00 1970 +0000
1298 date: Thu Jan 01 00:00:00 1970 +0000
1299 summary: commit on default
1299 summary: commit on default
1300
1300
1301 changeset: 0:24427303d56f
1301 changeset: 0:24427303d56f
1302 user: test
1302 user: test
1303 date: Thu Jan 01 00:00:00 1970 +0000
1303 date: Thu Jan 01 00:00:00 1970 +0000
1304 summary: commit on default
1304 summary: commit on default
1305
1305
1306
1306
1307
1307
1308 log -b test
1308 log -b test
1309
1309
1310 $ hg log -b test
1310 $ hg log -b test
1311 changeset: 3:f5d8de11c2e2
1311 changeset: 3:f5d8de11c2e2
1312 branch: test
1312 branch: test
1313 tag: tip
1313 tag: tip
1314 parent: 1:d32277701ccb
1314 parent: 1:d32277701ccb
1315 user: test
1315 user: test
1316 date: Thu Jan 01 00:00:00 1970 +0000
1316 date: Thu Jan 01 00:00:00 1970 +0000
1317 summary: commit on test
1317 summary: commit on test
1318
1318
1319 changeset: 1:d32277701ccb
1319 changeset: 1:d32277701ccb
1320 branch: test
1320 branch: test
1321 user: test
1321 user: test
1322 date: Thu Jan 01 00:00:00 1970 +0000
1322 date: Thu Jan 01 00:00:00 1970 +0000
1323 summary: commit on test
1323 summary: commit on test
1324
1324
1325
1325
1326
1326
1327 log -b dummy
1327 log -b dummy
1328
1328
1329 $ hg log -b dummy
1329 $ hg log -b dummy
1330 abort: unknown revision 'dummy'!
1330 abort: unknown revision 'dummy'!
1331 [255]
1331 [255]
1332
1332
1333
1333
1334 log -b .
1334 log -b .
1335
1335
1336 $ hg log -b .
1336 $ hg log -b .
1337 changeset: 3:f5d8de11c2e2
1337 changeset: 3:f5d8de11c2e2
1338 branch: test
1338 branch: test
1339 tag: tip
1339 tag: tip
1340 parent: 1:d32277701ccb
1340 parent: 1:d32277701ccb
1341 user: test
1341 user: test
1342 date: Thu Jan 01 00:00:00 1970 +0000
1342 date: Thu Jan 01 00:00:00 1970 +0000
1343 summary: commit on test
1343 summary: commit on test
1344
1344
1345 changeset: 1:d32277701ccb
1345 changeset: 1:d32277701ccb
1346 branch: test
1346 branch: test
1347 user: test
1347 user: test
1348 date: Thu Jan 01 00:00:00 1970 +0000
1348 date: Thu Jan 01 00:00:00 1970 +0000
1349 summary: commit on test
1349 summary: commit on test
1350
1350
1351
1351
1352
1352
1353 log -b default -b test
1353 log -b default -b test
1354
1354
1355 $ hg log -b default -b test
1355 $ hg log -b default -b test
1356 changeset: 3:f5d8de11c2e2
1356 changeset: 3:f5d8de11c2e2
1357 branch: test
1357 branch: test
1358 tag: tip
1358 tag: tip
1359 parent: 1:d32277701ccb
1359 parent: 1:d32277701ccb
1360 user: test
1360 user: test
1361 date: Thu Jan 01 00:00:00 1970 +0000
1361 date: Thu Jan 01 00:00:00 1970 +0000
1362 summary: commit on test
1362 summary: commit on test
1363
1363
1364 changeset: 2:c3a4f03cc9a7
1364 changeset: 2:c3a4f03cc9a7
1365 parent: 0:24427303d56f
1365 parent: 0:24427303d56f
1366 user: test
1366 user: test
1367 date: Thu Jan 01 00:00:00 1970 +0000
1367 date: Thu Jan 01 00:00:00 1970 +0000
1368 summary: commit on default
1368 summary: commit on default
1369
1369
1370 changeset: 1:d32277701ccb
1370 changeset: 1:d32277701ccb
1371 branch: test
1371 branch: test
1372 user: test
1372 user: test
1373 date: Thu Jan 01 00:00:00 1970 +0000
1373 date: Thu Jan 01 00:00:00 1970 +0000
1374 summary: commit on test
1374 summary: commit on test
1375
1375
1376 changeset: 0:24427303d56f
1376 changeset: 0:24427303d56f
1377 user: test
1377 user: test
1378 date: Thu Jan 01 00:00:00 1970 +0000
1378 date: Thu Jan 01 00:00:00 1970 +0000
1379 summary: commit on default
1379 summary: commit on default
1380
1380
1381
1381
1382
1382
1383 log -b default -b .
1383 log -b default -b .
1384
1384
1385 $ hg log -b default -b .
1385 $ hg log -b default -b .
1386 changeset: 3:f5d8de11c2e2
1386 changeset: 3:f5d8de11c2e2
1387 branch: test
1387 branch: test
1388 tag: tip
1388 tag: tip
1389 parent: 1:d32277701ccb
1389 parent: 1:d32277701ccb
1390 user: test
1390 user: test
1391 date: Thu Jan 01 00:00:00 1970 +0000
1391 date: Thu Jan 01 00:00:00 1970 +0000
1392 summary: commit on test
1392 summary: commit on test
1393
1393
1394 changeset: 2:c3a4f03cc9a7
1394 changeset: 2:c3a4f03cc9a7
1395 parent: 0:24427303d56f
1395 parent: 0:24427303d56f
1396 user: test
1396 user: test
1397 date: Thu Jan 01 00:00:00 1970 +0000
1397 date: Thu Jan 01 00:00:00 1970 +0000
1398 summary: commit on default
1398 summary: commit on default
1399
1399
1400 changeset: 1:d32277701ccb
1400 changeset: 1:d32277701ccb
1401 branch: test
1401 branch: test
1402 user: test
1402 user: test
1403 date: Thu Jan 01 00:00:00 1970 +0000
1403 date: Thu Jan 01 00:00:00 1970 +0000
1404 summary: commit on test
1404 summary: commit on test
1405
1405
1406 changeset: 0:24427303d56f
1406 changeset: 0:24427303d56f
1407 user: test
1407 user: test
1408 date: Thu Jan 01 00:00:00 1970 +0000
1408 date: Thu Jan 01 00:00:00 1970 +0000
1409 summary: commit on default
1409 summary: commit on default
1410
1410
1411
1411
1412
1412
1413 log -b . -b test
1413 log -b . -b test
1414
1414
1415 $ hg log -b . -b test
1415 $ hg log -b . -b test
1416 changeset: 3:f5d8de11c2e2
1416 changeset: 3:f5d8de11c2e2
1417 branch: test
1417 branch: test
1418 tag: tip
1418 tag: tip
1419 parent: 1:d32277701ccb
1419 parent: 1:d32277701ccb
1420 user: test
1420 user: test
1421 date: Thu Jan 01 00:00:00 1970 +0000
1421 date: Thu Jan 01 00:00:00 1970 +0000
1422 summary: commit on test
1422 summary: commit on test
1423
1423
1424 changeset: 1:d32277701ccb
1424 changeset: 1:d32277701ccb
1425 branch: test
1425 branch: test
1426 user: test
1426 user: test
1427 date: Thu Jan 01 00:00:00 1970 +0000
1427 date: Thu Jan 01 00:00:00 1970 +0000
1428 summary: commit on test
1428 summary: commit on test
1429
1429
1430
1430
1431
1431
1432 log -b 2
1432 log -b 2
1433
1433
1434 $ hg log -b 2
1434 $ hg log -b 2
1435 changeset: 2:c3a4f03cc9a7
1435 changeset: 2:c3a4f03cc9a7
1436 parent: 0:24427303d56f
1436 parent: 0:24427303d56f
1437 user: test
1437 user: test
1438 date: Thu Jan 01 00:00:00 1970 +0000
1438 date: Thu Jan 01 00:00:00 1970 +0000
1439 summary: commit on default
1439 summary: commit on default
1440
1440
1441 changeset: 0:24427303d56f
1441 changeset: 0:24427303d56f
1442 user: test
1442 user: test
1443 date: Thu Jan 01 00:00:00 1970 +0000
1443 date: Thu Jan 01 00:00:00 1970 +0000
1444 summary: commit on default
1444 summary: commit on default
1445
1445
1446 #if gettext
1446 #if gettext
1447
1447
1448 Test that all log names are translated (e.g. branches, bookmarks, tags):
1448 Test that all log names are translated (e.g. branches, bookmarks, tags):
1449
1449
1450 $ hg bookmark babar -r tip
1450 $ hg bookmark babar -r tip
1451
1451
1452 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1452 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1453 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1453 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1454 Zweig: test
1454 Zweig: test
1455 Lesezeichen: babar
1455 Lesezeichen: babar
1456 Marke: tip
1456 Marke: tip
1457 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1457 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1458 Nutzer: test
1458 Nutzer: test
1459 Datum: Thu Jan 01 00:00:00 1970 +0000
1459 Datum: Thu Jan 01 00:00:00 1970 +0000
1460 Zusammenfassung: commit on test
1460 Zusammenfassung: commit on test
1461
1461
1462 $ hg bookmark -d babar
1462 $ hg bookmark -d babar
1463
1463
1464 #endif
1464 #endif
1465
1465
1466 log -p --cwd dir (in subdir)
1466 log -p --cwd dir (in subdir)
1467
1467
1468 $ mkdir dir
1468 $ mkdir dir
1469 $ hg log -p --cwd dir
1469 $ hg log -p --cwd dir
1470 changeset: 3:f5d8de11c2e2
1470 changeset: 3:f5d8de11c2e2
1471 branch: test
1471 branch: test
1472 tag: tip
1472 tag: tip
1473 parent: 1:d32277701ccb
1473 parent: 1:d32277701ccb
1474 user: test
1474 user: test
1475 date: Thu Jan 01 00:00:00 1970 +0000
1475 date: Thu Jan 01 00:00:00 1970 +0000
1476 summary: commit on test
1476 summary: commit on test
1477
1477
1478 diff -r d32277701ccb -r f5d8de11c2e2 c
1478 diff -r d32277701ccb -r f5d8de11c2e2 c
1479 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1479 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1480 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1480 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1481 @@ -0,0 +1,1 @@
1481 @@ -0,0 +1,1 @@
1482 +c
1482 +c
1483
1483
1484 changeset: 2:c3a4f03cc9a7
1484 changeset: 2:c3a4f03cc9a7
1485 parent: 0:24427303d56f
1485 parent: 0:24427303d56f
1486 user: test
1486 user: test
1487 date: Thu Jan 01 00:00:00 1970 +0000
1487 date: Thu Jan 01 00:00:00 1970 +0000
1488 summary: commit on default
1488 summary: commit on default
1489
1489
1490 diff -r 24427303d56f -r c3a4f03cc9a7 c
1490 diff -r 24427303d56f -r c3a4f03cc9a7 c
1491 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1491 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1492 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1492 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1493 @@ -0,0 +1,1 @@
1493 @@ -0,0 +1,1 @@
1494 +c
1494 +c
1495
1495
1496 changeset: 1:d32277701ccb
1496 changeset: 1:d32277701ccb
1497 branch: test
1497 branch: test
1498 user: test
1498 user: test
1499 date: Thu Jan 01 00:00:00 1970 +0000
1499 date: Thu Jan 01 00:00:00 1970 +0000
1500 summary: commit on test
1500 summary: commit on test
1501
1501
1502 diff -r 24427303d56f -r d32277701ccb b
1502 diff -r 24427303d56f -r d32277701ccb b
1503 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1503 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1504 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1504 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1505 @@ -0,0 +1,1 @@
1505 @@ -0,0 +1,1 @@
1506 +b
1506 +b
1507
1507
1508 changeset: 0:24427303d56f
1508 changeset: 0:24427303d56f
1509 user: test
1509 user: test
1510 date: Thu Jan 01 00:00:00 1970 +0000
1510 date: Thu Jan 01 00:00:00 1970 +0000
1511 summary: commit on default
1511 summary: commit on default
1512
1512
1513 diff -r 000000000000 -r 24427303d56f a
1513 diff -r 000000000000 -r 24427303d56f a
1514 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1514 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1515 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1515 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1516 @@ -0,0 +1,1 @@
1516 @@ -0,0 +1,1 @@
1517 +a
1517 +a
1518
1518
1519
1519
1520
1520
1521 log -p -R repo
1521 log -p -R repo
1522
1522
1523 $ cd dir
1523 $ cd dir
1524 $ hg log -p -R .. ../a
1524 $ hg log -p -R .. ../a
1525 changeset: 0:24427303d56f
1525 changeset: 0:24427303d56f
1526 user: test
1526 user: test
1527 date: Thu Jan 01 00:00:00 1970 +0000
1527 date: Thu Jan 01 00:00:00 1970 +0000
1528 summary: commit on default
1528 summary: commit on default
1529
1529
1530 diff -r 000000000000 -r 24427303d56f a
1530 diff -r 000000000000 -r 24427303d56f a
1531 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1531 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1532 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1532 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1533 @@ -0,0 +1,1 @@
1533 @@ -0,0 +1,1 @@
1534 +a
1534 +a
1535
1535
1536
1536
1537 $ cd ../..
1537 $ cd ../..
1538
1538
1539 $ hg init follow2
1539 $ hg init follow2
1540 $ cd follow2
1540 $ cd follow2
1541
1541
1542 # Build the following history:
1542 # Build the following history:
1543 # tip - o - x - o - x - x
1543 # tip - o - x - o - x - x
1544 # \ /
1544 # \ /
1545 # o - o - o - x
1545 # o - o - o - x
1546 # \ /
1546 # \ /
1547 # o
1547 # o
1548 #
1548 #
1549 # Where "o" is a revision containing "foo" and
1549 # Where "o" is a revision containing "foo" and
1550 # "x" is a revision without "foo"
1550 # "x" is a revision without "foo"
1551
1551
1552 $ touch init
1552 $ touch init
1553 $ hg ci -A -m "init, unrelated"
1553 $ hg ci -A -m "init, unrelated"
1554 adding init
1554 adding init
1555 $ echo 'foo' > init
1555 $ echo 'foo' > init
1556 $ hg ci -m "change, unrelated"
1556 $ hg ci -m "change, unrelated"
1557 $ echo 'foo' > foo
1557 $ echo 'foo' > foo
1558 $ hg ci -A -m "add unrelated old foo"
1558 $ hg ci -A -m "add unrelated old foo"
1559 adding foo
1559 adding foo
1560 $ hg rm foo
1560 $ hg rm foo
1561 $ hg ci -m "delete foo, unrelated"
1561 $ hg ci -m "delete foo, unrelated"
1562 $ echo 'related' > foo
1562 $ echo 'related' > foo
1563 $ hg ci -A -m "add foo, related"
1563 $ hg ci -A -m "add foo, related"
1564 adding foo
1564 adding foo
1565
1565
1566 $ hg up 0
1566 $ hg up 0
1567 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1567 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1568 $ touch branch
1568 $ touch branch
1569 $ hg ci -A -m "first branch, unrelated"
1569 $ hg ci -A -m "first branch, unrelated"
1570 adding branch
1570 adding branch
1571 created new head
1571 created new head
1572 $ touch foo
1572 $ touch foo
1573 $ hg ci -A -m "create foo, related"
1573 $ hg ci -A -m "create foo, related"
1574 adding foo
1574 adding foo
1575 $ echo 'change' > foo
1575 $ echo 'change' > foo
1576 $ hg ci -m "change foo, related"
1576 $ hg ci -m "change foo, related"
1577
1577
1578 $ hg up 6
1578 $ hg up 6
1579 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1579 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1580 $ echo 'change foo in branch' > foo
1580 $ echo 'change foo in branch' > foo
1581 $ hg ci -m "change foo in branch, related"
1581 $ hg ci -m "change foo in branch, related"
1582 created new head
1582 created new head
1583 $ hg merge 7
1583 $ hg merge 7
1584 merging foo
1584 merging foo
1585 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1585 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1586 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1586 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1587 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1587 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1588 [1]
1588 [1]
1589 $ echo 'merge 1' > foo
1589 $ echo 'merge 1' > foo
1590 $ hg resolve -m foo
1590 $ hg resolve -m foo
1591 (no more unresolved files)
1591 (no more unresolved files)
1592 $ hg ci -m "First merge, related"
1592 $ hg ci -m "First merge, related"
1593
1593
1594 $ hg merge 4
1594 $ hg merge 4
1595 merging foo
1595 merging foo
1596 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1596 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
1597 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1597 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1598 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1598 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1599 [1]
1599 [1]
1600 $ echo 'merge 2' > foo
1600 $ echo 'merge 2' > foo
1601 $ hg resolve -m foo
1601 $ hg resolve -m foo
1602 (no more unresolved files)
1602 (no more unresolved files)
1603 $ hg ci -m "Last merge, related"
1603 $ hg ci -m "Last merge, related"
1604
1604
1605 $ hg log --graph
1605 $ hg log --graph
1606 @ changeset: 10:4dae8563d2c5
1606 @ changeset: 10:4dae8563d2c5
1607 |\ tag: tip
1607 |\ tag: tip
1608 | | parent: 9:7b35701b003e
1608 | | parent: 9:7b35701b003e
1609 | | parent: 4:88176d361b69
1609 | | parent: 4:88176d361b69
1610 | | user: test
1610 | | user: test
1611 | | date: Thu Jan 01 00:00:00 1970 +0000
1611 | | date: Thu Jan 01 00:00:00 1970 +0000
1612 | | summary: Last merge, related
1612 | | summary: Last merge, related
1613 | |
1613 | |
1614 | o changeset: 9:7b35701b003e
1614 | o changeset: 9:7b35701b003e
1615 | |\ parent: 8:e5416ad8a855
1615 | |\ parent: 8:e5416ad8a855
1616 | | | parent: 7:87fe3144dcfa
1616 | | | parent: 7:87fe3144dcfa
1617 | | | user: test
1617 | | | user: test
1618 | | | date: Thu Jan 01 00:00:00 1970 +0000
1618 | | | date: Thu Jan 01 00:00:00 1970 +0000
1619 | | | summary: First merge, related
1619 | | | summary: First merge, related
1620 | | |
1620 | | |
1621 | | o changeset: 8:e5416ad8a855
1621 | | o changeset: 8:e5416ad8a855
1622 | | | parent: 6:dc6c325fe5ee
1622 | | | parent: 6:dc6c325fe5ee
1623 | | | user: test
1623 | | | user: test
1624 | | | date: Thu Jan 01 00:00:00 1970 +0000
1624 | | | date: Thu Jan 01 00:00:00 1970 +0000
1625 | | | summary: change foo in branch, related
1625 | | | summary: change foo in branch, related
1626 | | |
1626 | | |
1627 | o | changeset: 7:87fe3144dcfa
1627 | o | changeset: 7:87fe3144dcfa
1628 | |/ user: test
1628 | |/ user: test
1629 | | date: Thu Jan 01 00:00:00 1970 +0000
1629 | | date: Thu Jan 01 00:00:00 1970 +0000
1630 | | summary: change foo, related
1630 | | summary: change foo, related
1631 | |
1631 | |
1632 | o changeset: 6:dc6c325fe5ee
1632 | o changeset: 6:dc6c325fe5ee
1633 | | user: test
1633 | | user: test
1634 | | date: Thu Jan 01 00:00:00 1970 +0000
1634 | | date: Thu Jan 01 00:00:00 1970 +0000
1635 | | summary: create foo, related
1635 | | summary: create foo, related
1636 | |
1636 | |
1637 | o changeset: 5:73db34516eb9
1637 | o changeset: 5:73db34516eb9
1638 | | parent: 0:e87515fd044a
1638 | | parent: 0:e87515fd044a
1639 | | user: test
1639 | | user: test
1640 | | date: Thu Jan 01 00:00:00 1970 +0000
1640 | | date: Thu Jan 01 00:00:00 1970 +0000
1641 | | summary: first branch, unrelated
1641 | | summary: first branch, unrelated
1642 | |
1642 | |
1643 o | changeset: 4:88176d361b69
1643 o | changeset: 4:88176d361b69
1644 | | user: test
1644 | | user: test
1645 | | date: Thu Jan 01 00:00:00 1970 +0000
1645 | | date: Thu Jan 01 00:00:00 1970 +0000
1646 | | summary: add foo, related
1646 | | summary: add foo, related
1647 | |
1647 | |
1648 o | changeset: 3:dd78ae4afb56
1648 o | changeset: 3:dd78ae4afb56
1649 | | user: test
1649 | | user: test
1650 | | date: Thu Jan 01 00:00:00 1970 +0000
1650 | | date: Thu Jan 01 00:00:00 1970 +0000
1651 | | summary: delete foo, unrelated
1651 | | summary: delete foo, unrelated
1652 | |
1652 | |
1653 o | changeset: 2:c4c64aedf0f7
1653 o | changeset: 2:c4c64aedf0f7
1654 | | user: test
1654 | | user: test
1655 | | date: Thu Jan 01 00:00:00 1970 +0000
1655 | | date: Thu Jan 01 00:00:00 1970 +0000
1656 | | summary: add unrelated old foo
1656 | | summary: add unrelated old foo
1657 | |
1657 | |
1658 o | changeset: 1:e5faa7440653
1658 o | changeset: 1:e5faa7440653
1659 |/ user: test
1659 |/ user: test
1660 | date: Thu Jan 01 00:00:00 1970 +0000
1660 | date: Thu Jan 01 00:00:00 1970 +0000
1661 | summary: change, unrelated
1661 | summary: change, unrelated
1662 |
1662 |
1663 o changeset: 0:e87515fd044a
1663 o changeset: 0:e87515fd044a
1664 user: test
1664 user: test
1665 date: Thu Jan 01 00:00:00 1970 +0000
1665 date: Thu Jan 01 00:00:00 1970 +0000
1666 summary: init, unrelated
1666 summary: init, unrelated
1667
1667
1668
1668
1669 $ hg --traceback log -f foo
1669 $ hg --traceback log -f foo
1670 changeset: 10:4dae8563d2c5
1670 changeset: 10:4dae8563d2c5
1671 tag: tip
1671 tag: tip
1672 parent: 9:7b35701b003e
1672 parent: 9:7b35701b003e
1673 parent: 4:88176d361b69
1673 parent: 4:88176d361b69
1674 user: test
1674 user: test
1675 date: Thu Jan 01 00:00:00 1970 +0000
1675 date: Thu Jan 01 00:00:00 1970 +0000
1676 summary: Last merge, related
1676 summary: Last merge, related
1677
1677
1678 changeset: 9:7b35701b003e
1678 changeset: 9:7b35701b003e
1679 parent: 8:e5416ad8a855
1679 parent: 8:e5416ad8a855
1680 parent: 7:87fe3144dcfa
1680 parent: 7:87fe3144dcfa
1681 user: test
1681 user: test
1682 date: Thu Jan 01 00:00:00 1970 +0000
1682 date: Thu Jan 01 00:00:00 1970 +0000
1683 summary: First merge, related
1683 summary: First merge, related
1684
1684
1685 changeset: 8:e5416ad8a855
1685 changeset: 8:e5416ad8a855
1686 parent: 6:dc6c325fe5ee
1686 parent: 6:dc6c325fe5ee
1687 user: test
1687 user: test
1688 date: Thu Jan 01 00:00:00 1970 +0000
1688 date: Thu Jan 01 00:00:00 1970 +0000
1689 summary: change foo in branch, related
1689 summary: change foo in branch, related
1690
1690
1691 changeset: 7:87fe3144dcfa
1691 changeset: 7:87fe3144dcfa
1692 user: test
1692 user: test
1693 date: Thu Jan 01 00:00:00 1970 +0000
1693 date: Thu Jan 01 00:00:00 1970 +0000
1694 summary: change foo, related
1694 summary: change foo, related
1695
1695
1696 changeset: 6:dc6c325fe5ee
1696 changeset: 6:dc6c325fe5ee
1697 user: test
1697 user: test
1698 date: Thu Jan 01 00:00:00 1970 +0000
1698 date: Thu Jan 01 00:00:00 1970 +0000
1699 summary: create foo, related
1699 summary: create foo, related
1700
1700
1701 changeset: 4:88176d361b69
1701 changeset: 4:88176d361b69
1702 user: test
1702 user: test
1703 date: Thu Jan 01 00:00:00 1970 +0000
1703 date: Thu Jan 01 00:00:00 1970 +0000
1704 summary: add foo, related
1704 summary: add foo, related
1705
1705
1706
1706
1707 Also check when maxrev < lastrevfilelog
1707 Also check when maxrev < lastrevfilelog
1708
1708
1709 $ hg --traceback log -f -r4 foo
1709 $ hg --traceback log -f -r4 foo
1710 changeset: 4:88176d361b69
1710 changeset: 4:88176d361b69
1711 user: test
1711 user: test
1712 date: Thu Jan 01 00:00:00 1970 +0000
1712 date: Thu Jan 01 00:00:00 1970 +0000
1713 summary: add foo, related
1713 summary: add foo, related
1714
1714
1715 changeset: 2:c4c64aedf0f7
1715 changeset: 2:c4c64aedf0f7
1716 user: test
1716 user: test
1717 date: Thu Jan 01 00:00:00 1970 +0000
1717 date: Thu Jan 01 00:00:00 1970 +0000
1718 summary: add unrelated old foo
1718 summary: add unrelated old foo
1719
1719
1720 $ cd ..
1720 $ cd ..
1721
1721
1722 Issue2383: hg log showing _less_ differences than hg diff
1722 Issue2383: hg log showing _less_ differences than hg diff
1723
1723
1724 $ hg init issue2383
1724 $ hg init issue2383
1725 $ cd issue2383
1725 $ cd issue2383
1726
1726
1727 Create a test repo:
1727 Create a test repo:
1728
1728
1729 $ echo a > a
1729 $ echo a > a
1730 $ hg ci -Am0
1730 $ hg ci -Am0
1731 adding a
1731 adding a
1732 $ echo b > b
1732 $ echo b > b
1733 $ hg ci -Am1
1733 $ hg ci -Am1
1734 adding b
1734 adding b
1735 $ hg co 0
1735 $ hg co 0
1736 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1736 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1737 $ echo b > a
1737 $ echo b > a
1738 $ hg ci -m2
1738 $ hg ci -m2
1739 created new head
1739 created new head
1740
1740
1741 Merge:
1741 Merge:
1742
1742
1743 $ hg merge
1743 $ hg merge
1744 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1744 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1745 (branch merge, don't forget to commit)
1745 (branch merge, don't forget to commit)
1746
1746
1747 Make sure there's a file listed in the merge to trigger the bug:
1747 Make sure there's a file listed in the merge to trigger the bug:
1748
1748
1749 $ echo c > a
1749 $ echo c > a
1750 $ hg ci -m3
1750 $ hg ci -m3
1751
1751
1752 Two files shown here in diff:
1752 Two files shown here in diff:
1753
1753
1754 $ hg diff --rev 2:3
1754 $ hg diff --rev 2:3
1755 diff -r b09be438c43a -r 8e07aafe1edc a
1755 diff -r b09be438c43a -r 8e07aafe1edc a
1756 --- a/a Thu Jan 01 00:00:00 1970 +0000
1756 --- a/a Thu Jan 01 00:00:00 1970 +0000
1757 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1757 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1758 @@ -1,1 +1,1 @@
1758 @@ -1,1 +1,1 @@
1759 -b
1759 -b
1760 +c
1760 +c
1761 diff -r b09be438c43a -r 8e07aafe1edc b
1761 diff -r b09be438c43a -r 8e07aafe1edc b
1762 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1762 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1763 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1763 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1764 @@ -0,0 +1,1 @@
1764 @@ -0,0 +1,1 @@
1765 +b
1765 +b
1766
1766
1767 Diff here should be the same:
1767 Diff here should be the same:
1768
1768
1769 $ hg log -vpr 3
1769 $ hg log -vpr 3
1770 changeset: 3:8e07aafe1edc
1770 changeset: 3:8e07aafe1edc
1771 tag: tip
1771 tag: tip
1772 parent: 2:b09be438c43a
1772 parent: 2:b09be438c43a
1773 parent: 1:925d80f479bb
1773 parent: 1:925d80f479bb
1774 user: test
1774 user: test
1775 date: Thu Jan 01 00:00:00 1970 +0000
1775 date: Thu Jan 01 00:00:00 1970 +0000
1776 files: a
1776 files: a
1777 description:
1777 description:
1778 3
1778 3
1779
1779
1780
1780
1781 diff -r b09be438c43a -r 8e07aafe1edc a
1781 diff -r b09be438c43a -r 8e07aafe1edc a
1782 --- a/a Thu Jan 01 00:00:00 1970 +0000
1782 --- a/a Thu Jan 01 00:00:00 1970 +0000
1783 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1783 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1784 @@ -1,1 +1,1 @@
1784 @@ -1,1 +1,1 @@
1785 -b
1785 -b
1786 +c
1786 +c
1787 diff -r b09be438c43a -r 8e07aafe1edc b
1787 diff -r b09be438c43a -r 8e07aafe1edc b
1788 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1788 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1789 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1789 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1790 @@ -0,0 +1,1 @@
1790 @@ -0,0 +1,1 @@
1791 +b
1791 +b
1792
1792
1793 $ cd ..
1793 $ cd ..
1794
1794
1795 'hg log -r rev fn' when last(filelog(fn)) != rev
1795 'hg log -r rev fn' when last(filelog(fn)) != rev
1796
1796
1797 $ hg init simplelog
1797 $ hg init simplelog
1798 $ cd simplelog
1798 $ cd simplelog
1799 $ echo f > a
1799 $ echo f > a
1800 $ hg ci -Am'a' -d '0 0'
1800 $ hg ci -Am'a' -d '0 0'
1801 adding a
1801 adding a
1802 $ echo f >> a
1802 $ echo f >> a
1803 $ hg ci -Am'a bis' -d '1 0'
1803 $ hg ci -Am'a bis' -d '1 0'
1804
1804
1805 $ hg log -r0 a
1805 $ hg log -r0 a
1806 changeset: 0:9f758d63dcde
1806 changeset: 0:9f758d63dcde
1807 user: test
1807 user: test
1808 date: Thu Jan 01 00:00:00 1970 +0000
1808 date: Thu Jan 01 00:00:00 1970 +0000
1809 summary: a
1809 summary: a
1810
1810
1811 enable obsolete to test hidden feature
1811 enable obsolete to test hidden feature
1812
1812
1813 $ cat >> $HGRCPATH << EOF
1813 $ cat >> $HGRCPATH << EOF
1814 > [experimental]
1814 > [experimental]
1815 > evolution.createmarkers=True
1815 > evolution.createmarkers=True
1816 > EOF
1816 > EOF
1817
1817
1818 $ hg log --template='{rev}:{node}\n'
1818 $ hg log --template='{rev}:{node}\n'
1819 1:a765632148dc55d38c35c4f247c618701886cb2f
1819 1:a765632148dc55d38c35c4f247c618701886cb2f
1820 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1820 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1821 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1821 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1822 obsoleted 1 changesets
1822 obsoleted 1 changesets
1823 $ hg up null -q
1823 $ hg up null -q
1824 $ hg log --template='{rev}:{node}\n'
1824 $ hg log --template='{rev}:{node}\n'
1825 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1825 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1826 $ hg log --template='{rev}:{node}\n' --hidden
1826 $ hg log --template='{rev}:{node}\n' --hidden
1827 1:a765632148dc55d38c35c4f247c618701886cb2f
1827 1:a765632148dc55d38c35c4f247c618701886cb2f
1828 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1828 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1829 $ hg log -r a
1829 $ hg log -r a
1830 abort: hidden revision 'a'!
1830 abort: hidden revision 'a' is pruned!
1831 (use --hidden to access hidden revisions)
1831 (use --hidden to access hidden revisions)
1832 [255]
1832 [255]
1833
1833
1834 test that parent prevent a changeset to be hidden
1834 test that parent prevent a changeset to be hidden
1835
1835
1836 $ hg up 1 -q --hidden
1836 $ hg up 1 -q --hidden
1837 updating to a hidden changeset a765632148dc
1837 updating to a hidden changeset a765632148dc
1838 $ hg log --template='{rev}:{node}\n'
1838 $ hg log --template='{rev}:{node}\n'
1839 1:a765632148dc55d38c35c4f247c618701886cb2f
1839 1:a765632148dc55d38c35c4f247c618701886cb2f
1840 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1840 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1841
1841
1842 test that second parent prevent a changeset to be hidden too
1842 test that second parent prevent a changeset to be hidden too
1843
1843
1844 $ hg debugsetparents 0 1 # nothing suitable to merge here
1844 $ hg debugsetparents 0 1 # nothing suitable to merge here
1845 $ hg log --template='{rev}:{node}\n'
1845 $ hg log --template='{rev}:{node}\n'
1846 1:a765632148dc55d38c35c4f247c618701886cb2f
1846 1:a765632148dc55d38c35c4f247c618701886cb2f
1847 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1847 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1848 $ hg debugsetparents 1
1848 $ hg debugsetparents 1
1849 $ hg up -q null
1849 $ hg up -q null
1850
1850
1851 bookmarks prevent a changeset being hidden
1851 bookmarks prevent a changeset being hidden
1852
1852
1853 $ hg bookmark --hidden -r 1 X
1853 $ hg bookmark --hidden -r 1 X
1854 $ hg log --template '{rev}:{node}\n'
1854 $ hg log --template '{rev}:{node}\n'
1855 1:a765632148dc55d38c35c4f247c618701886cb2f
1855 1:a765632148dc55d38c35c4f247c618701886cb2f
1856 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1856 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1857 $ hg bookmark -d X
1857 $ hg bookmark -d X
1858
1858
1859 divergent bookmarks are not hidden
1859 divergent bookmarks are not hidden
1860
1860
1861 $ hg bookmark --hidden -r 1 X@foo
1861 $ hg bookmark --hidden -r 1 X@foo
1862 $ hg log --template '{rev}:{node}\n'
1862 $ hg log --template '{rev}:{node}\n'
1863 1:a765632148dc55d38c35c4f247c618701886cb2f
1863 1:a765632148dc55d38c35c4f247c618701886cb2f
1864 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1864 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1865
1865
1866 test hidden revision 0 (issue5385)
1866 test hidden revision 0 (issue5385)
1867
1867
1868 $ hg bookmark -d X@foo
1868 $ hg bookmark -d X@foo
1869 $ hg up null -q
1869 $ hg up null -q
1870 $ hg debugobsolete 9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1870 $ hg debugobsolete 9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1871 obsoleted 1 changesets
1871 obsoleted 1 changesets
1872 $ echo f > b
1872 $ echo f > b
1873 $ hg ci -Am'b' -d '2 0'
1873 $ hg ci -Am'b' -d '2 0'
1874 adding b
1874 adding b
1875 $ echo f >> b
1875 $ echo f >> b
1876 $ hg ci -m'b bis' -d '3 0'
1876 $ hg ci -m'b bis' -d '3 0'
1877 $ hg log -T'{rev}:{node}\n'
1877 $ hg log -T'{rev}:{node}\n'
1878 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1878 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1879 2:94375ec45bddd2a824535fc04855bd058c926ec0
1879 2:94375ec45bddd2a824535fc04855bd058c926ec0
1880
1880
1881 $ hg log -T'{rev}:{node}\n' -r:
1881 $ hg log -T'{rev}:{node}\n' -r:
1882 2:94375ec45bddd2a824535fc04855bd058c926ec0
1882 2:94375ec45bddd2a824535fc04855bd058c926ec0
1883 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1883 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1884 $ hg log -T'{rev}:{node}\n' -r:tip
1884 $ hg log -T'{rev}:{node}\n' -r:tip
1885 2:94375ec45bddd2a824535fc04855bd058c926ec0
1885 2:94375ec45bddd2a824535fc04855bd058c926ec0
1886 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1886 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1887 $ hg log -T'{rev}:{node}\n' -r:0
1887 $ hg log -T'{rev}:{node}\n' -r:0
1888 abort: hidden revision '0'!
1888 abort: hidden revision '0' is pruned!
1889 (use --hidden to access hidden revisions)
1889 (use --hidden to access hidden revisions)
1890 [255]
1890 [255]
1891 $ hg log -T'{rev}:{node}\n' -f
1891 $ hg log -T'{rev}:{node}\n' -f
1892 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1892 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
1893 2:94375ec45bddd2a824535fc04855bd058c926ec0
1893 2:94375ec45bddd2a824535fc04855bd058c926ec0
1894
1894
1895 clear extensions configuration
1895 clear extensions configuration
1896 $ echo '[extensions]' >> $HGRCPATH
1896 $ echo '[extensions]' >> $HGRCPATH
1897 $ echo "obs=!" >> $HGRCPATH
1897 $ echo "obs=!" >> $HGRCPATH
1898 $ cd ..
1898 $ cd ..
1899
1899
1900 test -u/-k for problematic encoding
1900 test -u/-k for problematic encoding
1901 # unicode: cp932:
1901 # unicode: cp932:
1902 # u30A2 0x83 0x41(= 'A')
1902 # u30A2 0x83 0x41(= 'A')
1903 # u30C2 0x83 0x61(= 'a')
1903 # u30C2 0x83 0x61(= 'a')
1904
1904
1905 $ hg init problematicencoding
1905 $ hg init problematicencoding
1906 $ cd problematicencoding
1906 $ cd problematicencoding
1907
1907
1908 $ $PYTHON > setup.sh <<EOF
1908 $ $PYTHON > setup.sh <<EOF
1909 > print(u'''
1909 > print(u'''
1910 > echo a > text
1910 > echo a > text
1911 > hg add text
1911 > hg add text
1912 > hg --encoding utf-8 commit -u '\u30A2' -m none
1912 > hg --encoding utf-8 commit -u '\u30A2' -m none
1913 > echo b > text
1913 > echo b > text
1914 > hg --encoding utf-8 commit -u '\u30C2' -m none
1914 > hg --encoding utf-8 commit -u '\u30C2' -m none
1915 > echo c > text
1915 > echo c > text
1916 > hg --encoding utf-8 commit -u none -m '\u30A2'
1916 > hg --encoding utf-8 commit -u none -m '\u30A2'
1917 > echo d > text
1917 > echo d > text
1918 > hg --encoding utf-8 commit -u none -m '\u30C2'
1918 > hg --encoding utf-8 commit -u none -m '\u30C2'
1919 > '''.encode('utf-8'))
1919 > '''.encode('utf-8'))
1920 > EOF
1920 > EOF
1921 $ sh < setup.sh
1921 $ sh < setup.sh
1922
1922
1923 test in problematic encoding
1923 test in problematic encoding
1924 $ $PYTHON > test.sh <<EOF
1924 $ $PYTHON > test.sh <<EOF
1925 > print(u'''
1925 > print(u'''
1926 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1926 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1927 > echo ====
1927 > echo ====
1928 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1928 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1929 > echo ====
1929 > echo ====
1930 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1930 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1931 > echo ====
1931 > echo ====
1932 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1932 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1933 > '''.encode('cp932'))
1933 > '''.encode('cp932'))
1934 > EOF
1934 > EOF
1935 $ sh < test.sh
1935 $ sh < test.sh
1936 0
1936 0
1937 ====
1937 ====
1938 1
1938 1
1939 ====
1939 ====
1940 2
1940 2
1941 0
1941 0
1942 ====
1942 ====
1943 3
1943 3
1944 1
1944 1
1945
1945
1946 $ cd ..
1946 $ cd ..
1947
1947
1948 test hg log on non-existent files and on directories
1948 test hg log on non-existent files and on directories
1949 $ hg init issue1340
1949 $ hg init issue1340
1950 $ cd issue1340
1950 $ cd issue1340
1951 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1951 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1952 $ echo 1 > d1/f1
1952 $ echo 1 > d1/f1
1953 $ echo 1 > D2/f1
1953 $ echo 1 > D2/f1
1954 $ echo 1 > D3.i/f1
1954 $ echo 1 > D3.i/f1
1955 $ echo 1 > d4.hg/f1
1955 $ echo 1 > d4.hg/f1
1956 $ echo 1 > d5.d/f1
1956 $ echo 1 > d5.d/f1
1957 $ echo 1 > .d6/f1
1957 $ echo 1 > .d6/f1
1958 $ hg -q add .
1958 $ hg -q add .
1959 $ hg commit -m "a bunch of weird directories"
1959 $ hg commit -m "a bunch of weird directories"
1960 $ hg log -l1 d1/f1 | grep changeset
1960 $ hg log -l1 d1/f1 | grep changeset
1961 changeset: 0:65624cd9070a
1961 changeset: 0:65624cd9070a
1962 $ hg log -l1 f1
1962 $ hg log -l1 f1
1963 $ hg log -l1 . | grep changeset
1963 $ hg log -l1 . | grep changeset
1964 changeset: 0:65624cd9070a
1964 changeset: 0:65624cd9070a
1965 $ hg log -l1 ./ | grep changeset
1965 $ hg log -l1 ./ | grep changeset
1966 changeset: 0:65624cd9070a
1966 changeset: 0:65624cd9070a
1967 $ hg log -l1 d1 | grep changeset
1967 $ hg log -l1 d1 | grep changeset
1968 changeset: 0:65624cd9070a
1968 changeset: 0:65624cd9070a
1969 $ hg log -l1 D2 | grep changeset
1969 $ hg log -l1 D2 | grep changeset
1970 changeset: 0:65624cd9070a
1970 changeset: 0:65624cd9070a
1971 $ hg log -l1 D2/f1 | grep changeset
1971 $ hg log -l1 D2/f1 | grep changeset
1972 changeset: 0:65624cd9070a
1972 changeset: 0:65624cd9070a
1973 $ hg log -l1 D3.i | grep changeset
1973 $ hg log -l1 D3.i | grep changeset
1974 changeset: 0:65624cd9070a
1974 changeset: 0:65624cd9070a
1975 $ hg log -l1 D3.i/f1 | grep changeset
1975 $ hg log -l1 D3.i/f1 | grep changeset
1976 changeset: 0:65624cd9070a
1976 changeset: 0:65624cd9070a
1977 $ hg log -l1 d4.hg | grep changeset
1977 $ hg log -l1 d4.hg | grep changeset
1978 changeset: 0:65624cd9070a
1978 changeset: 0:65624cd9070a
1979 $ hg log -l1 d4.hg/f1 | grep changeset
1979 $ hg log -l1 d4.hg/f1 | grep changeset
1980 changeset: 0:65624cd9070a
1980 changeset: 0:65624cd9070a
1981 $ hg log -l1 d5.d | grep changeset
1981 $ hg log -l1 d5.d | grep changeset
1982 changeset: 0:65624cd9070a
1982 changeset: 0:65624cd9070a
1983 $ hg log -l1 d5.d/f1 | grep changeset
1983 $ hg log -l1 d5.d/f1 | grep changeset
1984 changeset: 0:65624cd9070a
1984 changeset: 0:65624cd9070a
1985 $ hg log -l1 .d6 | grep changeset
1985 $ hg log -l1 .d6 | grep changeset
1986 changeset: 0:65624cd9070a
1986 changeset: 0:65624cd9070a
1987 $ hg log -l1 .d6/f1 | grep changeset
1987 $ hg log -l1 .d6/f1 | grep changeset
1988 changeset: 0:65624cd9070a
1988 changeset: 0:65624cd9070a
1989
1989
1990 issue3772: hg log -r :null showing revision 0 as well
1990 issue3772: hg log -r :null showing revision 0 as well
1991
1991
1992 $ hg log -r :null
1992 $ hg log -r :null
1993 changeset: 0:65624cd9070a
1993 changeset: 0:65624cd9070a
1994 tag: tip
1994 tag: tip
1995 user: test
1995 user: test
1996 date: Thu Jan 01 00:00:00 1970 +0000
1996 date: Thu Jan 01 00:00:00 1970 +0000
1997 summary: a bunch of weird directories
1997 summary: a bunch of weird directories
1998
1998
1999 changeset: -1:000000000000
1999 changeset: -1:000000000000
2000 user:
2000 user:
2001 date: Thu Jan 01 00:00:00 1970 +0000
2001 date: Thu Jan 01 00:00:00 1970 +0000
2002
2002
2003 $ hg log -r null:null
2003 $ hg log -r null:null
2004 changeset: -1:000000000000
2004 changeset: -1:000000000000
2005 user:
2005 user:
2006 date: Thu Jan 01 00:00:00 1970 +0000
2006 date: Thu Jan 01 00:00:00 1970 +0000
2007
2007
2008 working-directory revision requires special treatment
2008 working-directory revision requires special treatment
2009
2009
2010 clean:
2010 clean:
2011
2011
2012 $ hg log -r 'wdir()' --debug
2012 $ hg log -r 'wdir()' --debug
2013 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2013 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2014 phase: draft
2014 phase: draft
2015 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2015 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2016 parent: -1:0000000000000000000000000000000000000000
2016 parent: -1:0000000000000000000000000000000000000000
2017 user: test
2017 user: test
2018 date: [A-Za-z0-9:+ ]+ (re)
2018 date: [A-Za-z0-9:+ ]+ (re)
2019 extra: branch=default
2019 extra: branch=default
2020
2020
2021 $ hg log -r 'wdir()' -p --stat
2021 $ hg log -r 'wdir()' -p --stat
2022 changeset: 2147483647:ffffffffffff
2022 changeset: 2147483647:ffffffffffff
2023 parent: 0:65624cd9070a
2023 parent: 0:65624cd9070a
2024 user: test
2024 user: test
2025 date: [A-Za-z0-9:+ ]+ (re)
2025 date: [A-Za-z0-9:+ ]+ (re)
2026
2026
2027
2027
2028
2028
2029
2029
2030 dirty:
2030 dirty:
2031
2031
2032 $ echo 2 >> d1/f1
2032 $ echo 2 >> d1/f1
2033 $ echo 2 > d1/f2
2033 $ echo 2 > d1/f2
2034 $ hg add d1/f2
2034 $ hg add d1/f2
2035 $ hg remove .d6/f1
2035 $ hg remove .d6/f1
2036 $ hg status
2036 $ hg status
2037 M d1/f1
2037 M d1/f1
2038 A d1/f2
2038 A d1/f2
2039 R .d6/f1
2039 R .d6/f1
2040
2040
2041 $ hg log -r 'wdir()'
2041 $ hg log -r 'wdir()'
2042 changeset: 2147483647:ffffffffffff
2042 changeset: 2147483647:ffffffffffff
2043 parent: 0:65624cd9070a
2043 parent: 0:65624cd9070a
2044 user: test
2044 user: test
2045 date: [A-Za-z0-9:+ ]+ (re)
2045 date: [A-Za-z0-9:+ ]+ (re)
2046
2046
2047 $ hg log -r 'wdir()' -q
2047 $ hg log -r 'wdir()' -q
2048 2147483647:ffffffffffff
2048 2147483647:ffffffffffff
2049
2049
2050 $ hg log -r 'wdir()' --debug
2050 $ hg log -r 'wdir()' --debug
2051 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2051 changeset: 2147483647:ffffffffffffffffffffffffffffffffffffffff
2052 phase: draft
2052 phase: draft
2053 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2053 parent: 0:65624cd9070a035fa7191a54f2b8af39f16b0c08
2054 parent: -1:0000000000000000000000000000000000000000
2054 parent: -1:0000000000000000000000000000000000000000
2055 user: test
2055 user: test
2056 date: [A-Za-z0-9:+ ]+ (re)
2056 date: [A-Za-z0-9:+ ]+ (re)
2057 files: d1/f1
2057 files: d1/f1
2058 files+: d1/f2
2058 files+: d1/f2
2059 files-: .d6/f1
2059 files-: .d6/f1
2060 extra: branch=default
2060 extra: branch=default
2061
2061
2062 $ hg log -r 'wdir()' -p --stat --git
2062 $ hg log -r 'wdir()' -p --stat --git
2063 changeset: 2147483647:ffffffffffff
2063 changeset: 2147483647:ffffffffffff
2064 parent: 0:65624cd9070a
2064 parent: 0:65624cd9070a
2065 user: test
2065 user: test
2066 date: [A-Za-z0-9:+ ]+ (re)
2066 date: [A-Za-z0-9:+ ]+ (re)
2067
2067
2068 .d6/f1 | 1 -
2068 .d6/f1 | 1 -
2069 d1/f1 | 1 +
2069 d1/f1 | 1 +
2070 d1/f2 | 1 +
2070 d1/f2 | 1 +
2071 3 files changed, 2 insertions(+), 1 deletions(-)
2071 3 files changed, 2 insertions(+), 1 deletions(-)
2072
2072
2073 diff --git a/.d6/f1 b/.d6/f1
2073 diff --git a/.d6/f1 b/.d6/f1
2074 deleted file mode 100644
2074 deleted file mode 100644
2075 --- a/.d6/f1
2075 --- a/.d6/f1
2076 +++ /dev/null
2076 +++ /dev/null
2077 @@ -1,1 +0,0 @@
2077 @@ -1,1 +0,0 @@
2078 -1
2078 -1
2079 diff --git a/d1/f1 b/d1/f1
2079 diff --git a/d1/f1 b/d1/f1
2080 --- a/d1/f1
2080 --- a/d1/f1
2081 +++ b/d1/f1
2081 +++ b/d1/f1
2082 @@ -1,1 +1,2 @@
2082 @@ -1,1 +1,2 @@
2083 1
2083 1
2084 +2
2084 +2
2085 diff --git a/d1/f2 b/d1/f2
2085 diff --git a/d1/f2 b/d1/f2
2086 new file mode 100644
2086 new file mode 100644
2087 --- /dev/null
2087 --- /dev/null
2088 +++ b/d1/f2
2088 +++ b/d1/f2
2089 @@ -0,0 +1,1 @@
2089 @@ -0,0 +1,1 @@
2090 +2
2090 +2
2091
2091
2092 $ hg log -r 'wdir()' -Tjson
2092 $ hg log -r 'wdir()' -Tjson
2093 [
2093 [
2094 {
2094 {
2095 "rev": null,
2095 "rev": null,
2096 "node": null,
2096 "node": null,
2097 "branch": "default",
2097 "branch": "default",
2098 "phase": "draft",
2098 "phase": "draft",
2099 "user": "test",
2099 "user": "test",
2100 "date": [*, 0], (glob)
2100 "date": [*, 0], (glob)
2101 "desc": "",
2101 "desc": "",
2102 "bookmarks": [],
2102 "bookmarks": [],
2103 "tags": [],
2103 "tags": [],
2104 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"]
2104 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"]
2105 }
2105 }
2106 ]
2106 ]
2107
2107
2108 $ hg log -r 'wdir()' -Tjson -q
2108 $ hg log -r 'wdir()' -Tjson -q
2109 [
2109 [
2110 {
2110 {
2111 "rev": null,
2111 "rev": null,
2112 "node": null
2112 "node": null
2113 }
2113 }
2114 ]
2114 ]
2115
2115
2116 $ hg log -r 'wdir()' -Tjson --debug
2116 $ hg log -r 'wdir()' -Tjson --debug
2117 [
2117 [
2118 {
2118 {
2119 "rev": null,
2119 "rev": null,
2120 "node": null,
2120 "node": null,
2121 "branch": "default",
2121 "branch": "default",
2122 "phase": "draft",
2122 "phase": "draft",
2123 "user": "test",
2123 "user": "test",
2124 "date": [*, 0], (glob)
2124 "date": [*, 0], (glob)
2125 "desc": "",
2125 "desc": "",
2126 "bookmarks": [],
2126 "bookmarks": [],
2127 "tags": [],
2127 "tags": [],
2128 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2128 "parents": ["65624cd9070a035fa7191a54f2b8af39f16b0c08"],
2129 "manifest": null,
2129 "manifest": null,
2130 "extra": {"branch": "default"},
2130 "extra": {"branch": "default"},
2131 "modified": ["d1/f1"],
2131 "modified": ["d1/f1"],
2132 "added": ["d1/f2"],
2132 "added": ["d1/f2"],
2133 "removed": [".d6/f1"]
2133 "removed": [".d6/f1"]
2134 }
2134 }
2135 ]
2135 ]
2136
2136
2137 $ hg revert -aqC
2137 $ hg revert -aqC
2138
2138
2139 Check that adding an arbitrary name shows up in log automatically
2139 Check that adding an arbitrary name shows up in log automatically
2140
2140
2141 $ cat > ../names.py <<EOF
2141 $ cat > ../names.py <<EOF
2142 > """A small extension to test adding arbitrary names to a repo"""
2142 > """A small extension to test adding arbitrary names to a repo"""
2143 > from __future__ import absolute_import
2143 > from __future__ import absolute_import
2144 > from mercurial import namespaces
2144 > from mercurial import namespaces
2145 >
2145 >
2146 > def reposetup(ui, repo):
2146 > def reposetup(ui, repo):
2147 > foo = {'foo': repo[0].node()}
2147 > foo = {'foo': repo[0].node()}
2148 > names = lambda r: foo.keys()
2148 > names = lambda r: foo.keys()
2149 > namemap = lambda r, name: foo.get(name)
2149 > namemap = lambda r, name: foo.get(name)
2150 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
2150 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
2151 > if n == node]
2151 > if n == node]
2152 > ns = namespaces.namespace(
2152 > ns = namespaces.namespace(
2153 > "bars", templatename="bar", logname="barlog",
2153 > "bars", templatename="bar", logname="barlog",
2154 > colorname="barcolor", listnames=names, namemap=namemap,
2154 > colorname="barcolor", listnames=names, namemap=namemap,
2155 > nodemap=nodemap)
2155 > nodemap=nodemap)
2156 >
2156 >
2157 > repo.names.addnamespace(ns)
2157 > repo.names.addnamespace(ns)
2158 > EOF
2158 > EOF
2159
2159
2160 $ hg --config extensions.names=../names.py log -r 0
2160 $ hg --config extensions.names=../names.py log -r 0
2161 changeset: 0:65624cd9070a
2161 changeset: 0:65624cd9070a
2162 tag: tip
2162 tag: tip
2163 barlog: foo
2163 barlog: foo
2164 user: test
2164 user: test
2165 date: Thu Jan 01 00:00:00 1970 +0000
2165 date: Thu Jan 01 00:00:00 1970 +0000
2166 summary: a bunch of weird directories
2166 summary: a bunch of weird directories
2167
2167
2168 $ hg --config extensions.names=../names.py \
2168 $ hg --config extensions.names=../names.py \
2169 > --config extensions.color= --config color.log.barcolor=red \
2169 > --config extensions.color= --config color.log.barcolor=red \
2170 > --color=always log -r 0
2170 > --color=always log -r 0
2171 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
2171 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
2172 tag: tip
2172 tag: tip
2173 \x1b[0;31mbarlog: foo\x1b[0m (esc)
2173 \x1b[0;31mbarlog: foo\x1b[0m (esc)
2174 user: test
2174 user: test
2175 date: Thu Jan 01 00:00:00 1970 +0000
2175 date: Thu Jan 01 00:00:00 1970 +0000
2176 summary: a bunch of weird directories
2176 summary: a bunch of weird directories
2177
2177
2178 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2178 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2179 foo
2179 foo
2180
2180
2181 $ cd ..
2181 $ cd ..
2182
2182
2183 hg log -f dir across branches
2183 hg log -f dir across branches
2184
2184
2185 $ hg init acrossbranches
2185 $ hg init acrossbranches
2186 $ cd acrossbranches
2186 $ cd acrossbranches
2187 $ mkdir d
2187 $ mkdir d
2188 $ echo a > d/a && hg ci -Aqm a
2188 $ echo a > d/a && hg ci -Aqm a
2189 $ echo b > d/a && hg ci -Aqm b
2189 $ echo b > d/a && hg ci -Aqm b
2190 $ hg up -q 0
2190 $ hg up -q 0
2191 $ echo b > d/a && hg ci -Aqm c
2191 $ echo b > d/a && hg ci -Aqm c
2192 $ hg log -f d -T '{desc}' -G
2192 $ hg log -f d -T '{desc}' -G
2193 @ c
2193 @ c
2194 |
2194 |
2195 o a
2195 o a
2196
2196
2197 Ensure that largefiles doesn't interfere with following a normal file
2197 Ensure that largefiles doesn't interfere with following a normal file
2198 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
2198 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
2199 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
2199 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
2200 @ c
2200 @ c
2201 |
2201 |
2202 o a
2202 o a
2203
2203
2204 $ hg log -f d/a -T '{desc}' -G
2204 $ hg log -f d/a -T '{desc}' -G
2205 @ c
2205 @ c
2206 |
2206 |
2207 o a
2207 o a
2208
2208
2209 $ cd ..
2209 $ cd ..
2210
2210
2211 hg log -f with linkrev pointing to another branch
2211 hg log -f with linkrev pointing to another branch
2212 -------------------------------------------------
2212 -------------------------------------------------
2213
2213
2214 create history with a filerev whose linkrev points to another branch
2214 create history with a filerev whose linkrev points to another branch
2215
2215
2216 $ hg init branchedlinkrev
2216 $ hg init branchedlinkrev
2217 $ cd branchedlinkrev
2217 $ cd branchedlinkrev
2218 $ echo 1 > a
2218 $ echo 1 > a
2219 $ hg commit -Am 'content1'
2219 $ hg commit -Am 'content1'
2220 adding a
2220 adding a
2221 $ echo 2 > a
2221 $ echo 2 > a
2222 $ hg commit -m 'content2'
2222 $ hg commit -m 'content2'
2223 $ hg up --rev 'desc(content1)'
2223 $ hg up --rev 'desc(content1)'
2224 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2224 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2225 $ echo unrelated > unrelated
2225 $ echo unrelated > unrelated
2226 $ hg commit -Am 'unrelated'
2226 $ hg commit -Am 'unrelated'
2227 adding unrelated
2227 adding unrelated
2228 created new head
2228 created new head
2229 $ hg graft -r 'desc(content2)'
2229 $ hg graft -r 'desc(content2)'
2230 grafting 1:2294ae80ad84 "content2"
2230 grafting 1:2294ae80ad84 "content2"
2231 $ echo 3 > a
2231 $ echo 3 > a
2232 $ hg commit -m 'content3'
2232 $ hg commit -m 'content3'
2233 $ hg log -G
2233 $ hg log -G
2234 @ changeset: 4:50b9b36e9c5d
2234 @ changeset: 4:50b9b36e9c5d
2235 | tag: tip
2235 | tag: tip
2236 | user: test
2236 | user: test
2237 | date: Thu Jan 01 00:00:00 1970 +0000
2237 | date: Thu Jan 01 00:00:00 1970 +0000
2238 | summary: content3
2238 | summary: content3
2239 |
2239 |
2240 o changeset: 3:15b2327059e5
2240 o changeset: 3:15b2327059e5
2241 | user: test
2241 | user: test
2242 | date: Thu Jan 01 00:00:00 1970 +0000
2242 | date: Thu Jan 01 00:00:00 1970 +0000
2243 | summary: content2
2243 | summary: content2
2244 |
2244 |
2245 o changeset: 2:2029acd1168c
2245 o changeset: 2:2029acd1168c
2246 | parent: 0:ae0a3c9f9e95
2246 | parent: 0:ae0a3c9f9e95
2247 | user: test
2247 | user: test
2248 | date: Thu Jan 01 00:00:00 1970 +0000
2248 | date: Thu Jan 01 00:00:00 1970 +0000
2249 | summary: unrelated
2249 | summary: unrelated
2250 |
2250 |
2251 | o changeset: 1:2294ae80ad84
2251 | o changeset: 1:2294ae80ad84
2252 |/ user: test
2252 |/ user: test
2253 | date: Thu Jan 01 00:00:00 1970 +0000
2253 | date: Thu Jan 01 00:00:00 1970 +0000
2254 | summary: content2
2254 | summary: content2
2255 |
2255 |
2256 o changeset: 0:ae0a3c9f9e95
2256 o changeset: 0:ae0a3c9f9e95
2257 user: test
2257 user: test
2258 date: Thu Jan 01 00:00:00 1970 +0000
2258 date: Thu Jan 01 00:00:00 1970 +0000
2259 summary: content1
2259 summary: content1
2260
2260
2261
2261
2262 log -f on the file should list the graft result.
2262 log -f on the file should list the graft result.
2263
2263
2264 $ hg log -Gf a
2264 $ hg log -Gf a
2265 @ changeset: 4:50b9b36e9c5d
2265 @ changeset: 4:50b9b36e9c5d
2266 | tag: tip
2266 | tag: tip
2267 | user: test
2267 | user: test
2268 | date: Thu Jan 01 00:00:00 1970 +0000
2268 | date: Thu Jan 01 00:00:00 1970 +0000
2269 | summary: content3
2269 | summary: content3
2270 |
2270 |
2271 o changeset: 3:15b2327059e5
2271 o changeset: 3:15b2327059e5
2272 : user: test
2272 : user: test
2273 : date: Thu Jan 01 00:00:00 1970 +0000
2273 : date: Thu Jan 01 00:00:00 1970 +0000
2274 : summary: content2
2274 : summary: content2
2275 :
2275 :
2276 o changeset: 0:ae0a3c9f9e95
2276 o changeset: 0:ae0a3c9f9e95
2277 user: test
2277 user: test
2278 date: Thu Jan 01 00:00:00 1970 +0000
2278 date: Thu Jan 01 00:00:00 1970 +0000
2279 summary: content1
2279 summary: content1
2280
2280
2281
2281
2282 plain log lists the original version
2282 plain log lists the original version
2283 (XXX we should probably list both)
2283 (XXX we should probably list both)
2284
2284
2285 $ hg log -G a
2285 $ hg log -G a
2286 @ changeset: 4:50b9b36e9c5d
2286 @ changeset: 4:50b9b36e9c5d
2287 : tag: tip
2287 : tag: tip
2288 : user: test
2288 : user: test
2289 : date: Thu Jan 01 00:00:00 1970 +0000
2289 : date: Thu Jan 01 00:00:00 1970 +0000
2290 : summary: content3
2290 : summary: content3
2291 :
2291 :
2292 : o changeset: 1:2294ae80ad84
2292 : o changeset: 1:2294ae80ad84
2293 :/ user: test
2293 :/ user: test
2294 : date: Thu Jan 01 00:00:00 1970 +0000
2294 : date: Thu Jan 01 00:00:00 1970 +0000
2295 : summary: content2
2295 : summary: content2
2296 :
2296 :
2297 o changeset: 0:ae0a3c9f9e95
2297 o changeset: 0:ae0a3c9f9e95
2298 user: test
2298 user: test
2299 date: Thu Jan 01 00:00:00 1970 +0000
2299 date: Thu Jan 01 00:00:00 1970 +0000
2300 summary: content1
2300 summary: content1
2301
2301
2302
2302
2303 hg log -f from the grafted changeset
2303 hg log -f from the grafted changeset
2304 (The bootstrap should properly take the topology in account)
2304 (The bootstrap should properly take the topology in account)
2305
2305
2306 $ hg up 'desc(content3)^'
2306 $ hg up 'desc(content3)^'
2307 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2307 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2308 $ hg log -Gf a
2308 $ hg log -Gf a
2309 @ changeset: 3:15b2327059e5
2309 @ changeset: 3:15b2327059e5
2310 : user: test
2310 : user: test
2311 : date: Thu Jan 01 00:00:00 1970 +0000
2311 : date: Thu Jan 01 00:00:00 1970 +0000
2312 : summary: content2
2312 : summary: content2
2313 :
2313 :
2314 o changeset: 0:ae0a3c9f9e95
2314 o changeset: 0:ae0a3c9f9e95
2315 user: test
2315 user: test
2316 date: Thu Jan 01 00:00:00 1970 +0000
2316 date: Thu Jan 01 00:00:00 1970 +0000
2317 summary: content1
2317 summary: content1
2318
2318
2319
2319
2320 Test that we use the first non-hidden changeset in that case.
2320 Test that we use the first non-hidden changeset in that case.
2321
2321
2322 (hide the changeset)
2322 (hide the changeset)
2323
2323
2324 $ hg log -T '{node}\n' -r 1
2324 $ hg log -T '{node}\n' -r 1
2325 2294ae80ad8447bc78383182eeac50cb049df623
2325 2294ae80ad8447bc78383182eeac50cb049df623
2326 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
2326 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
2327 obsoleted 1 changesets
2327 obsoleted 1 changesets
2328 $ hg log -G
2328 $ hg log -G
2329 o changeset: 4:50b9b36e9c5d
2329 o changeset: 4:50b9b36e9c5d
2330 | tag: tip
2330 | tag: tip
2331 | user: test
2331 | user: test
2332 | date: Thu Jan 01 00:00:00 1970 +0000
2332 | date: Thu Jan 01 00:00:00 1970 +0000
2333 | summary: content3
2333 | summary: content3
2334 |
2334 |
2335 @ changeset: 3:15b2327059e5
2335 @ changeset: 3:15b2327059e5
2336 | user: test
2336 | user: test
2337 | date: Thu Jan 01 00:00:00 1970 +0000
2337 | date: Thu Jan 01 00:00:00 1970 +0000
2338 | summary: content2
2338 | summary: content2
2339 |
2339 |
2340 o changeset: 2:2029acd1168c
2340 o changeset: 2:2029acd1168c
2341 | parent: 0:ae0a3c9f9e95
2341 | parent: 0:ae0a3c9f9e95
2342 | user: test
2342 | user: test
2343 | date: Thu Jan 01 00:00:00 1970 +0000
2343 | date: Thu Jan 01 00:00:00 1970 +0000
2344 | summary: unrelated
2344 | summary: unrelated
2345 |
2345 |
2346 o changeset: 0:ae0a3c9f9e95
2346 o changeset: 0:ae0a3c9f9e95
2347 user: test
2347 user: test
2348 date: Thu Jan 01 00:00:00 1970 +0000
2348 date: Thu Jan 01 00:00:00 1970 +0000
2349 summary: content1
2349 summary: content1
2350
2350
2351
2351
2352 Check that log on the file does not drop the file revision.
2352 Check that log on the file does not drop the file revision.
2353
2353
2354 $ hg log -G a
2354 $ hg log -G a
2355 o changeset: 4:50b9b36e9c5d
2355 o changeset: 4:50b9b36e9c5d
2356 | tag: tip
2356 | tag: tip
2357 | user: test
2357 | user: test
2358 | date: Thu Jan 01 00:00:00 1970 +0000
2358 | date: Thu Jan 01 00:00:00 1970 +0000
2359 | summary: content3
2359 | summary: content3
2360 |
2360 |
2361 @ changeset: 3:15b2327059e5
2361 @ changeset: 3:15b2327059e5
2362 : user: test
2362 : user: test
2363 : date: Thu Jan 01 00:00:00 1970 +0000
2363 : date: Thu Jan 01 00:00:00 1970 +0000
2364 : summary: content2
2364 : summary: content2
2365 :
2365 :
2366 o changeset: 0:ae0a3c9f9e95
2366 o changeset: 0:ae0a3c9f9e95
2367 user: test
2367 user: test
2368 date: Thu Jan 01 00:00:00 1970 +0000
2368 date: Thu Jan 01 00:00:00 1970 +0000
2369 summary: content1
2369 summary: content1
2370
2370
2371
2371
2372 Even when a head revision is linkrev-shadowed.
2372 Even when a head revision is linkrev-shadowed.
2373
2373
2374 $ hg log -T '{node}\n' -r 4
2374 $ hg log -T '{node}\n' -r 4
2375 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2375 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2376 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2376 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
2377 obsoleted 1 changesets
2377 obsoleted 1 changesets
2378 $ hg log -G a
2378 $ hg log -G a
2379 @ changeset: 3:15b2327059e5
2379 @ changeset: 3:15b2327059e5
2380 : tag: tip
2380 : tag: tip
2381 : user: test
2381 : user: test
2382 : date: Thu Jan 01 00:00:00 1970 +0000
2382 : date: Thu Jan 01 00:00:00 1970 +0000
2383 : summary: content2
2383 : summary: content2
2384 :
2384 :
2385 o changeset: 0:ae0a3c9f9e95
2385 o changeset: 0:ae0a3c9f9e95
2386 user: test
2386 user: test
2387 date: Thu Jan 01 00:00:00 1970 +0000
2387 date: Thu Jan 01 00:00:00 1970 +0000
2388 summary: content1
2388 summary: content1
2389
2389
2390
2390
2391 $ cd ..
2391 $ cd ..
2392
2392
2393 Even when the file revision is missing from some head:
2393 Even when the file revision is missing from some head:
2394
2394
2395 $ hg init issue4490
2395 $ hg init issue4490
2396 $ cd issue4490
2396 $ cd issue4490
2397 $ echo '[experimental]' >> .hg/hgrc
2397 $ echo '[experimental]' >> .hg/hgrc
2398 $ echo 'evolution.createmarkers=True' >> .hg/hgrc
2398 $ echo 'evolution.createmarkers=True' >> .hg/hgrc
2399 $ echo a > a
2399 $ echo a > a
2400 $ hg ci -Am0
2400 $ hg ci -Am0
2401 adding a
2401 adding a
2402 $ echo b > b
2402 $ echo b > b
2403 $ hg ci -Am1
2403 $ hg ci -Am1
2404 adding b
2404 adding b
2405 $ echo B > b
2405 $ echo B > b
2406 $ hg ci --amend -m 1
2406 $ hg ci --amend -m 1
2407 $ hg up 0
2407 $ hg up 0
2408 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2408 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2409 $ echo c > c
2409 $ echo c > c
2410 $ hg ci -Am2
2410 $ hg ci -Am2
2411 adding c
2411 adding c
2412 created new head
2412 created new head
2413 $ hg up 'head() and not .'
2413 $ hg up 'head() and not .'
2414 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
2414 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
2415 $ hg log -G
2415 $ hg log -G
2416 o changeset: 3:db815d6d32e6
2416 o changeset: 3:db815d6d32e6
2417 | tag: tip
2417 | tag: tip
2418 | parent: 0:f7b1eb17ad24
2418 | parent: 0:f7b1eb17ad24
2419 | user: test
2419 | user: test
2420 | date: Thu Jan 01 00:00:00 1970 +0000
2420 | date: Thu Jan 01 00:00:00 1970 +0000
2421 | summary: 2
2421 | summary: 2
2422 |
2422 |
2423 | @ changeset: 2:9bc8ce7f9356
2423 | @ changeset: 2:9bc8ce7f9356
2424 |/ parent: 0:f7b1eb17ad24
2424 |/ parent: 0:f7b1eb17ad24
2425 | user: test
2425 | user: test
2426 | date: Thu Jan 01 00:00:00 1970 +0000
2426 | date: Thu Jan 01 00:00:00 1970 +0000
2427 | summary: 1
2427 | summary: 1
2428 |
2428 |
2429 o changeset: 0:f7b1eb17ad24
2429 o changeset: 0:f7b1eb17ad24
2430 user: test
2430 user: test
2431 date: Thu Jan 01 00:00:00 1970 +0000
2431 date: Thu Jan 01 00:00:00 1970 +0000
2432 summary: 0
2432 summary: 0
2433
2433
2434 $ hg log -f -G b
2434 $ hg log -f -G b
2435 @ changeset: 2:9bc8ce7f9356
2435 @ changeset: 2:9bc8ce7f9356
2436 | parent: 0:f7b1eb17ad24
2436 | parent: 0:f7b1eb17ad24
2437 ~ user: test
2437 ~ user: test
2438 date: Thu Jan 01 00:00:00 1970 +0000
2438 date: Thu Jan 01 00:00:00 1970 +0000
2439 summary: 1
2439 summary: 1
2440
2440
2441 $ hg log -G b
2441 $ hg log -G b
2442 @ changeset: 2:9bc8ce7f9356
2442 @ changeset: 2:9bc8ce7f9356
2443 | parent: 0:f7b1eb17ad24
2443 | parent: 0:f7b1eb17ad24
2444 ~ user: test
2444 ~ user: test
2445 date: Thu Jan 01 00:00:00 1970 +0000
2445 date: Thu Jan 01 00:00:00 1970 +0000
2446 summary: 1
2446 summary: 1
2447
2447
2448 $ cd ..
2448 $ cd ..
2449
2449
2450 Check proper report when the manifest changes but not the file issue4499
2450 Check proper report when the manifest changes but not the file issue4499
2451 ------------------------------------------------------------------------
2451 ------------------------------------------------------------------------
2452
2452
2453 $ hg init issue4499
2453 $ hg init issue4499
2454 $ cd issue4499
2454 $ cd issue4499
2455 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
2455 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
2456 > echo 1 > $f;
2456 > echo 1 > $f;
2457 > hg add $f;
2457 > hg add $f;
2458 > done
2458 > done
2459 $ hg commit -m 'A1B1C1'
2459 $ hg commit -m 'A1B1C1'
2460 $ echo 2 > A
2460 $ echo 2 > A
2461 $ echo 2 > B
2461 $ echo 2 > B
2462 $ echo 2 > C
2462 $ echo 2 > C
2463 $ hg commit -m 'A2B2C2'
2463 $ hg commit -m 'A2B2C2'
2464 $ hg up 0
2464 $ hg up 0
2465 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
2465 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
2466 $ echo 3 > A
2466 $ echo 3 > A
2467 $ echo 2 > B
2467 $ echo 2 > B
2468 $ echo 2 > C
2468 $ echo 2 > C
2469 $ hg commit -m 'A3B2C2'
2469 $ hg commit -m 'A3B2C2'
2470 created new head
2470 created new head
2471
2471
2472 $ hg log -G
2472 $ hg log -G
2473 @ changeset: 2:fe5fc3d0eb17
2473 @ changeset: 2:fe5fc3d0eb17
2474 | tag: tip
2474 | tag: tip
2475 | parent: 0:abf4f0e38563
2475 | parent: 0:abf4f0e38563
2476 | user: test
2476 | user: test
2477 | date: Thu Jan 01 00:00:00 1970 +0000
2477 | date: Thu Jan 01 00:00:00 1970 +0000
2478 | summary: A3B2C2
2478 | summary: A3B2C2
2479 |
2479 |
2480 | o changeset: 1:07dcc6b312c0
2480 | o changeset: 1:07dcc6b312c0
2481 |/ user: test
2481 |/ user: test
2482 | date: Thu Jan 01 00:00:00 1970 +0000
2482 | date: Thu Jan 01 00:00:00 1970 +0000
2483 | summary: A2B2C2
2483 | summary: A2B2C2
2484 |
2484 |
2485 o changeset: 0:abf4f0e38563
2485 o changeset: 0:abf4f0e38563
2486 user: test
2486 user: test
2487 date: Thu Jan 01 00:00:00 1970 +0000
2487 date: Thu Jan 01 00:00:00 1970 +0000
2488 summary: A1B1C1
2488 summary: A1B1C1
2489
2489
2490
2490
2491 Log -f on B should reports current changesets
2491 Log -f on B should reports current changesets
2492
2492
2493 $ hg log -fG B
2493 $ hg log -fG B
2494 @ changeset: 2:fe5fc3d0eb17
2494 @ changeset: 2:fe5fc3d0eb17
2495 | tag: tip
2495 | tag: tip
2496 | parent: 0:abf4f0e38563
2496 | parent: 0:abf4f0e38563
2497 | user: test
2497 | user: test
2498 | date: Thu Jan 01 00:00:00 1970 +0000
2498 | date: Thu Jan 01 00:00:00 1970 +0000
2499 | summary: A3B2C2
2499 | summary: A3B2C2
2500 |
2500 |
2501 o changeset: 0:abf4f0e38563
2501 o changeset: 0:abf4f0e38563
2502 user: test
2502 user: test
2503 date: Thu Jan 01 00:00:00 1970 +0000
2503 date: Thu Jan 01 00:00:00 1970 +0000
2504 summary: A1B1C1
2504 summary: A1B1C1
2505
2505
2506 $ cd ..
2506 $ cd ..
@@ -1,1563 +1,1563 b''
1 $ cat >> $HGRCPATH << EOF
1 $ cat >> $HGRCPATH << EOF
2 > [phases]
2 > [phases]
3 > # public changeset are not obsolete
3 > # public changeset are not obsolete
4 > publish=false
4 > publish=false
5 > [ui]
5 > [ui]
6 > logtemplate="{rev}:{node|short} ({phase}{if(obsolete, ' *{obsolete}*')}{if(instabilities, ' {instabilities}')}) [{tags} {bookmarks}] {desc|firstline}{if(obsfate, " [{join(obsfate, "; ")}]")}\n"
6 > logtemplate="{rev}:{node|short} ({phase}{if(obsolete, ' *{obsolete}*')}{if(instabilities, ' {instabilities}')}) [{tags} {bookmarks}] {desc|firstline}{if(obsfate, " [{join(obsfate, "; ")}]")}\n"
7 > EOF
7 > EOF
8 $ mkcommit() {
8 $ mkcommit() {
9 > echo "$1" > "$1"
9 > echo "$1" > "$1"
10 > hg add "$1"
10 > hg add "$1"
11 > hg ci -m "add $1"
11 > hg ci -m "add $1"
12 > }
12 > }
13 $ getid() {
13 $ getid() {
14 > hg log -T "{node}\n" --hidden -r "desc('$1')"
14 > hg log -T "{node}\n" --hidden -r "desc('$1')"
15 > }
15 > }
16
16
17 $ cat > debugkeys.py <<EOF
17 $ cat > debugkeys.py <<EOF
18 > def reposetup(ui, repo):
18 > def reposetup(ui, repo):
19 > class debugkeysrepo(repo.__class__):
19 > class debugkeysrepo(repo.__class__):
20 > def listkeys(self, namespace):
20 > def listkeys(self, namespace):
21 > ui.write('listkeys %s\n' % (namespace,))
21 > ui.write('listkeys %s\n' % (namespace,))
22 > return super(debugkeysrepo, self).listkeys(namespace)
22 > return super(debugkeysrepo, self).listkeys(namespace)
23 >
23 >
24 > if repo.local():
24 > if repo.local():
25 > repo.__class__ = debugkeysrepo
25 > repo.__class__ = debugkeysrepo
26 > EOF
26 > EOF
27
27
28 $ hg init tmpa
28 $ hg init tmpa
29 $ cd tmpa
29 $ cd tmpa
30 $ mkcommit kill_me
30 $ mkcommit kill_me
31
31
32 Checking that the feature is properly disabled
32 Checking that the feature is properly disabled
33
33
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
35 abort: creating obsolete markers is not enabled on this repo
35 abort: creating obsolete markers is not enabled on this repo
36 [255]
36 [255]
37
37
38 Enabling it
38 Enabling it
39
39
40 $ cat >> $HGRCPATH << EOF
40 $ cat >> $HGRCPATH << EOF
41 > [experimental]
41 > [experimental]
42 > evolution=exchange
42 > evolution=exchange
43 > evolution.createmarkers=True
43 > evolution.createmarkers=True
44 > EOF
44 > EOF
45
45
46 Killing a single changeset without replacement
46 Killing a single changeset without replacement
47
47
48 $ hg debugobsolete 0
48 $ hg debugobsolete 0
49 abort: changeset references must be full hexadecimal node identifiers
49 abort: changeset references must be full hexadecimal node identifiers
50 [255]
50 [255]
51 $ hg debugobsolete '00'
51 $ hg debugobsolete '00'
52 abort: changeset references must be full hexadecimal node identifiers
52 abort: changeset references must be full hexadecimal node identifiers
53 [255]
53 [255]
54 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
54 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
55 obsoleted 1 changesets
55 obsoleted 1 changesets
56 $ hg debugobsolete
56 $ hg debugobsolete
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
58
58
59 (test that mercurial is not confused)
59 (test that mercurial is not confused)
60
60
61 $ hg up null --quiet # having 0 as parent prevents it to be hidden
61 $ hg up null --quiet # having 0 as parent prevents it to be hidden
62 $ hg tip
62 $ hg tip
63 -1:000000000000 (public) [tip ]
63 -1:000000000000 (public) [tip ]
64 $ hg up --hidden tip --quiet
64 $ hg up --hidden tip --quiet
65 updating to a hidden changeset 97b7c2d76b18
65 updating to a hidden changeset 97b7c2d76b18
66
66
67 Killing a single changeset with itself should fail
67 Killing a single changeset with itself should fail
68 (simple local safeguard)
68 (simple local safeguard)
69
69
70 $ hg debugobsolete `getid kill_me` `getid kill_me`
70 $ hg debugobsolete `getid kill_me` `getid kill_me`
71 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
71 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
72 [255]
72 [255]
73
73
74 $ cd ..
74 $ cd ..
75
75
76 Killing a single changeset with replacement
76 Killing a single changeset with replacement
77 (and testing the format option)
77 (and testing the format option)
78
78
79 $ hg init tmpb
79 $ hg init tmpb
80 $ cd tmpb
80 $ cd tmpb
81 $ mkcommit a
81 $ mkcommit a
82 $ mkcommit b
82 $ mkcommit b
83 $ mkcommit original_c
83 $ mkcommit original_c
84 $ hg up "desc('b')"
84 $ hg up "desc('b')"
85 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
85 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
86 $ mkcommit new_c
86 $ mkcommit new_c
87 created new head
87 created new head
88 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
88 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
89 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
89 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
90 obsoleted 1 changesets
90 obsoleted 1 changesets
91 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
91 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
92 2:245bde4270cd add original_c
92 2:245bde4270cd add original_c
93 $ hg debugrevlog -cd
93 $ hg debugrevlog -cd
94 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
94 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
95 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
95 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
96 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
96 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
97 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
97 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
98 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
98 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
99 $ hg debugobsolete
99 $ hg debugobsolete
100 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
100 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
101
101
102 (check for version number of the obsstore)
102 (check for version number of the obsstore)
103
103
104 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
104 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
105 \x00 (no-eol) (esc)
105 \x00 (no-eol) (esc)
106
106
107 do it again (it read the obsstore before adding new changeset)
107 do it again (it read the obsstore before adding new changeset)
108
108
109 $ hg up '.^'
109 $ hg up '.^'
110 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
110 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
111 $ mkcommit new_2_c
111 $ mkcommit new_2_c
112 created new head
112 created new head
113 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
113 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
114 obsoleted 1 changesets
114 obsoleted 1 changesets
115 $ hg debugobsolete
115 $ hg debugobsolete
116 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
116 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
117 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
117 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
118
118
119 Register two markers with a missing node
119 Register two markers with a missing node
120
120
121 $ hg up '.^'
121 $ hg up '.^'
122 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
122 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
123 $ mkcommit new_3_c
123 $ mkcommit new_3_c
124 created new head
124 created new head
125 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
125 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
126 obsoleted 1 changesets
126 obsoleted 1 changesets
127 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
127 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
128 $ hg debugobsolete
128 $ hg debugobsolete
129 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
129 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
130 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
130 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
131 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
131 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
132 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
132 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
133
133
134 Test the --index option of debugobsolete command
134 Test the --index option of debugobsolete command
135 $ hg debugobsolete --index
135 $ hg debugobsolete --index
136 0 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
136 0 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
137 1 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
137 1 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
138 2 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
138 2 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
139 3 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
139 3 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
140
140
141 Refuse pathological nullid successors
141 Refuse pathological nullid successors
142 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
142 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
143 transaction abort!
143 transaction abort!
144 rollback completed
144 rollback completed
145 abort: bad obsolescence marker detected: invalid successors nullid
145 abort: bad obsolescence marker detected: invalid successors nullid
146 [255]
146 [255]
147
147
148 Check that graphlog detect that a changeset is obsolete:
148 Check that graphlog detect that a changeset is obsolete:
149
149
150 $ hg log -G
150 $ hg log -G
151 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
151 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
152 |
152 |
153 o 1:7c3bad9141dc (draft) [ ] add b
153 o 1:7c3bad9141dc (draft) [ ] add b
154 |
154 |
155 o 0:1f0dee641bb7 (draft) [ ] add a
155 o 0:1f0dee641bb7 (draft) [ ] add a
156
156
157
157
158 check that heads does not report them
158 check that heads does not report them
159
159
160 $ hg heads
160 $ hg heads
161 5:5601fb93a350 (draft) [tip ] add new_3_c
161 5:5601fb93a350 (draft) [tip ] add new_3_c
162 $ hg heads --hidden
162 $ hg heads --hidden
163 5:5601fb93a350 (draft) [tip ] add new_3_c
163 5:5601fb93a350 (draft) [tip ] add new_3_c
164 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
164 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
165 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
165 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
166 2:245bde4270cd (draft *obsolete*) [ ] add original_c [rewritten as 3:cdbce2fbb163]
166 2:245bde4270cd (draft *obsolete*) [ ] add original_c [rewritten as 3:cdbce2fbb163]
167
167
168
168
169 check that summary does not report them
169 check that summary does not report them
170
170
171 $ hg init ../sink
171 $ hg init ../sink
172 $ echo '[paths]' >> .hg/hgrc
172 $ echo '[paths]' >> .hg/hgrc
173 $ echo 'default=../sink' >> .hg/hgrc
173 $ echo 'default=../sink' >> .hg/hgrc
174 $ hg summary --remote
174 $ hg summary --remote
175 parent: 5:5601fb93a350 tip
175 parent: 5:5601fb93a350 tip
176 add new_3_c
176 add new_3_c
177 branch: default
177 branch: default
178 commit: (clean)
178 commit: (clean)
179 update: (current)
179 update: (current)
180 phases: 3 draft
180 phases: 3 draft
181 remote: 3 outgoing
181 remote: 3 outgoing
182
182
183 $ hg summary --remote --hidden
183 $ hg summary --remote --hidden
184 parent: 5:5601fb93a350 tip
184 parent: 5:5601fb93a350 tip
185 add new_3_c
185 add new_3_c
186 branch: default
186 branch: default
187 commit: (clean)
187 commit: (clean)
188 update: 3 new changesets, 4 branch heads (merge)
188 update: 3 new changesets, 4 branch heads (merge)
189 phases: 6 draft
189 phases: 6 draft
190 remote: 3 outgoing
190 remote: 3 outgoing
191
191
192 check that various commands work well with filtering
192 check that various commands work well with filtering
193
193
194 $ hg tip
194 $ hg tip
195 5:5601fb93a350 (draft) [tip ] add new_3_c
195 5:5601fb93a350 (draft) [tip ] add new_3_c
196 $ hg log -r 6
196 $ hg log -r 6
197 abort: unknown revision '6'!
197 abort: unknown revision '6'!
198 [255]
198 [255]
199 $ hg log -r 4
199 $ hg log -r 4
200 abort: hidden revision '4'!
200 abort: hidden revision '4' was rewritten as: 5601fb93a350!
201 (use --hidden to access hidden revisions)
201 (use --hidden to access hidden revisions)
202 [255]
202 [255]
203 $ hg debugrevspec 'rev(6)'
203 $ hg debugrevspec 'rev(6)'
204 $ hg debugrevspec 'rev(4)'
204 $ hg debugrevspec 'rev(4)'
205 $ hg debugrevspec 'null'
205 $ hg debugrevspec 'null'
206 -1
206 -1
207
207
208 Check that public changeset are not accounted as obsolete:
208 Check that public changeset are not accounted as obsolete:
209
209
210 $ hg --hidden phase --public 2
210 $ hg --hidden phase --public 2
211 $ hg log -G
211 $ hg log -G
212 @ 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
212 @ 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
213 |
213 |
214 | o 2:245bde4270cd (public) [ ] add original_c
214 | o 2:245bde4270cd (public) [ ] add original_c
215 |/
215 |/
216 o 1:7c3bad9141dc (public) [ ] add b
216 o 1:7c3bad9141dc (public) [ ] add b
217 |
217 |
218 o 0:1f0dee641bb7 (public) [ ] add a
218 o 0:1f0dee641bb7 (public) [ ] add a
219
219
220
220
221 And that bumped changeset are detected
221 And that bumped changeset are detected
222 --------------------------------------
222 --------------------------------------
223
223
224 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
224 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
225 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
225 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
226 the public changeset
226 the public changeset
227
227
228 $ hg log --hidden -r 'phasedivergent()'
228 $ hg log --hidden -r 'phasedivergent()'
229 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
229 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
230
230
231 And that we can't push bumped changeset
231 And that we can't push bumped changeset
232
232
233 $ hg push ../tmpa -r 0 --force #(make repo related)
233 $ hg push ../tmpa -r 0 --force #(make repo related)
234 pushing to ../tmpa
234 pushing to ../tmpa
235 searching for changes
235 searching for changes
236 warning: repository is unrelated
236 warning: repository is unrelated
237 adding changesets
237 adding changesets
238 adding manifests
238 adding manifests
239 adding file changes
239 adding file changes
240 added 1 changesets with 1 changes to 1 files (+1 heads)
240 added 1 changesets with 1 changes to 1 files (+1 heads)
241 $ hg push ../tmpa
241 $ hg push ../tmpa
242 pushing to ../tmpa
242 pushing to ../tmpa
243 searching for changes
243 searching for changes
244 abort: push includes phase-divergent changeset: 5601fb93a350!
244 abort: push includes phase-divergent changeset: 5601fb93a350!
245 [255]
245 [255]
246
246
247 Fixing "bumped" situation
247 Fixing "bumped" situation
248 We need to create a clone of 5 and add a special marker with a flag
248 We need to create a clone of 5 and add a special marker with a flag
249
249
250 $ hg summary
250 $ hg summary
251 parent: 5:5601fb93a350 tip (phase-divergent)
251 parent: 5:5601fb93a350 tip (phase-divergent)
252 add new_3_c
252 add new_3_c
253 branch: default
253 branch: default
254 commit: (clean)
254 commit: (clean)
255 update: 1 new changesets, 2 branch heads (merge)
255 update: 1 new changesets, 2 branch heads (merge)
256 phases: 1 draft
256 phases: 1 draft
257 phase-divergent: 1 changesets
257 phase-divergent: 1 changesets
258 $ hg up '5^'
258 $ hg up '5^'
259 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
259 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
260 $ hg revert -ar 5
260 $ hg revert -ar 5
261 adding new_3_c
261 adding new_3_c
262 $ hg ci -m 'add n3w_3_c'
262 $ hg ci -m 'add n3w_3_c'
263 created new head
263 created new head
264 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
264 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
265 obsoleted 1 changesets
265 obsoleted 1 changesets
266 $ hg log -r 'phasedivergent()'
266 $ hg log -r 'phasedivergent()'
267 $ hg log -G
267 $ hg log -G
268 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
268 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
269 |
269 |
270 | o 2:245bde4270cd (public) [ ] add original_c
270 | o 2:245bde4270cd (public) [ ] add original_c
271 |/
271 |/
272 o 1:7c3bad9141dc (public) [ ] add b
272 o 1:7c3bad9141dc (public) [ ] add b
273 |
273 |
274 o 0:1f0dee641bb7 (public) [ ] add a
274 o 0:1f0dee641bb7 (public) [ ] add a
275
275
276
276
277 Basic exclusive testing
277 Basic exclusive testing
278
278
279 $ hg log -G --hidden
279 $ hg log -G --hidden
280 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
280 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
281 |
281 |
282 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
282 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
283 |/
283 |/
284 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
284 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
285 |/
285 |/
286 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
286 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
287 |/
287 |/
288 | o 2:245bde4270cd (public) [ ] add original_c
288 | o 2:245bde4270cd (public) [ ] add original_c
289 |/
289 |/
290 o 1:7c3bad9141dc (public) [ ] add b
290 o 1:7c3bad9141dc (public) [ ] add b
291 |
291 |
292 o 0:1f0dee641bb7 (public) [ ] add a
292 o 0:1f0dee641bb7 (public) [ ] add a
293
293
294 $ hg debugobsolete --rev 6f9641995072
294 $ hg debugobsolete --rev 6f9641995072
295 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
295 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
296 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
296 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
297 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
297 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
298 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
298 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
299 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
299 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
300 $ hg debugobsolete --rev 6f9641995072 --exclusive
300 $ hg debugobsolete --rev 6f9641995072 --exclusive
301 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
301 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
302 $ hg debugobsolete --rev 5601fb93a350 --hidden
302 $ hg debugobsolete --rev 5601fb93a350 --hidden
303 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
303 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
304 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
304 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
305 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
305 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
306 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
306 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
307 $ hg debugobsolete --rev 5601fb93a350 --hidden --exclusive
307 $ hg debugobsolete --rev 5601fb93a350 --hidden --exclusive
308 $ hg debugobsolete --rev 5601fb93a350+6f9641995072 --hidden --exclusive
308 $ hg debugobsolete --rev 5601fb93a350+6f9641995072 --hidden --exclusive
309 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
309 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
310 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
310 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
311 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
311 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
312
312
313 $ cd ..
313 $ cd ..
314
314
315 Revision 0 is hidden
315 Revision 0 is hidden
316 --------------------
316 --------------------
317
317
318 $ hg init rev0hidden
318 $ hg init rev0hidden
319 $ cd rev0hidden
319 $ cd rev0hidden
320
320
321 $ mkcommit kill0
321 $ mkcommit kill0
322 $ hg up -q null
322 $ hg up -q null
323 $ hg debugobsolete `getid kill0`
323 $ hg debugobsolete `getid kill0`
324 obsoleted 1 changesets
324 obsoleted 1 changesets
325 $ mkcommit a
325 $ mkcommit a
326 $ mkcommit b
326 $ mkcommit b
327
327
328 Should pick the first visible revision as "repo" node
328 Should pick the first visible revision as "repo" node
329
329
330 $ hg archive ../archive-null
330 $ hg archive ../archive-null
331 $ cat ../archive-null/.hg_archival.txt
331 $ cat ../archive-null/.hg_archival.txt
332 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
332 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
333 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
333 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
334 branch: default
334 branch: default
335 latesttag: null
335 latesttag: null
336 latesttagdistance: 2
336 latesttagdistance: 2
337 changessincelatesttag: 2
337 changessincelatesttag: 2
338
338
339
339
340 $ cd ..
340 $ cd ..
341
341
342 Exchange Test
342 Exchange Test
343 ============================
343 ============================
344
344
345 Destination repo does not have any data
345 Destination repo does not have any data
346 ---------------------------------------
346 ---------------------------------------
347
347
348 Simple incoming test
348 Simple incoming test
349
349
350 $ hg init tmpc
350 $ hg init tmpc
351 $ cd tmpc
351 $ cd tmpc
352 $ hg incoming ../tmpb
352 $ hg incoming ../tmpb
353 comparing with ../tmpb
353 comparing with ../tmpb
354 0:1f0dee641bb7 (public) [ ] add a
354 0:1f0dee641bb7 (public) [ ] add a
355 1:7c3bad9141dc (public) [ ] add b
355 1:7c3bad9141dc (public) [ ] add b
356 2:245bde4270cd (public) [ ] add original_c
356 2:245bde4270cd (public) [ ] add original_c
357 6:6f9641995072 (draft) [tip ] add n3w_3_c
357 6:6f9641995072 (draft) [tip ] add n3w_3_c
358
358
359 Try to pull markers
359 Try to pull markers
360 (extinct changeset are excluded but marker are pushed)
360 (extinct changeset are excluded but marker are pushed)
361
361
362 $ hg pull ../tmpb
362 $ hg pull ../tmpb
363 pulling from ../tmpb
363 pulling from ../tmpb
364 requesting all changes
364 requesting all changes
365 adding changesets
365 adding changesets
366 adding manifests
366 adding manifests
367 adding file changes
367 adding file changes
368 added 4 changesets with 4 changes to 4 files (+1 heads)
368 added 4 changesets with 4 changes to 4 files (+1 heads)
369 5 new obsolescence markers
369 5 new obsolescence markers
370 new changesets 1f0dee641bb7:6f9641995072
370 new changesets 1f0dee641bb7:6f9641995072
371 (run 'hg heads' to see heads, 'hg merge' to merge)
371 (run 'hg heads' to see heads, 'hg merge' to merge)
372 $ hg debugobsolete
372 $ hg debugobsolete
373 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
373 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
374 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
374 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
375 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
375 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
376 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
376 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
377 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
377 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
378
378
379 Rollback//Transaction support
379 Rollback//Transaction support
380
380
381 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
381 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
382 $ hg debugobsolete
382 $ hg debugobsolete
383 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
383 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
384 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
384 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
385 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
385 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
386 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
386 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
387 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
387 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
388 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
388 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
389 $ hg rollback -n
389 $ hg rollback -n
390 repository tip rolled back to revision 3 (undo debugobsolete)
390 repository tip rolled back to revision 3 (undo debugobsolete)
391 $ hg rollback
391 $ hg rollback
392 repository tip rolled back to revision 3 (undo debugobsolete)
392 repository tip rolled back to revision 3 (undo debugobsolete)
393 $ hg debugobsolete
393 $ hg debugobsolete
394 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
394 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
395 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
395 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
396 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
396 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
397 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
397 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
398 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
398 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
399
399
400 $ cd ..
400 $ cd ..
401
401
402 Try to push markers
402 Try to push markers
403
403
404 $ hg init tmpd
404 $ hg init tmpd
405 $ hg -R tmpb push tmpd
405 $ hg -R tmpb push tmpd
406 pushing to tmpd
406 pushing to tmpd
407 searching for changes
407 searching for changes
408 adding changesets
408 adding changesets
409 adding manifests
409 adding manifests
410 adding file changes
410 adding file changes
411 added 4 changesets with 4 changes to 4 files (+1 heads)
411 added 4 changesets with 4 changes to 4 files (+1 heads)
412 5 new obsolescence markers
412 5 new obsolescence markers
413 $ hg -R tmpd debugobsolete | sort
413 $ hg -R tmpd debugobsolete | sort
414 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
414 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
415 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
415 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
416 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
416 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
417 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
417 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
418 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
418 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
419
419
420 Check obsolete keys are exchanged only if source has an obsolete store
420 Check obsolete keys are exchanged only if source has an obsolete store
421
421
422 $ hg init empty
422 $ hg init empty
423 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
423 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
424 pushing to tmpd
424 pushing to tmpd
425 listkeys phases
425 listkeys phases
426 listkeys bookmarks
426 listkeys bookmarks
427 no changes found
427 no changes found
428 listkeys phases
428 listkeys phases
429 [1]
429 [1]
430
430
431 clone support
431 clone support
432 (markers are copied and extinct changesets are included to allow hardlinks)
432 (markers are copied and extinct changesets are included to allow hardlinks)
433
433
434 $ hg clone tmpb clone-dest
434 $ hg clone tmpb clone-dest
435 updating to branch default
435 updating to branch default
436 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
436 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 $ hg -R clone-dest log -G --hidden
437 $ hg -R clone-dest log -G --hidden
438 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
438 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
439 |
439 |
440 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
440 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
441 |/
441 |/
442 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
442 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
443 |/
443 |/
444 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
444 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
445 |/
445 |/
446 | o 2:245bde4270cd (public) [ ] add original_c
446 | o 2:245bde4270cd (public) [ ] add original_c
447 |/
447 |/
448 o 1:7c3bad9141dc (public) [ ] add b
448 o 1:7c3bad9141dc (public) [ ] add b
449 |
449 |
450 o 0:1f0dee641bb7 (public) [ ] add a
450 o 0:1f0dee641bb7 (public) [ ] add a
451
451
452 $ hg -R clone-dest debugobsolete
452 $ hg -R clone-dest debugobsolete
453 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
453 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
454 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
454 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
455 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
455 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
456 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
456 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
457 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
457 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
458
458
459
459
460 Destination repo have existing data
460 Destination repo have existing data
461 ---------------------------------------
461 ---------------------------------------
462
462
463 On pull
463 On pull
464
464
465 $ hg init tmpe
465 $ hg init tmpe
466 $ cd tmpe
466 $ cd tmpe
467 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
467 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
468 $ hg pull ../tmpb
468 $ hg pull ../tmpb
469 pulling from ../tmpb
469 pulling from ../tmpb
470 requesting all changes
470 requesting all changes
471 adding changesets
471 adding changesets
472 adding manifests
472 adding manifests
473 adding file changes
473 adding file changes
474 added 4 changesets with 4 changes to 4 files (+1 heads)
474 added 4 changesets with 4 changes to 4 files (+1 heads)
475 5 new obsolescence markers
475 5 new obsolescence markers
476 new changesets 1f0dee641bb7:6f9641995072
476 new changesets 1f0dee641bb7:6f9641995072
477 (run 'hg heads' to see heads, 'hg merge' to merge)
477 (run 'hg heads' to see heads, 'hg merge' to merge)
478 $ hg debugobsolete
478 $ hg debugobsolete
479 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
479 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
480 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
480 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
481 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
481 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
482 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
482 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
483 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
483 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
484 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
484 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
485
485
486
486
487 On push
487 On push
488
488
489 $ hg push ../tmpc
489 $ hg push ../tmpc
490 pushing to ../tmpc
490 pushing to ../tmpc
491 searching for changes
491 searching for changes
492 no changes found
492 no changes found
493 1 new obsolescence markers
493 1 new obsolescence markers
494 [1]
494 [1]
495 $ hg -R ../tmpc debugobsolete
495 $ hg -R ../tmpc debugobsolete
496 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
496 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
497 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
497 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
498 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
498 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
499 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
499 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
500 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
500 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
501 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
501 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
502
502
503 detect outgoing obsolete and unstable
503 detect outgoing obsolete and unstable
504 ---------------------------------------
504 ---------------------------------------
505
505
506
506
507 $ hg log -G
507 $ hg log -G
508 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
508 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
509 |
509 |
510 | o 2:245bde4270cd (public) [ ] add original_c
510 | o 2:245bde4270cd (public) [ ] add original_c
511 |/
511 |/
512 o 1:7c3bad9141dc (public) [ ] add b
512 o 1:7c3bad9141dc (public) [ ] add b
513 |
513 |
514 o 0:1f0dee641bb7 (public) [ ] add a
514 o 0:1f0dee641bb7 (public) [ ] add a
515
515
516 $ hg up 'desc("n3w_3_c")'
516 $ hg up 'desc("n3w_3_c")'
517 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
517 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
518 $ mkcommit original_d
518 $ mkcommit original_d
519 $ mkcommit original_e
519 $ mkcommit original_e
520 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
520 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
521 obsoleted 1 changesets
521 obsoleted 1 changesets
522 $ hg debugobsolete | grep `getid original_d`
522 $ hg debugobsolete | grep `getid original_d`
523 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
523 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
524 $ hg log -r 'obsolete()'
524 $ hg log -r 'obsolete()'
525 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
525 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
526 $ hg summary
526 $ hg summary
527 parent: 5:cda648ca50f5 tip (orphan)
527 parent: 5:cda648ca50f5 tip (orphan)
528 add original_e
528 add original_e
529 branch: default
529 branch: default
530 commit: (clean)
530 commit: (clean)
531 update: 1 new changesets, 2 branch heads (merge)
531 update: 1 new changesets, 2 branch heads (merge)
532 phases: 3 draft
532 phases: 3 draft
533 orphan: 1 changesets
533 orphan: 1 changesets
534 $ hg log -G -r '::orphan()'
534 $ hg log -G -r '::orphan()'
535 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
535 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
536 |
536 |
537 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
537 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
538 |
538 |
539 o 3:6f9641995072 (draft) [ ] add n3w_3_c
539 o 3:6f9641995072 (draft) [ ] add n3w_3_c
540 |
540 |
541 o 1:7c3bad9141dc (public) [ ] add b
541 o 1:7c3bad9141dc (public) [ ] add b
542 |
542 |
543 o 0:1f0dee641bb7 (public) [ ] add a
543 o 0:1f0dee641bb7 (public) [ ] add a
544
544
545
545
546 refuse to push obsolete changeset
546 refuse to push obsolete changeset
547
547
548 $ hg push ../tmpc/ -r 'desc("original_d")'
548 $ hg push ../tmpc/ -r 'desc("original_d")'
549 pushing to ../tmpc/
549 pushing to ../tmpc/
550 searching for changes
550 searching for changes
551 abort: push includes obsolete changeset: 94b33453f93b!
551 abort: push includes obsolete changeset: 94b33453f93b!
552 [255]
552 [255]
553
553
554 refuse to push unstable changeset
554 refuse to push unstable changeset
555
555
556 $ hg push ../tmpc/
556 $ hg push ../tmpc/
557 pushing to ../tmpc/
557 pushing to ../tmpc/
558 searching for changes
558 searching for changes
559 abort: push includes orphan changeset: cda648ca50f5!
559 abort: push includes orphan changeset: cda648ca50f5!
560 [255]
560 [255]
561
561
562 Test that extinct changeset are properly detected
562 Test that extinct changeset are properly detected
563
563
564 $ hg log -r 'extinct()'
564 $ hg log -r 'extinct()'
565
565
566 Don't try to push extinct changeset
566 Don't try to push extinct changeset
567
567
568 $ hg init ../tmpf
568 $ hg init ../tmpf
569 $ hg out ../tmpf
569 $ hg out ../tmpf
570 comparing with ../tmpf
570 comparing with ../tmpf
571 searching for changes
571 searching for changes
572 0:1f0dee641bb7 (public) [ ] add a
572 0:1f0dee641bb7 (public) [ ] add a
573 1:7c3bad9141dc (public) [ ] add b
573 1:7c3bad9141dc (public) [ ] add b
574 2:245bde4270cd (public) [ ] add original_c
574 2:245bde4270cd (public) [ ] add original_c
575 3:6f9641995072 (draft) [ ] add n3w_3_c
575 3:6f9641995072 (draft) [ ] add n3w_3_c
576 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
576 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
577 5:cda648ca50f5 (draft orphan) [tip ] add original_e
577 5:cda648ca50f5 (draft orphan) [tip ] add original_e
578 $ hg push ../tmpf -f # -f because be push unstable too
578 $ hg push ../tmpf -f # -f because be push unstable too
579 pushing to ../tmpf
579 pushing to ../tmpf
580 searching for changes
580 searching for changes
581 adding changesets
581 adding changesets
582 adding manifests
582 adding manifests
583 adding file changes
583 adding file changes
584 added 6 changesets with 6 changes to 6 files (+1 heads)
584 added 6 changesets with 6 changes to 6 files (+1 heads)
585 7 new obsolescence markers
585 7 new obsolescence markers
586
586
587 no warning displayed
587 no warning displayed
588
588
589 $ hg push ../tmpf
589 $ hg push ../tmpf
590 pushing to ../tmpf
590 pushing to ../tmpf
591 searching for changes
591 searching for changes
592 no changes found
592 no changes found
593 [1]
593 [1]
594
594
595 Do not warn about new head when the new head is a successors of a remote one
595 Do not warn about new head when the new head is a successors of a remote one
596
596
597 $ hg log -G
597 $ hg log -G
598 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
598 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
599 |
599 |
600 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
600 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
601 |
601 |
602 o 3:6f9641995072 (draft) [ ] add n3w_3_c
602 o 3:6f9641995072 (draft) [ ] add n3w_3_c
603 |
603 |
604 | o 2:245bde4270cd (public) [ ] add original_c
604 | o 2:245bde4270cd (public) [ ] add original_c
605 |/
605 |/
606 o 1:7c3bad9141dc (public) [ ] add b
606 o 1:7c3bad9141dc (public) [ ] add b
607 |
607 |
608 o 0:1f0dee641bb7 (public) [ ] add a
608 o 0:1f0dee641bb7 (public) [ ] add a
609
609
610 $ hg up -q 'desc(n3w_3_c)'
610 $ hg up -q 'desc(n3w_3_c)'
611 $ mkcommit obsolete_e
611 $ mkcommit obsolete_e
612 created new head
612 created new head
613 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'` \
613 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'` \
614 > -u 'test <test@example.net>'
614 > -u 'test <test@example.net>'
615 obsoleted 1 changesets
615 obsoleted 1 changesets
616 $ hg outgoing ../tmpf # parasite hg outgoing testin
616 $ hg outgoing ../tmpf # parasite hg outgoing testin
617 comparing with ../tmpf
617 comparing with ../tmpf
618 searching for changes
618 searching for changes
619 6:3de5eca88c00 (draft) [tip ] add obsolete_e
619 6:3de5eca88c00 (draft) [tip ] add obsolete_e
620 $ hg push ../tmpf
620 $ hg push ../tmpf
621 pushing to ../tmpf
621 pushing to ../tmpf
622 searching for changes
622 searching for changes
623 adding changesets
623 adding changesets
624 adding manifests
624 adding manifests
625 adding file changes
625 adding file changes
626 added 1 changesets with 1 changes to 1 files (+1 heads)
626 added 1 changesets with 1 changes to 1 files (+1 heads)
627 1 new obsolescence markers
627 1 new obsolescence markers
628 obsoleted 1 changesets
628 obsoleted 1 changesets
629
629
630 test relevance computation
630 test relevance computation
631 ---------------------------------------
631 ---------------------------------------
632
632
633 Checking simple case of "marker relevance".
633 Checking simple case of "marker relevance".
634
634
635
635
636 Reminder of the repo situation
636 Reminder of the repo situation
637
637
638 $ hg log --hidden --graph
638 $ hg log --hidden --graph
639 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
639 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
640 |
640 |
641 | x 5:cda648ca50f5 (draft *obsolete*) [ ] add original_e [rewritten as 6:3de5eca88c00 by test <test@example.net>]
641 | x 5:cda648ca50f5 (draft *obsolete*) [ ] add original_e [rewritten as 6:3de5eca88c00 by test <test@example.net>]
642 | |
642 | |
643 | x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
643 | x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
644 |/
644 |/
645 o 3:6f9641995072 (draft) [ ] add n3w_3_c
645 o 3:6f9641995072 (draft) [ ] add n3w_3_c
646 |
646 |
647 | o 2:245bde4270cd (public) [ ] add original_c
647 | o 2:245bde4270cd (public) [ ] add original_c
648 |/
648 |/
649 o 1:7c3bad9141dc (public) [ ] add b
649 o 1:7c3bad9141dc (public) [ ] add b
650 |
650 |
651 o 0:1f0dee641bb7 (public) [ ] add a
651 o 0:1f0dee641bb7 (public) [ ] add a
652
652
653
653
654 List of all markers
654 List of all markers
655
655
656 $ hg debugobsolete
656 $ hg debugobsolete
657 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
657 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
658 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
658 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
659 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
659 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
660 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
660 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
661 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
661 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
662 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
662 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
663 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
663 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
664 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
664 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
665
665
666 List of changesets with no chain
666 List of changesets with no chain
667
667
668 $ hg debugobsolete --hidden --rev ::2
668 $ hg debugobsolete --hidden --rev ::2
669
669
670 List of changesets that are included on marker chain
670 List of changesets that are included on marker chain
671
671
672 $ hg debugobsolete --hidden --rev 6
672 $ hg debugobsolete --hidden --rev 6
673 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
673 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
674
674
675 List of changesets with a longer chain, (including a pruned children)
675 List of changesets with a longer chain, (including a pruned children)
676
676
677 $ hg debugobsolete --hidden --rev 3
677 $ hg debugobsolete --hidden --rev 3
678 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
678 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
679 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
679 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
680 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
680 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
681 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
681 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
682 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
682 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
683 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
683 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
684 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
684 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
685
685
686 List of both
686 List of both
687
687
688 $ hg debugobsolete --hidden --rev 3::6
688 $ hg debugobsolete --hidden --rev 3::6
689 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
689 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
690 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
690 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
691 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
691 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
692 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
692 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
693 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
693 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
694 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
694 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
695 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
695 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
696 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
696 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
697
697
698 List of all markers in JSON
698 List of all markers in JSON
699
699
700 $ hg debugobsolete -Tjson
700 $ hg debugobsolete -Tjson
701 [
701 [
702 {
702 {
703 "date": [1339.0, 0],
703 "date": [1339.0, 0],
704 "flag": 0,
704 "flag": 0,
705 "metadata": {"user": "test"},
705 "metadata": {"user": "test"},
706 "prednode": "1339133913391339133913391339133913391339",
706 "prednode": "1339133913391339133913391339133913391339",
707 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
707 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
708 },
708 },
709 {
709 {
710 "date": [1339.0, 0],
710 "date": [1339.0, 0],
711 "flag": 0,
711 "flag": 0,
712 "metadata": {"user": "test"},
712 "metadata": {"user": "test"},
713 "prednode": "1337133713371337133713371337133713371337",
713 "prednode": "1337133713371337133713371337133713371337",
714 "succnodes": ["5601fb93a350734d935195fee37f4054c529ff39"]
714 "succnodes": ["5601fb93a350734d935195fee37f4054c529ff39"]
715 },
715 },
716 {
716 {
717 "date": [121.0, 120],
717 "date": [121.0, 120],
718 "flag": 12,
718 "flag": 12,
719 "metadata": {"user": "test"},
719 "metadata": {"user": "test"},
720 "prednode": "245bde4270cd1072a27757984f9cda8ba26f08ca",
720 "prednode": "245bde4270cd1072a27757984f9cda8ba26f08ca",
721 "succnodes": ["cdbce2fbb16313928851e97e0d85413f3f7eb77f"]
721 "succnodes": ["cdbce2fbb16313928851e97e0d85413f3f7eb77f"]
722 },
722 },
723 {
723 {
724 "date": [1338.0, 0],
724 "date": [1338.0, 0],
725 "flag": 1,
725 "flag": 1,
726 "metadata": {"user": "test"},
726 "metadata": {"user": "test"},
727 "prednode": "5601fb93a350734d935195fee37f4054c529ff39",
727 "prednode": "5601fb93a350734d935195fee37f4054c529ff39",
728 "succnodes": ["6f96419950729f3671185b847352890f074f7557"]
728 "succnodes": ["6f96419950729f3671185b847352890f074f7557"]
729 },
729 },
730 {
730 {
731 "date": [1338.0, 0],
731 "date": [1338.0, 0],
732 "flag": 0,
732 "flag": 0,
733 "metadata": {"user": "test"},
733 "metadata": {"user": "test"},
734 "prednode": "ca819180edb99ed25ceafb3e9584ac287e240b00",
734 "prednode": "ca819180edb99ed25ceafb3e9584ac287e240b00",
735 "succnodes": ["1337133713371337133713371337133713371337"]
735 "succnodes": ["1337133713371337133713371337133713371337"]
736 },
736 },
737 {
737 {
738 "date": [1337.0, 0],
738 "date": [1337.0, 0],
739 "flag": 0,
739 "flag": 0,
740 "metadata": {"user": "test"},
740 "metadata": {"user": "test"},
741 "prednode": "cdbce2fbb16313928851e97e0d85413f3f7eb77f",
741 "prednode": "cdbce2fbb16313928851e97e0d85413f3f7eb77f",
742 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
742 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
743 },
743 },
744 {
744 {
745 "date": [0.0, 0],
745 "date": [0.0, 0],
746 "flag": 0,
746 "flag": 0,
747 "metadata": {"user": "test"},
747 "metadata": {"user": "test"},
748 "parentnodes": ["6f96419950729f3671185b847352890f074f7557"],
748 "parentnodes": ["6f96419950729f3671185b847352890f074f7557"],
749 "prednode": "94b33453f93bdb8d457ef9b770851a618bf413e1",
749 "prednode": "94b33453f93bdb8d457ef9b770851a618bf413e1",
750 "succnodes": []
750 "succnodes": []
751 },
751 },
752 {
752 {
753 "date": *, (glob)
753 "date": *, (glob)
754 "flag": 0,
754 "flag": 0,
755 "metadata": {"user": "test <test@example.net>"},
755 "metadata": {"user": "test <test@example.net>"},
756 "prednode": "cda648ca50f50482b7055c0b0c4c117bba6733d9",
756 "prednode": "cda648ca50f50482b7055c0b0c4c117bba6733d9",
757 "succnodes": ["3de5eca88c00aa039da7399a220f4a5221faa585"]
757 "succnodes": ["3de5eca88c00aa039da7399a220f4a5221faa585"]
758 }
758 }
759 ]
759 ]
760
760
761 Template keywords
761 Template keywords
762
762
763 $ hg debugobsolete -r6 -T '{succnodes % "{node|short}"} {date|shortdate}\n'
763 $ hg debugobsolete -r6 -T '{succnodes % "{node|short}"} {date|shortdate}\n'
764 3de5eca88c00 ????-??-?? (glob)
764 3de5eca88c00 ????-??-?? (glob)
765 $ hg debugobsolete -r6 -T '{join(metadata % "{key}={value}", " ")}\n'
765 $ hg debugobsolete -r6 -T '{join(metadata % "{key}={value}", " ")}\n'
766 user=test <test@example.net>
766 user=test <test@example.net>
767 $ hg debugobsolete -r6 -T '{metadata}\n{metadata}\n'
767 $ hg debugobsolete -r6 -T '{metadata}\n{metadata}\n'
768 'user': 'test <test@example.net>'
768 'user': 'test <test@example.net>'
769 'user': 'test <test@example.net>'
769 'user': 'test <test@example.net>'
770 $ hg debugobsolete -r6 -T '{succnodes}\n{succnodes}\n'
770 $ hg debugobsolete -r6 -T '{succnodes}\n{succnodes}\n'
771 3de5eca88c00aa039da7399a220f4a5221faa585
771 3de5eca88c00aa039da7399a220f4a5221faa585
772 3de5eca88c00aa039da7399a220f4a5221faa585
772 3de5eca88c00aa039da7399a220f4a5221faa585
773 $ hg debugobsolete -r6 -T '{flag} {get(metadata, "user")}\n'
773 $ hg debugobsolete -r6 -T '{flag} {get(metadata, "user")}\n'
774 0 test <test@example.net>
774 0 test <test@example.net>
775
775
776 Test the debug output for exchange
776 Test the debug output for exchange
777 ----------------------------------
777 ----------------------------------
778
778
779 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' # bundle2
779 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' # bundle2
780 pulling from ../tmpb
780 pulling from ../tmpb
781 searching for changes
781 searching for changes
782 no changes found
782 no changes found
783 obsmarker-exchange: 346 bytes received
783 obsmarker-exchange: 346 bytes received
784
784
785 check hgweb does not explode
785 check hgweb does not explode
786 ====================================
786 ====================================
787
787
788 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
788 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
789 adding changesets
789 adding changesets
790 adding manifests
790 adding manifests
791 adding file changes
791 adding file changes
792 added 62 changesets with 63 changes to 9 files (+60 heads)
792 added 62 changesets with 63 changes to 9 files (+60 heads)
793 new changesets 50c51b361e60:c15e9edfca13
793 new changesets 50c51b361e60:c15e9edfca13
794 (run 'hg heads .' to see heads, 'hg merge' to merge)
794 (run 'hg heads .' to see heads, 'hg merge' to merge)
795 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
795 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
796 > do
796 > do
797 > hg debugobsolete $node
797 > hg debugobsolete $node
798 > done
798 > done
799 obsoleted 1 changesets
799 obsoleted 1 changesets
800 obsoleted 1 changesets
800 obsoleted 1 changesets
801 obsoleted 1 changesets
801 obsoleted 1 changesets
802 obsoleted 1 changesets
802 obsoleted 1 changesets
803 obsoleted 1 changesets
803 obsoleted 1 changesets
804 obsoleted 1 changesets
804 obsoleted 1 changesets
805 obsoleted 1 changesets
805 obsoleted 1 changesets
806 obsoleted 1 changesets
806 obsoleted 1 changesets
807 obsoleted 1 changesets
807 obsoleted 1 changesets
808 obsoleted 1 changesets
808 obsoleted 1 changesets
809 obsoleted 1 changesets
809 obsoleted 1 changesets
810 obsoleted 1 changesets
810 obsoleted 1 changesets
811 obsoleted 1 changesets
811 obsoleted 1 changesets
812 obsoleted 1 changesets
812 obsoleted 1 changesets
813 obsoleted 1 changesets
813 obsoleted 1 changesets
814 obsoleted 1 changesets
814 obsoleted 1 changesets
815 obsoleted 1 changesets
815 obsoleted 1 changesets
816 obsoleted 1 changesets
816 obsoleted 1 changesets
817 obsoleted 1 changesets
817 obsoleted 1 changesets
818 obsoleted 1 changesets
818 obsoleted 1 changesets
819 obsoleted 1 changesets
819 obsoleted 1 changesets
820 obsoleted 1 changesets
820 obsoleted 1 changesets
821 obsoleted 1 changesets
821 obsoleted 1 changesets
822 obsoleted 1 changesets
822 obsoleted 1 changesets
823 obsoleted 1 changesets
823 obsoleted 1 changesets
824 obsoleted 1 changesets
824 obsoleted 1 changesets
825 obsoleted 1 changesets
825 obsoleted 1 changesets
826 obsoleted 1 changesets
826 obsoleted 1 changesets
827 obsoleted 1 changesets
827 obsoleted 1 changesets
828 obsoleted 1 changesets
828 obsoleted 1 changesets
829 obsoleted 1 changesets
829 obsoleted 1 changesets
830 obsoleted 1 changesets
830 obsoleted 1 changesets
831 obsoleted 1 changesets
831 obsoleted 1 changesets
832 obsoleted 1 changesets
832 obsoleted 1 changesets
833 obsoleted 1 changesets
833 obsoleted 1 changesets
834 obsoleted 1 changesets
834 obsoleted 1 changesets
835 obsoleted 1 changesets
835 obsoleted 1 changesets
836 obsoleted 1 changesets
836 obsoleted 1 changesets
837 obsoleted 1 changesets
837 obsoleted 1 changesets
838 obsoleted 1 changesets
838 obsoleted 1 changesets
839 obsoleted 1 changesets
839 obsoleted 1 changesets
840 obsoleted 1 changesets
840 obsoleted 1 changesets
841 obsoleted 1 changesets
841 obsoleted 1 changesets
842 obsoleted 1 changesets
842 obsoleted 1 changesets
843 obsoleted 1 changesets
843 obsoleted 1 changesets
844 obsoleted 1 changesets
844 obsoleted 1 changesets
845 obsoleted 1 changesets
845 obsoleted 1 changesets
846 obsoleted 1 changesets
846 obsoleted 1 changesets
847 obsoleted 1 changesets
847 obsoleted 1 changesets
848 obsoleted 1 changesets
848 obsoleted 1 changesets
849 obsoleted 1 changesets
849 obsoleted 1 changesets
850 obsoleted 1 changesets
850 obsoleted 1 changesets
851 obsoleted 1 changesets
851 obsoleted 1 changesets
852 obsoleted 1 changesets
852 obsoleted 1 changesets
853 obsoleted 1 changesets
853 obsoleted 1 changesets
854 obsoleted 1 changesets
854 obsoleted 1 changesets
855 obsoleted 1 changesets
855 obsoleted 1 changesets
856 obsoleted 1 changesets
856 obsoleted 1 changesets
857 obsoleted 1 changesets
857 obsoleted 1 changesets
858 obsoleted 1 changesets
858 obsoleted 1 changesets
859 $ hg up tip
859 $ hg up tip
860 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
860 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
861
861
862 #if serve
862 #if serve
863
863
864 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
864 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
865 $ cat hg.pid >> $DAEMON_PIDS
865 $ cat hg.pid >> $DAEMON_PIDS
866
866
867 check changelog view
867 check changelog view
868
868
869 $ get-with-headers.py --headeronly localhost:$HGPORT 'shortlog/'
869 $ get-with-headers.py --headeronly localhost:$HGPORT 'shortlog/'
870 200 Script output follows
870 200 Script output follows
871
871
872 check graph view
872 check graph view
873
873
874 $ get-with-headers.py --headeronly localhost:$HGPORT 'graph'
874 $ get-with-headers.py --headeronly localhost:$HGPORT 'graph'
875 200 Script output follows
875 200 Script output follows
876
876
877 check filelog view
877 check filelog view
878
878
879 $ get-with-headers.py --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
879 $ get-with-headers.py --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
880 200 Script output follows
880 200 Script output follows
881
881
882 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/68'
882 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/68'
883 200 Script output follows
883 200 Script output follows
884 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
884 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
885 404 Not Found
885 404 Not Found
886 [1]
886 [1]
887
887
888 check that web.view config option:
888 check that web.view config option:
889
889
890 $ killdaemons.py hg.pid
890 $ killdaemons.py hg.pid
891 $ cat >> .hg/hgrc << EOF
891 $ cat >> .hg/hgrc << EOF
892 > [web]
892 > [web]
893 > view=all
893 > view=all
894 > EOF
894 > EOF
895 $ wait
895 $ wait
896 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
896 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
897 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
897 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
898 200 Script output follows
898 200 Script output follows
899 $ killdaemons.py hg.pid
899 $ killdaemons.py hg.pid
900
900
901 Checking _enable=False warning if obsolete marker exists
901 Checking _enable=False warning if obsolete marker exists
902
902
903 $ echo '[experimental]' >> $HGRCPATH
903 $ echo '[experimental]' >> $HGRCPATH
904 $ echo "evolution=" >> $HGRCPATH
904 $ echo "evolution=" >> $HGRCPATH
905 $ hg log -r tip
905 $ hg log -r tip
906 68:c15e9edfca13 (draft) [tip ] add celestine
906 68:c15e9edfca13 (draft) [tip ] add celestine
907
907
908 reenable for later test
908 reenable for later test
909
909
910 $ echo '[experimental]' >> $HGRCPATH
910 $ echo '[experimental]' >> $HGRCPATH
911 $ echo "evolution.exchange=True" >> $HGRCPATH
911 $ echo "evolution.exchange=True" >> $HGRCPATH
912 $ echo "evolution.createmarkers=True" >> $HGRCPATH
912 $ echo "evolution.createmarkers=True" >> $HGRCPATH
913
913
914 $ rm hg.pid access.log errors.log
914 $ rm hg.pid access.log errors.log
915 #endif
915 #endif
916
916
917 Several troubles on the same changeset (create an unstable and bumped changeset)
917 Several troubles on the same changeset (create an unstable and bumped changeset)
918
918
919 $ hg debugobsolete `getid obsolete_e`
919 $ hg debugobsolete `getid obsolete_e`
920 obsoleted 1 changesets
920 obsoleted 1 changesets
921 $ hg debugobsolete `getid original_c` `getid babar`
921 $ hg debugobsolete `getid original_c` `getid babar`
922 $ hg log --config ui.logtemplate= -r 'phasedivergent() and orphan()'
922 $ hg log --config ui.logtemplate= -r 'phasedivergent() and orphan()'
923 changeset: 7:50c51b361e60
923 changeset: 7:50c51b361e60
924 user: test
924 user: test
925 date: Thu Jan 01 00:00:00 1970 +0000
925 date: Thu Jan 01 00:00:00 1970 +0000
926 instability: orphan, phase-divergent
926 instability: orphan, phase-divergent
927 summary: add babar
927 summary: add babar
928
928
929
929
930 test the "obsolete" templatekw
930 test the "obsolete" templatekw
931
931
932 $ hg log -r 'obsolete()'
932 $ hg log -r 'obsolete()'
933 6:3de5eca88c00 (draft *obsolete*) [ ] add obsolete_e [pruned]
933 6:3de5eca88c00 (draft *obsolete*) [ ] add obsolete_e [pruned]
934
934
935 test the "troubles" templatekw
935 test the "troubles" templatekw
936
936
937 $ hg log -r 'phasedivergent() and orphan()'
937 $ hg log -r 'phasedivergent() and orphan()'
938 7:50c51b361e60 (draft orphan phase-divergent) [ ] add babar
938 7:50c51b361e60 (draft orphan phase-divergent) [ ] add babar
939
939
940 test the default cmdline template
940 test the default cmdline template
941
941
942 $ hg log -T default -r 'phasedivergent()'
942 $ hg log -T default -r 'phasedivergent()'
943 changeset: 7:50c51b361e60
943 changeset: 7:50c51b361e60
944 user: test
944 user: test
945 date: Thu Jan 01 00:00:00 1970 +0000
945 date: Thu Jan 01 00:00:00 1970 +0000
946 instability: orphan, phase-divergent
946 instability: orphan, phase-divergent
947 summary: add babar
947 summary: add babar
948
948
949 $ hg log -T default -r 'obsolete()'
949 $ hg log -T default -r 'obsolete()'
950 changeset: 6:3de5eca88c00
950 changeset: 6:3de5eca88c00
951 parent: 3:6f9641995072
951 parent: 3:6f9641995072
952 user: test
952 user: test
953 date: Thu Jan 01 00:00:00 1970 +0000
953 date: Thu Jan 01 00:00:00 1970 +0000
954 obsolete: pruned
954 obsolete: pruned
955 summary: add obsolete_e
955 summary: add obsolete_e
956
956
957
957
958 test the obsolete labels
958 test the obsolete labels
959
959
960 $ hg log --config ui.logtemplate= --color=debug -r 'phasedivergent()'
960 $ hg log --config ui.logtemplate= --color=debug -r 'phasedivergent()'
961 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent|changeset: 7:50c51b361e60]
961 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent|changeset: 7:50c51b361e60]
962 [log.user|user: test]
962 [log.user|user: test]
963 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
963 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
964 [log.instability|instability: orphan, phase-divergent]
964 [log.instability|instability: orphan, phase-divergent]
965 [log.summary|summary: add babar]
965 [log.summary|summary: add babar]
966
966
967
967
968 $ hg log -T default -r 'phasedivergent()' --color=debug
968 $ hg log -T default -r 'phasedivergent()' --color=debug
969 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent|changeset: 7:50c51b361e60]
969 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent|changeset: 7:50c51b361e60]
970 [log.user|user: test]
970 [log.user|user: test]
971 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
971 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
972 [log.instability|instability: orphan, phase-divergent]
972 [log.instability|instability: orphan, phase-divergent]
973 [log.summary|summary: add babar]
973 [log.summary|summary: add babar]
974
974
975
975
976 $ hg log --config ui.logtemplate= --color=debug -r "obsolete()"
976 $ hg log --config ui.logtemplate= --color=debug -r "obsolete()"
977 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
977 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
978 [log.parent changeset.draft|parent: 3:6f9641995072]
978 [log.parent changeset.draft|parent: 3:6f9641995072]
979 [log.user|user: test]
979 [log.user|user: test]
980 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
980 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
981 [log.obsfate|obsolete: pruned]
981 [log.obsfate|obsolete: pruned]
982 [log.summary|summary: add obsolete_e]
982 [log.summary|summary: add obsolete_e]
983
983
984
984
985 $ hg log -T default -r 'obsolete()' --color=debug
985 $ hg log -T default -r 'obsolete()' --color=debug
986 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
986 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
987 [log.parent changeset.draft|parent: 3:6f9641995072]
987 [log.parent changeset.draft|parent: 3:6f9641995072]
988 [log.user|user: test]
988 [log.user|user: test]
989 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
989 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
990 [log.obsfate|obsolete: pruned]
990 [log.obsfate|obsolete: pruned]
991 [log.summary|summary: add obsolete_e]
991 [log.summary|summary: add obsolete_e]
992
992
993
993
994 test summary output
994 test summary output
995
995
996 $ hg up -r 'phasedivergent() and orphan()'
996 $ hg up -r 'phasedivergent() and orphan()'
997 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
997 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
998 $ hg summary
998 $ hg summary
999 parent: 7:50c51b361e60 (orphan, phase-divergent)
999 parent: 7:50c51b361e60 (orphan, phase-divergent)
1000 add babar
1000 add babar
1001 branch: default
1001 branch: default
1002 commit: (clean)
1002 commit: (clean)
1003 update: 2 new changesets (update)
1003 update: 2 new changesets (update)
1004 phases: 4 draft
1004 phases: 4 draft
1005 orphan: 2 changesets
1005 orphan: 2 changesets
1006 phase-divergent: 1 changesets
1006 phase-divergent: 1 changesets
1007 $ hg up -r 'obsolete()'
1007 $ hg up -r 'obsolete()'
1008 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1008 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1009 $ hg summary
1009 $ hg summary
1010 parent: 6:3de5eca88c00 (obsolete)
1010 parent: 6:3de5eca88c00 (obsolete)
1011 add obsolete_e
1011 add obsolete_e
1012 branch: default
1012 branch: default
1013 commit: (clean)
1013 commit: (clean)
1014 update: 3 new changesets (update)
1014 update: 3 new changesets (update)
1015 phases: 4 draft
1015 phases: 4 draft
1016 orphan: 2 changesets
1016 orphan: 2 changesets
1017 phase-divergent: 1 changesets
1017 phase-divergent: 1 changesets
1018
1018
1019 #if serve
1019 #if serve
1020
1020
1021 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1021 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1022 $ cat hg.pid >> $DAEMON_PIDS
1022 $ cat hg.pid >> $DAEMON_PIDS
1023
1023
1024 check obsolete changeset
1024 check obsolete changeset
1025
1025
1026 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=paper' | grep '<span class="obsolete">'
1026 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=paper' | grep '<span class="obsolete">'
1027 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1027 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1028 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=coal' | grep '<span class="obsolete">'
1028 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=coal' | grep '<span class="obsolete">'
1029 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1029 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1030 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=gitweb' | grep '<span class="logtags">'
1030 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=gitweb' | grep '<span class="logtags">'
1031 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1031 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1032 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=monoblue' | grep '<span class="logtags">'
1032 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=monoblue' | grep '<span class="logtags">'
1033 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1033 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1034 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=spartan' | grep 'class="obsolete"'
1034 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=spartan' | grep 'class="obsolete"'
1035 <th class="obsolete">obsolete:</th>
1035 <th class="obsolete">obsolete:</th>
1036 <td class="obsolete">pruned</td>
1036 <td class="obsolete">pruned</td>
1037
1037
1038 check an obsolete changeset that has been rewritten
1038 check an obsolete changeset that has been rewritten
1039 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=paper' | grep rewritten
1039 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=paper' | grep rewritten
1040 <td>rewritten as <a href="/rev/3de5eca88c00?style=paper">3de5eca88c00</a> </td>
1040 <td>rewritten as <a href="/rev/3de5eca88c00?style=paper">3de5eca88c00</a> </td>
1041 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=coal' | grep rewritten
1041 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=coal' | grep rewritten
1042 <td>rewritten as <a href="/rev/3de5eca88c00?style=coal">3de5eca88c00</a> </td>
1042 <td>rewritten as <a href="/rev/3de5eca88c00?style=coal">3de5eca88c00</a> </td>
1043 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=gitweb' | grep rewritten
1043 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=gitweb' | grep rewritten
1044 <tr><td>obsolete</td><td>rewritten as <a class="list" href="/rev/3de5eca88c00?style=gitweb">3de5eca88c00</a> </td></tr>
1044 <tr><td>obsolete</td><td>rewritten as <a class="list" href="/rev/3de5eca88c00?style=gitweb">3de5eca88c00</a> </td></tr>
1045 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=monoblue' | grep rewritten
1045 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=monoblue' | grep rewritten
1046 <dt>obsolete</dt><dd>rewritten as <a href="/rev/3de5eca88c00?style=monoblue">3de5eca88c00</a> </dd>
1046 <dt>obsolete</dt><dd>rewritten as <a href="/rev/3de5eca88c00?style=monoblue">3de5eca88c00</a> </dd>
1047 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=spartan' | grep rewritten
1047 $ get-with-headers.py localhost:$HGPORT 'rev/cda648ca50f5?style=spartan' | grep rewritten
1048 <td class="obsolete">rewritten as <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a> </td>
1048 <td class="obsolete">rewritten as <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a> </td>
1049
1049
1050 check changeset with instabilities
1050 check changeset with instabilities
1051
1051
1052 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=paper' | grep '<span class="instability">'
1052 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=paper' | grep '<span class="instability">'
1053 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span>
1053 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span>
1054 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=coal' | grep '<span class="instability">'
1054 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=coal' | grep '<span class="instability">'
1055 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span>
1055 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span>
1056 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=gitweb' | grep '<span class="logtags">'
1056 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=gitweb' | grep '<span class="logtags">'
1057 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> </span>
1057 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> </span>
1058 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=monoblue' | grep '<span class="logtags">'
1058 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=monoblue' | grep '<span class="logtags">'
1059 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> </span>
1059 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> </span>
1060 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=spartan' | grep 'class="instabilities"'
1060 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=spartan' | grep 'class="instabilities"'
1061 <th class="instabilities">instabilities:</th>
1061 <th class="instabilities">instabilities:</th>
1062 <td class="instabilities">orphan phase-divergent </td>
1062 <td class="instabilities">orphan phase-divergent </td>
1063
1063
1064 $ killdaemons.py
1064 $ killdaemons.py
1065
1065
1066 $ rm hg.pid access.log errors.log
1066 $ rm hg.pid access.log errors.log
1067 #endif
1067 #endif
1068
1068
1069 Test incoming/outcoming with changesets obsoleted remotely, known locally
1069 Test incoming/outcoming with changesets obsoleted remotely, known locally
1070 ===============================================================================
1070 ===============================================================================
1071
1071
1072 This test issue 3805
1072 This test issue 3805
1073
1073
1074 $ hg init repo-issue3805
1074 $ hg init repo-issue3805
1075 $ cd repo-issue3805
1075 $ cd repo-issue3805
1076 $ echo "base" > base
1076 $ echo "base" > base
1077 $ hg ci -Am "base"
1077 $ hg ci -Am "base"
1078 adding base
1078 adding base
1079 $ echo "foo" > foo
1079 $ echo "foo" > foo
1080 $ hg ci -Am "A"
1080 $ hg ci -Am "A"
1081 adding foo
1081 adding foo
1082 $ hg clone . ../other-issue3805
1082 $ hg clone . ../other-issue3805
1083 updating to branch default
1083 updating to branch default
1084 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1084 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1085 $ echo "bar" >> foo
1085 $ echo "bar" >> foo
1086 $ hg ci --amend
1086 $ hg ci --amend
1087 $ cd ../other-issue3805
1087 $ cd ../other-issue3805
1088 $ hg log -G
1088 $ hg log -G
1089 @ 1:29f0c6921ddd (draft) [tip ] A
1089 @ 1:29f0c6921ddd (draft) [tip ] A
1090 |
1090 |
1091 o 0:d20a80d4def3 (draft) [ ] base
1091 o 0:d20a80d4def3 (draft) [ ] base
1092
1092
1093 $ hg log -G -R ../repo-issue3805
1093 $ hg log -G -R ../repo-issue3805
1094 @ 2:323a9c3ddd91 (draft) [tip ] A
1094 @ 2:323a9c3ddd91 (draft) [tip ] A
1095 |
1095 |
1096 o 0:d20a80d4def3 (draft) [ ] base
1096 o 0:d20a80d4def3 (draft) [ ] base
1097
1097
1098 $ hg incoming
1098 $ hg incoming
1099 comparing with $TESTTMP/tmpe/repo-issue3805
1099 comparing with $TESTTMP/tmpe/repo-issue3805
1100 searching for changes
1100 searching for changes
1101 2:323a9c3ddd91 (draft) [tip ] A
1101 2:323a9c3ddd91 (draft) [tip ] A
1102 $ hg incoming --bundle ../issue3805.hg
1102 $ hg incoming --bundle ../issue3805.hg
1103 comparing with $TESTTMP/tmpe/repo-issue3805
1103 comparing with $TESTTMP/tmpe/repo-issue3805
1104 searching for changes
1104 searching for changes
1105 2:323a9c3ddd91 (draft) [tip ] A
1105 2:323a9c3ddd91 (draft) [tip ] A
1106 $ hg outgoing
1106 $ hg outgoing
1107 comparing with $TESTTMP/tmpe/repo-issue3805
1107 comparing with $TESTTMP/tmpe/repo-issue3805
1108 searching for changes
1108 searching for changes
1109 1:29f0c6921ddd (draft) [tip ] A
1109 1:29f0c6921ddd (draft) [tip ] A
1110
1110
1111 #if serve
1111 #if serve
1112
1112
1113 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1113 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1114 $ cat hg.pid >> $DAEMON_PIDS
1114 $ cat hg.pid >> $DAEMON_PIDS
1115
1115
1116 $ hg incoming http://localhost:$HGPORT
1116 $ hg incoming http://localhost:$HGPORT
1117 comparing with http://localhost:$HGPORT/
1117 comparing with http://localhost:$HGPORT/
1118 searching for changes
1118 searching for changes
1119 2:323a9c3ddd91 (draft) [tip ] A
1119 2:323a9c3ddd91 (draft) [tip ] A
1120 $ hg outgoing http://localhost:$HGPORT
1120 $ hg outgoing http://localhost:$HGPORT
1121 comparing with http://localhost:$HGPORT/
1121 comparing with http://localhost:$HGPORT/
1122 searching for changes
1122 searching for changes
1123 1:29f0c6921ddd (draft) [tip ] A
1123 1:29f0c6921ddd (draft) [tip ] A
1124
1124
1125 $ killdaemons.py
1125 $ killdaemons.py
1126
1126
1127 #endif
1127 #endif
1128
1128
1129 This test issue 3814
1129 This test issue 3814
1130
1130
1131 (nothing to push but locally hidden changeset)
1131 (nothing to push but locally hidden changeset)
1132
1132
1133 $ cd ..
1133 $ cd ..
1134 $ hg init repo-issue3814
1134 $ hg init repo-issue3814
1135 $ cd repo-issue3805
1135 $ cd repo-issue3805
1136 $ hg push -r 323a9c3ddd91 ../repo-issue3814
1136 $ hg push -r 323a9c3ddd91 ../repo-issue3814
1137 pushing to ../repo-issue3814
1137 pushing to ../repo-issue3814
1138 searching for changes
1138 searching for changes
1139 adding changesets
1139 adding changesets
1140 adding manifests
1140 adding manifests
1141 adding file changes
1141 adding file changes
1142 added 2 changesets with 2 changes to 2 files
1142 added 2 changesets with 2 changes to 2 files
1143 1 new obsolescence markers
1143 1 new obsolescence markers
1144 $ hg out ../repo-issue3814
1144 $ hg out ../repo-issue3814
1145 comparing with ../repo-issue3814
1145 comparing with ../repo-issue3814
1146 searching for changes
1146 searching for changes
1147 no changes found
1147 no changes found
1148 [1]
1148 [1]
1149
1149
1150 Test that a local tag blocks a changeset from being hidden
1150 Test that a local tag blocks a changeset from being hidden
1151
1151
1152 $ hg tag -l visible -r 1 --hidden
1152 $ hg tag -l visible -r 1 --hidden
1153 $ hg log -G
1153 $ hg log -G
1154 @ 2:323a9c3ddd91 (draft) [tip ] A
1154 @ 2:323a9c3ddd91 (draft) [tip ] A
1155 |
1155 |
1156 | x 1:29f0c6921ddd (draft *obsolete*) [visible ] A [rewritten using amend as 2:323a9c3ddd91]
1156 | x 1:29f0c6921ddd (draft *obsolete*) [visible ] A [rewritten using amend as 2:323a9c3ddd91]
1157 |/
1157 |/
1158 o 0:d20a80d4def3 (draft) [ ] base
1158 o 0:d20a80d4def3 (draft) [ ] base
1159
1159
1160 Test that removing a local tag does not cause some commands to fail
1160 Test that removing a local tag does not cause some commands to fail
1161
1161
1162 $ hg tag -l -r tip tiptag
1162 $ hg tag -l -r tip tiptag
1163 $ hg tags
1163 $ hg tags
1164 tiptag 2:323a9c3ddd91
1164 tiptag 2:323a9c3ddd91
1165 tip 2:323a9c3ddd91
1165 tip 2:323a9c3ddd91
1166 visible 1:29f0c6921ddd
1166 visible 1:29f0c6921ddd
1167 $ hg --config extensions.strip= strip -r tip --no-backup
1167 $ hg --config extensions.strip= strip -r tip --no-backup
1168 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1168 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1169 $ hg tags
1169 $ hg tags
1170 visible 1:29f0c6921ddd
1170 visible 1:29f0c6921ddd
1171 tip 1:29f0c6921ddd
1171 tip 1:29f0c6921ddd
1172
1172
1173 Test bundle overlay onto hidden revision
1173 Test bundle overlay onto hidden revision
1174
1174
1175 $ cd ..
1175 $ cd ..
1176 $ hg init repo-bundleoverlay
1176 $ hg init repo-bundleoverlay
1177 $ cd repo-bundleoverlay
1177 $ cd repo-bundleoverlay
1178 $ echo "A" > foo
1178 $ echo "A" > foo
1179 $ hg ci -Am "A"
1179 $ hg ci -Am "A"
1180 adding foo
1180 adding foo
1181 $ echo "B" >> foo
1181 $ echo "B" >> foo
1182 $ hg ci -m "B"
1182 $ hg ci -m "B"
1183 $ hg up 0
1183 $ hg up 0
1184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1185 $ echo "C" >> foo
1185 $ echo "C" >> foo
1186 $ hg ci -m "C"
1186 $ hg ci -m "C"
1187 created new head
1187 created new head
1188 $ hg log -G
1188 $ hg log -G
1189 @ 2:c186d7714947 (draft) [tip ] C
1189 @ 2:c186d7714947 (draft) [tip ] C
1190 |
1190 |
1191 | o 1:44526ebb0f98 (draft) [ ] B
1191 | o 1:44526ebb0f98 (draft) [ ] B
1192 |/
1192 |/
1193 o 0:4b34ecfb0d56 (draft) [ ] A
1193 o 0:4b34ecfb0d56 (draft) [ ] A
1194
1194
1195
1195
1196 $ hg clone -r1 . ../other-bundleoverlay
1196 $ hg clone -r1 . ../other-bundleoverlay
1197 adding changesets
1197 adding changesets
1198 adding manifests
1198 adding manifests
1199 adding file changes
1199 adding file changes
1200 added 2 changesets with 2 changes to 1 files
1200 added 2 changesets with 2 changes to 1 files
1201 new changesets 4b34ecfb0d56:44526ebb0f98
1201 new changesets 4b34ecfb0d56:44526ebb0f98
1202 updating to branch default
1202 updating to branch default
1203 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1203 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1204 $ cd ../other-bundleoverlay
1204 $ cd ../other-bundleoverlay
1205 $ echo "B+" >> foo
1205 $ echo "B+" >> foo
1206 $ hg ci --amend -m "B+"
1206 $ hg ci --amend -m "B+"
1207 $ hg log -G --hidden
1207 $ hg log -G --hidden
1208 @ 2:b7d587542d40 (draft) [tip ] B+
1208 @ 2:b7d587542d40 (draft) [tip ] B+
1209 |
1209 |
1210 | x 1:44526ebb0f98 (draft *obsolete*) [ ] B [rewritten using amend as 2:b7d587542d40]
1210 | x 1:44526ebb0f98 (draft *obsolete*) [ ] B [rewritten using amend as 2:b7d587542d40]
1211 |/
1211 |/
1212 o 0:4b34ecfb0d56 (draft) [ ] A
1212 o 0:4b34ecfb0d56 (draft) [ ] A
1213
1213
1214
1214
1215 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
1215 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
1216 comparing with ../repo-bundleoverlay
1216 comparing with ../repo-bundleoverlay
1217 searching for changes
1217 searching for changes
1218 1:44526ebb0f98 (draft) [ ] B
1218 1:44526ebb0f98 (draft) [ ] B
1219 2:c186d7714947 (draft) [tip ] C
1219 2:c186d7714947 (draft) [tip ] C
1220 $ hg log -G -R ../bundleoverlay.hg
1220 $ hg log -G -R ../bundleoverlay.hg
1221 o 3:c186d7714947 (draft) [tip ] C
1221 o 3:c186d7714947 (draft) [tip ] C
1222 |
1222 |
1223 | @ 2:b7d587542d40 (draft) [ ] B+
1223 | @ 2:b7d587542d40 (draft) [ ] B+
1224 |/
1224 |/
1225 o 0:4b34ecfb0d56 (draft) [ ] A
1225 o 0:4b34ecfb0d56 (draft) [ ] A
1226
1226
1227
1227
1228 #if serve
1228 #if serve
1229
1229
1230 Test issue 4506
1230 Test issue 4506
1231
1231
1232 $ cd ..
1232 $ cd ..
1233 $ hg init repo-issue4506
1233 $ hg init repo-issue4506
1234 $ cd repo-issue4506
1234 $ cd repo-issue4506
1235 $ echo "0" > foo
1235 $ echo "0" > foo
1236 $ hg add foo
1236 $ hg add foo
1237 $ hg ci -m "content-0"
1237 $ hg ci -m "content-0"
1238
1238
1239 $ hg up null
1239 $ hg up null
1240 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1240 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1241 $ echo "1" > bar
1241 $ echo "1" > bar
1242 $ hg add bar
1242 $ hg add bar
1243 $ hg ci -m "content-1"
1243 $ hg ci -m "content-1"
1244 created new head
1244 created new head
1245 $ hg up 0
1245 $ hg up 0
1246 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1246 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1247 $ hg graft 1
1247 $ hg graft 1
1248 grafting 1:1c9eddb02162 "content-1" (tip)
1248 grafting 1:1c9eddb02162 "content-1" (tip)
1249
1249
1250 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
1250 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
1251 obsoleted 1 changesets
1251 obsoleted 1 changesets
1252
1252
1253 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1253 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1254 $ cat hg.pid >> $DAEMON_PIDS
1254 $ cat hg.pid >> $DAEMON_PIDS
1255
1255
1256 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/1'
1256 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/1'
1257 404 Not Found
1257 404 Not Found
1258 [1]
1258 [1]
1259 $ get-with-headers.py --headeronly localhost:$HGPORT 'file/tip/bar'
1259 $ get-with-headers.py --headeronly localhost:$HGPORT 'file/tip/bar'
1260 200 Script output follows
1260 200 Script output follows
1261 $ get-with-headers.py --headeronly localhost:$HGPORT 'annotate/tip/bar'
1261 $ get-with-headers.py --headeronly localhost:$HGPORT 'annotate/tip/bar'
1262 200 Script output follows
1262 200 Script output follows
1263
1263
1264 $ killdaemons.py
1264 $ killdaemons.py
1265
1265
1266 #endif
1266 #endif
1267
1267
1268 Test heads computation on pending index changes with obsolescence markers
1268 Test heads computation on pending index changes with obsolescence markers
1269 $ cd ..
1269 $ cd ..
1270 $ cat >$TESTTMP/test_extension.py << EOF
1270 $ cat >$TESTTMP/test_extension.py << EOF
1271 > from __future__ import absolute_import
1271 > from __future__ import absolute_import
1272 > from mercurial.i18n import _
1272 > from mercurial.i18n import _
1273 > from mercurial import cmdutil, registrar
1273 > from mercurial import cmdutil, registrar
1274 >
1274 >
1275 > cmdtable = {}
1275 > cmdtable = {}
1276 > command = registrar.command(cmdtable)
1276 > command = registrar.command(cmdtable)
1277 > @command(b"amendtransient",[], _('hg amendtransient [rev]'))
1277 > @command(b"amendtransient",[], _('hg amendtransient [rev]'))
1278 > def amend(ui, repo, *pats, **opts):
1278 > def amend(ui, repo, *pats, **opts):
1279 > opts['message'] = 'Test'
1279 > opts['message'] = 'Test'
1280 > opts['logfile'] = None
1280 > opts['logfile'] = None
1281 > cmdutil.amend(ui, repo, repo['.'], {}, pats, opts)
1281 > cmdutil.amend(ui, repo, repo['.'], {}, pats, opts)
1282 > ui.write('%s\n' % repo.changelog.headrevs())
1282 > ui.write('%s\n' % repo.changelog.headrevs())
1283 > EOF
1283 > EOF
1284 $ cat >> $HGRCPATH << EOF
1284 $ cat >> $HGRCPATH << EOF
1285 > [extensions]
1285 > [extensions]
1286 > testextension=$TESTTMP/test_extension.py
1286 > testextension=$TESTTMP/test_extension.py
1287 > EOF
1287 > EOF
1288 $ hg init repo-issue-nativerevs-pending-changes
1288 $ hg init repo-issue-nativerevs-pending-changes
1289 $ cd repo-issue-nativerevs-pending-changes
1289 $ cd repo-issue-nativerevs-pending-changes
1290 $ mkcommit a
1290 $ mkcommit a
1291 $ mkcommit b
1291 $ mkcommit b
1292 $ hg up ".^"
1292 $ hg up ".^"
1293 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1293 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1294 $ echo aa > a
1294 $ echo aa > a
1295 $ hg amendtransient
1295 $ hg amendtransient
1296 [1, 2]
1296 [1, 2]
1297
1297
1298 Test cache consistency for the visible filter
1298 Test cache consistency for the visible filter
1299 1) We want to make sure that the cached filtered revs are invalidated when
1299 1) We want to make sure that the cached filtered revs are invalidated when
1300 bookmarks change
1300 bookmarks change
1301 $ cd ..
1301 $ cd ..
1302 $ cat >$TESTTMP/test_extension.py << EOF
1302 $ cat >$TESTTMP/test_extension.py << EOF
1303 > from __future__ import absolute_import, print_function
1303 > from __future__ import absolute_import, print_function
1304 > import weakref
1304 > import weakref
1305 > from mercurial import (
1305 > from mercurial import (
1306 > bookmarks,
1306 > bookmarks,
1307 > cmdutil,
1307 > cmdutil,
1308 > extensions,
1308 > extensions,
1309 > repoview,
1309 > repoview,
1310 > )
1310 > )
1311 > def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
1311 > def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
1312 > reporef = weakref.ref(bkmstoreinst._repo)
1312 > reporef = weakref.ref(bkmstoreinst._repo)
1313 > def trhook(tr):
1313 > def trhook(tr):
1314 > repo = reporef()
1314 > repo = reporef()
1315 > hidden1 = repoview.computehidden(repo)
1315 > hidden1 = repoview.computehidden(repo)
1316 > hidden = repoview.filterrevs(repo, 'visible')
1316 > hidden = repoview.filterrevs(repo, 'visible')
1317 > if sorted(hidden1) != sorted(hidden):
1317 > if sorted(hidden1) != sorted(hidden):
1318 > print("cache inconsistency")
1318 > print("cache inconsistency")
1319 > bkmstoreinst._repo.currenttransaction().addpostclose('test_extension', trhook)
1319 > bkmstoreinst._repo.currenttransaction().addpostclose('test_extension', trhook)
1320 > orig(bkmstoreinst, *args, **kwargs)
1320 > orig(bkmstoreinst, *args, **kwargs)
1321 > def extsetup(ui):
1321 > def extsetup(ui):
1322 > extensions.wrapfunction(bookmarks.bmstore, '_recordchange',
1322 > extensions.wrapfunction(bookmarks.bmstore, '_recordchange',
1323 > _bookmarkchanged)
1323 > _bookmarkchanged)
1324 > EOF
1324 > EOF
1325
1325
1326 $ hg init repo-cache-inconsistency
1326 $ hg init repo-cache-inconsistency
1327 $ cd repo-issue-nativerevs-pending-changes
1327 $ cd repo-issue-nativerevs-pending-changes
1328 $ mkcommit a
1328 $ mkcommit a
1329 a already tracked!
1329 a already tracked!
1330 $ mkcommit b
1330 $ mkcommit b
1331 $ hg id
1331 $ hg id
1332 13bedc178fce tip
1332 13bedc178fce tip
1333 $ echo "hello" > b
1333 $ echo "hello" > b
1334 $ hg commit --amend -m "message"
1334 $ hg commit --amend -m "message"
1335 $ hg book bookb -r 13bedc178fce --hidden
1335 $ hg book bookb -r 13bedc178fce --hidden
1336 $ hg log -r 13bedc178fce
1336 $ hg log -r 13bedc178fce
1337 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753]
1337 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753]
1338 $ hg book -d bookb
1338 $ hg book -d bookb
1339 $ hg log -r 13bedc178fce
1339 $ hg log -r 13bedc178fce
1340 abort: hidden revision '13bedc178fce'!
1340 abort: hidden revision '13bedc178fce' was rewritten as: a9b1f8652753!
1341 (use --hidden to access hidden revisions)
1341 (use --hidden to access hidden revisions)
1342 [255]
1342 [255]
1343
1343
1344 Empty out the test extension, as it isn't compatible with later parts
1344 Empty out the test extension, as it isn't compatible with later parts
1345 of the test.
1345 of the test.
1346 $ echo > $TESTTMP/test_extension.py
1346 $ echo > $TESTTMP/test_extension.py
1347
1347
1348 Test ability to pull changeset with locally applying obsolescence markers
1348 Test ability to pull changeset with locally applying obsolescence markers
1349 (issue4945)
1349 (issue4945)
1350
1350
1351 $ cd ..
1351 $ cd ..
1352 $ hg init issue4845
1352 $ hg init issue4845
1353 $ cd issue4845
1353 $ cd issue4845
1354
1354
1355 $ echo foo > f0
1355 $ echo foo > f0
1356 $ hg add f0
1356 $ hg add f0
1357 $ hg ci -m '0'
1357 $ hg ci -m '0'
1358 $ echo foo > f1
1358 $ echo foo > f1
1359 $ hg add f1
1359 $ hg add f1
1360 $ hg ci -m '1'
1360 $ hg ci -m '1'
1361 $ echo foo > f2
1361 $ echo foo > f2
1362 $ hg add f2
1362 $ hg add f2
1363 $ hg ci -m '2'
1363 $ hg ci -m '2'
1364
1364
1365 $ echo bar > f2
1365 $ echo bar > f2
1366 $ hg commit --amend --config experimental.evolution.createmarkers=True
1366 $ hg commit --amend --config experimental.evolution.createmarkers=True
1367 $ hg log -G
1367 $ hg log -G
1368 @ 3:b0551702f918 (draft) [tip ] 2
1368 @ 3:b0551702f918 (draft) [tip ] 2
1369 |
1369 |
1370 o 1:e016b03fd86f (draft) [ ] 1
1370 o 1:e016b03fd86f (draft) [ ] 1
1371 |
1371 |
1372 o 0:a78f55e5508c (draft) [ ] 0
1372 o 0:a78f55e5508c (draft) [ ] 0
1373
1373
1374 $ hg log -G --hidden
1374 $ hg log -G --hidden
1375 @ 3:b0551702f918 (draft) [tip ] 2
1375 @ 3:b0551702f918 (draft) [tip ] 2
1376 |
1376 |
1377 | x 2:e008cf283490 (draft *obsolete*) [ ] 2 [rewritten using amend as 3:b0551702f918]
1377 | x 2:e008cf283490 (draft *obsolete*) [ ] 2 [rewritten using amend as 3:b0551702f918]
1378 |/
1378 |/
1379 o 1:e016b03fd86f (draft) [ ] 1
1379 o 1:e016b03fd86f (draft) [ ] 1
1380 |
1380 |
1381 o 0:a78f55e5508c (draft) [ ] 0
1381 o 0:a78f55e5508c (draft) [ ] 0
1382
1382
1383
1383
1384 $ hg strip --hidden -r 2 --config extensions.strip= --config devel.strip-obsmarkers=no
1384 $ hg strip --hidden -r 2 --config extensions.strip= --config devel.strip-obsmarkers=no
1385 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e008cf283490-ede36964-backup.hg
1385 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e008cf283490-ede36964-backup.hg
1386 $ hg debugobsolete
1386 $ hg debugobsolete
1387 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1387 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1388 $ hg log -G
1388 $ hg log -G
1389 @ 2:b0551702f918 (draft) [tip ] 2
1389 @ 2:b0551702f918 (draft) [tip ] 2
1390 |
1390 |
1391 o 1:e016b03fd86f (draft) [ ] 1
1391 o 1:e016b03fd86f (draft) [ ] 1
1392 |
1392 |
1393 o 0:a78f55e5508c (draft) [ ] 0
1393 o 0:a78f55e5508c (draft) [ ] 0
1394
1394
1395 $ hg log -G --hidden
1395 $ hg log -G --hidden
1396 @ 2:b0551702f918 (draft) [tip ] 2
1396 @ 2:b0551702f918 (draft) [tip ] 2
1397 |
1397 |
1398 o 1:e016b03fd86f (draft) [ ] 1
1398 o 1:e016b03fd86f (draft) [ ] 1
1399 |
1399 |
1400 o 0:a78f55e5508c (draft) [ ] 0
1400 o 0:a78f55e5508c (draft) [ ] 0
1401
1401
1402 $ hg debugbundle .hg/strip-backup/e008cf283490-*-backup.hg
1402 $ hg debugbundle .hg/strip-backup/e008cf283490-*-backup.hg
1403 Stream params: {Compression: BZ}
1403 Stream params: {Compression: BZ}
1404 changegroup -- {nbchanges: 1, version: 02}
1404 changegroup -- {nbchanges: 1, version: 02}
1405 e008cf2834908e5d6b0f792a9d4b0e2272260fb8
1405 e008cf2834908e5d6b0f792a9d4b0e2272260fb8
1406 phase-heads -- {}
1406 phase-heads -- {}
1407 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 draft
1407 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 draft
1408
1408
1409 $ hg pull .hg/strip-backup/e008cf283490-*-backup.hg
1409 $ hg pull .hg/strip-backup/e008cf283490-*-backup.hg
1410 pulling from .hg/strip-backup/e008cf283490-ede36964-backup.hg
1410 pulling from .hg/strip-backup/e008cf283490-ede36964-backup.hg
1411 searching for changes
1411 searching for changes
1412 no changes found
1412 no changes found
1413 $ hg debugobsolete
1413 $ hg debugobsolete
1414 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1414 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1415 $ hg log -G
1415 $ hg log -G
1416 @ 2:b0551702f918 (draft) [tip ] 2
1416 @ 2:b0551702f918 (draft) [tip ] 2
1417 |
1417 |
1418 o 1:e016b03fd86f (draft) [ ] 1
1418 o 1:e016b03fd86f (draft) [ ] 1
1419 |
1419 |
1420 o 0:a78f55e5508c (draft) [ ] 0
1420 o 0:a78f55e5508c (draft) [ ] 0
1421
1421
1422 $ hg log -G --hidden
1422 $ hg log -G --hidden
1423 @ 2:b0551702f918 (draft) [tip ] 2
1423 @ 2:b0551702f918 (draft) [tip ] 2
1424 |
1424 |
1425 o 1:e016b03fd86f (draft) [ ] 1
1425 o 1:e016b03fd86f (draft) [ ] 1
1426 |
1426 |
1427 o 0:a78f55e5508c (draft) [ ] 0
1427 o 0:a78f55e5508c (draft) [ ] 0
1428
1428
1429
1429
1430 Testing that strip remove markers:
1430 Testing that strip remove markers:
1431
1431
1432 $ hg strip -r 1 --config extensions.strip=
1432 $ hg strip -r 1 --config extensions.strip=
1433 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1433 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1434 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e016b03fd86f-65ede734-backup.hg
1434 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e016b03fd86f-65ede734-backup.hg
1435 $ hg debugobsolete
1435 $ hg debugobsolete
1436 $ hg log -G
1436 $ hg log -G
1437 @ 0:a78f55e5508c (draft) [tip ] 0
1437 @ 0:a78f55e5508c (draft) [tip ] 0
1438
1438
1439 $ hg log -G --hidden
1439 $ hg log -G --hidden
1440 @ 0:a78f55e5508c (draft) [tip ] 0
1440 @ 0:a78f55e5508c (draft) [tip ] 0
1441
1441
1442 $ hg debugbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1442 $ hg debugbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1443 Stream params: {Compression: BZ}
1443 Stream params: {Compression: BZ}
1444 changegroup -- {nbchanges: 2, version: 02}
1444 changegroup -- {nbchanges: 2, version: 02}
1445 e016b03fd86fcccc54817d120b90b751aaf367d6
1445 e016b03fd86fcccc54817d120b90b751aaf367d6
1446 b0551702f918510f01ae838ab03a463054c67b46
1446 b0551702f918510f01ae838ab03a463054c67b46
1447 obsmarkers -- {}
1447 obsmarkers -- {}
1448 version: 1 (92 bytes)
1448 version: 1 (92 bytes)
1449 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1449 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1450 phase-heads -- {}
1450 phase-heads -- {}
1451 b0551702f918510f01ae838ab03a463054c67b46 draft
1451 b0551702f918510f01ae838ab03a463054c67b46 draft
1452
1452
1453 $ hg unbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1453 $ hg unbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1454 adding changesets
1454 adding changesets
1455 adding manifests
1455 adding manifests
1456 adding file changes
1456 adding file changes
1457 added 2 changesets with 2 changes to 2 files
1457 added 2 changesets with 2 changes to 2 files
1458 1 new obsolescence markers
1458 1 new obsolescence markers
1459 new changesets e016b03fd86f:b0551702f918
1459 new changesets e016b03fd86f:b0551702f918
1460 (run 'hg update' to get a working copy)
1460 (run 'hg update' to get a working copy)
1461 $ hg debugobsolete | sort
1461 $ hg debugobsolete | sort
1462 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1462 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1463 $ hg log -G
1463 $ hg log -G
1464 o 2:b0551702f918 (draft) [tip ] 2
1464 o 2:b0551702f918 (draft) [tip ] 2
1465 |
1465 |
1466 o 1:e016b03fd86f (draft) [ ] 1
1466 o 1:e016b03fd86f (draft) [ ] 1
1467 |
1467 |
1468 @ 0:a78f55e5508c (draft) [ ] 0
1468 @ 0:a78f55e5508c (draft) [ ] 0
1469
1469
1470 $ hg log -G --hidden
1470 $ hg log -G --hidden
1471 o 2:b0551702f918 (draft) [tip ] 2
1471 o 2:b0551702f918 (draft) [tip ] 2
1472 |
1472 |
1473 o 1:e016b03fd86f (draft) [ ] 1
1473 o 1:e016b03fd86f (draft) [ ] 1
1474 |
1474 |
1475 @ 0:a78f55e5508c (draft) [ ] 0
1475 @ 0:a78f55e5508c (draft) [ ] 0
1476
1476
1477 Test that 'hg debugobsolete --index --rev' can show indices of obsmarkers when
1477 Test that 'hg debugobsolete --index --rev' can show indices of obsmarkers when
1478 only a subset of those are displayed (because of --rev option)
1478 only a subset of those are displayed (because of --rev option)
1479 $ hg init doindexrev
1479 $ hg init doindexrev
1480 $ cd doindexrev
1480 $ cd doindexrev
1481 $ echo a > a
1481 $ echo a > a
1482 $ hg ci -Am a
1482 $ hg ci -Am a
1483 adding a
1483 adding a
1484 $ hg ci --amend -m aa
1484 $ hg ci --amend -m aa
1485 $ echo b > b
1485 $ echo b > b
1486 $ hg ci -Am b
1486 $ hg ci -Am b
1487 adding b
1487 adding b
1488 $ hg ci --amend -m bb
1488 $ hg ci --amend -m bb
1489 $ echo c > c
1489 $ echo c > c
1490 $ hg ci -Am c
1490 $ hg ci -Am c
1491 adding c
1491 adding c
1492 $ hg ci --amend -m cc
1492 $ hg ci --amend -m cc
1493 $ echo d > d
1493 $ echo d > d
1494 $ hg ci -Am d
1494 $ hg ci -Am d
1495 adding d
1495 adding d
1496 $ hg ci --amend -m dd --config experimental.evolution.track-operation=1
1496 $ hg ci --amend -m dd --config experimental.evolution.track-operation=1
1497 $ hg debugobsolete --index --rev "3+7"
1497 $ hg debugobsolete --index --rev "3+7"
1498 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1498 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1499 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1499 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1500 $ hg debugobsolete --index --rev "3+7" -Tjson
1500 $ hg debugobsolete --index --rev "3+7" -Tjson
1501 [
1501 [
1502 {
1502 {
1503 "date": [0.0, 0],
1503 "date": [0.0, 0],
1504 "flag": 0,
1504 "flag": 0,
1505 "index": 1,
1505 "index": 1,
1506 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1506 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1507 "prednode": "6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1",
1507 "prednode": "6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1",
1508 "succnodes": ["d27fb9b066076fd921277a4b9e8b9cb48c95bc6a"]
1508 "succnodes": ["d27fb9b066076fd921277a4b9e8b9cb48c95bc6a"]
1509 },
1509 },
1510 {
1510 {
1511 "date": [0.0, 0],
1511 "date": [0.0, 0],
1512 "flag": 0,
1512 "flag": 0,
1513 "index": 3,
1513 "index": 3,
1514 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1514 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1515 "prednode": "4715cf767440ed891755448016c2b8cf70760c30",
1515 "prednode": "4715cf767440ed891755448016c2b8cf70760c30",
1516 "succnodes": ["7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d"]
1516 "succnodes": ["7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d"]
1517 }
1517 }
1518 ]
1518 ]
1519
1519
1520 Test the --delete option of debugobsolete command
1520 Test the --delete option of debugobsolete command
1521 $ hg debugobsolete --index
1521 $ hg debugobsolete --index
1522 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1522 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1523 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1523 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1524 2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1524 2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1525 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1525 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1526 $ hg debugobsolete --delete 1 --delete 3
1526 $ hg debugobsolete --delete 1 --delete 3
1527 deleted 2 obsolescence markers
1527 deleted 2 obsolescence markers
1528 $ hg debugobsolete
1528 $ hg debugobsolete
1529 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1529 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1530 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1530 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1531
1531
1532 Test adding changeset after obsmarkers affecting it
1532 Test adding changeset after obsmarkers affecting it
1533 (eg: during pull, or unbundle)
1533 (eg: during pull, or unbundle)
1534
1534
1535 $ mkcommit e
1535 $ mkcommit e
1536 $ hg bundle -r . --base .~1 ../bundle-2.hg
1536 $ hg bundle -r . --base .~1 ../bundle-2.hg
1537 1 changesets found
1537 1 changesets found
1538 $ getid .
1538 $ getid .
1539 $ hg --config extensions.strip= strip -r .
1539 $ hg --config extensions.strip= strip -r .
1540 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1540 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1541 saved backup bundle to $TESTTMP/tmpe/issue4845/doindexrev/.hg/strip-backup/9bc153528424-ee80edd4-backup.hg
1541 saved backup bundle to $TESTTMP/tmpe/issue4845/doindexrev/.hg/strip-backup/9bc153528424-ee80edd4-backup.hg
1542 $ hg debugobsolete 9bc153528424ea266d13e57f9ff0d799dfe61e4b
1542 $ hg debugobsolete 9bc153528424ea266d13e57f9ff0d799dfe61e4b
1543 $ hg unbundle ../bundle-2.hg
1543 $ hg unbundle ../bundle-2.hg
1544 adding changesets
1544 adding changesets
1545 adding manifests
1545 adding manifests
1546 adding file changes
1546 adding file changes
1547 added 1 changesets with 1 changes to 1 files
1547 added 1 changesets with 1 changes to 1 files
1548 (run 'hg update' to get a working copy)
1548 (run 'hg update' to get a working copy)
1549 $ hg log -G
1549 $ hg log -G
1550 @ 7:7ae79c5d60f0 (draft) [tip ] dd
1550 @ 7:7ae79c5d60f0 (draft) [tip ] dd
1551 |
1551 |
1552 | o 6:4715cf767440 (draft) [ ] d
1552 | o 6:4715cf767440 (draft) [ ] d
1553 |/
1553 |/
1554 o 5:29346082e4a9 (draft) [ ] cc
1554 o 5:29346082e4a9 (draft) [ ] cc
1555 |
1555 |
1556 o 3:d27fb9b06607 (draft) [ ] bb
1556 o 3:d27fb9b06607 (draft) [ ] bb
1557 |
1557 |
1558 | o 2:6fdef60fcbab (draft) [ ] b
1558 | o 2:6fdef60fcbab (draft) [ ] b
1559 |/
1559 |/
1560 o 1:f9bd49731b0b (draft) [ ] aa
1560 o 1:f9bd49731b0b (draft) [ ] aa
1561
1561
1562
1562
1563 $ cd ..
1563 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now