##// END OF EJS Templates
graphlog: use '%' only if there are *unresolved* conflicts...
Martin von Zweigbergk -
r46020:85b03b1e default
parent child Browse files
Show More
@@ -1,992 +1,992 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from .node import (
12 12 hex,
13 13 nullid,
14 14 wdirid,
15 15 wdirrev,
16 16 )
17 17
18 18 from . import (
19 19 diffutil,
20 20 encoding,
21 21 error,
22 22 hbisect,
23 23 i18n,
24 24 obsutil,
25 25 patch,
26 26 pycompat,
27 27 registrar,
28 28 scmutil,
29 29 templateutil,
30 30 util,
31 31 )
32 32 from .utils import stringutil
33 33
34 34 _hybrid = templateutil.hybrid
35 35 hybriddict = templateutil.hybriddict
36 36 hybridlist = templateutil.hybridlist
37 37 compatdict = templateutil.compatdict
38 38 compatlist = templateutil.compatlist
39 39 _showcompatlist = templateutil._showcompatlist
40 40
41 41
42 42 def getlatesttags(context, mapping, pattern=None):
43 43 '''return date, distance and name for the latest tag of rev'''
44 44 repo = context.resource(mapping, b'repo')
45 45 ctx = context.resource(mapping, b'ctx')
46 46 cache = context.resource(mapping, b'cache')
47 47
48 48 cachename = b'latesttags'
49 49 if pattern is not None:
50 50 cachename += b'-' + pattern
51 51 match = stringutil.stringmatcher(pattern)[2]
52 52 else:
53 53 match = util.always
54 54
55 55 if cachename not in cache:
56 56 # Cache mapping from rev to a tuple with tag date, tag
57 57 # distance and tag name
58 58 cache[cachename] = {-1: (0, 0, [b'null'])}
59 59 latesttags = cache[cachename]
60 60
61 61 rev = ctx.rev()
62 62 todo = [rev]
63 63 while todo:
64 64 rev = todo.pop()
65 65 if rev in latesttags:
66 66 continue
67 67 ctx = repo[rev]
68 68 tags = [
69 69 t
70 70 for t in ctx.tags()
71 71 if (repo.tagtype(t) and repo.tagtype(t) != b'local' and match(t))
72 72 ]
73 73 if tags:
74 74 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
75 75 continue
76 76 try:
77 77 ptags = [latesttags[p.rev()] for p in ctx.parents()]
78 78 if len(ptags) > 1:
79 79 if ptags[0][2] == ptags[1][2]:
80 80 # The tuples are laid out so the right one can be found by
81 81 # comparison in this case.
82 82 pdate, pdist, ptag = max(ptags)
83 83 else:
84 84
85 85 def key(x):
86 86 tag = x[2][0]
87 87 if ctx.rev() is None:
88 88 # only() doesn't support wdir
89 89 prevs = [c.rev() for c in ctx.parents()]
90 90 changes = repo.revs(b'only(%ld, %s)', prevs, tag)
91 91 changessincetag = len(changes) + 1
92 92 else:
93 93 changes = repo.revs(b'only(%d, %s)', ctx.rev(), tag)
94 94 changessincetag = len(changes)
95 95 # Smallest number of changes since tag wins. Date is
96 96 # used as tiebreaker.
97 97 return [-changessincetag, x[0]]
98 98
99 99 pdate, pdist, ptag = max(ptags, key=key)
100 100 else:
101 101 pdate, pdist, ptag = ptags[0]
102 102 except KeyError:
103 103 # Cache miss - recurse
104 104 todo.append(rev)
105 105 todo.extend(p.rev() for p in ctx.parents())
106 106 continue
107 107 latesttags[rev] = pdate, pdist + 1, ptag
108 108 return latesttags[rev]
109 109
110 110
111 111 def getlogcolumns():
112 112 """Return a dict of log column labels"""
113 113 _ = pycompat.identity # temporarily disable gettext
114 114 # i18n: column positioning for "hg log"
115 115 columns = _(
116 116 b'bookmark: %s\n'
117 117 b'branch: %s\n'
118 118 b'changeset: %s\n'
119 119 b'copies: %s\n'
120 120 b'date: %s\n'
121 121 b'extra: %s=%s\n'
122 122 b'files+: %s\n'
123 123 b'files-: %s\n'
124 124 b'files: %s\n'
125 125 b'instability: %s\n'
126 126 b'manifest: %s\n'
127 127 b'obsolete: %s\n'
128 128 b'parent: %s\n'
129 129 b'phase: %s\n'
130 130 b'summary: %s\n'
131 131 b'tag: %s\n'
132 132 b'user: %s\n'
133 133 )
134 134 return dict(
135 135 zip(
136 136 [s.split(b':', 1)[0] for s in columns.splitlines()],
137 137 i18n._(columns).splitlines(True),
138 138 )
139 139 )
140 140
141 141
142 142 # basic internal templates
143 143 _changeidtmpl = b'{rev}:{node|formatnode}'
144 144
145 145 # default templates internally used for rendering of lists
146 146 defaulttempl = {
147 147 b'parent': _changeidtmpl + b' ',
148 148 b'manifest': _changeidtmpl,
149 149 b'file_copy': b'{name} ({source})',
150 150 b'envvar': b'{key}={value}',
151 151 b'extra': b'{key}={value|stringescape}',
152 152 }
153 153 # filecopy is preserved for compatibility reasons
154 154 defaulttempl[b'filecopy'] = defaulttempl[b'file_copy']
155 155
156 156 # keywords are callables (see registrar.templatekeyword for details)
157 157 keywords = {}
158 158 templatekeyword = registrar.templatekeyword(keywords)
159 159
160 160
161 161 @templatekeyword(b'author', requires={b'ctx'})
162 162 def showauthor(context, mapping):
163 163 """Alias for ``{user}``"""
164 164 return showuser(context, mapping)
165 165
166 166
167 167 @templatekeyword(b'bisect', requires={b'repo', b'ctx'})
168 168 def showbisect(context, mapping):
169 169 """String. The changeset bisection status."""
170 170 repo = context.resource(mapping, b'repo')
171 171 ctx = context.resource(mapping, b'ctx')
172 172 return hbisect.label(repo, ctx.node())
173 173
174 174
175 175 @templatekeyword(b'branch', requires={b'ctx'})
176 176 def showbranch(context, mapping):
177 177 """String. The name of the branch on which the changeset was
178 178 committed.
179 179 """
180 180 ctx = context.resource(mapping, b'ctx')
181 181 return ctx.branch()
182 182
183 183
184 184 @templatekeyword(b'branches', requires={b'ctx'})
185 185 def showbranches(context, mapping):
186 186 """List of strings. The name of the branch on which the
187 187 changeset was committed. Will be empty if the branch name was
188 188 default. (DEPRECATED)
189 189 """
190 190 ctx = context.resource(mapping, b'ctx')
191 191 branch = ctx.branch()
192 192 if branch != b'default':
193 193 return compatlist(
194 194 context, mapping, b'branch', [branch], plural=b'branches'
195 195 )
196 196 return compatlist(context, mapping, b'branch', [], plural=b'branches')
197 197
198 198
199 199 @templatekeyword(b'bookmarks', requires={b'repo', b'ctx'})
200 200 def showbookmarks(context, mapping):
201 201 """List of strings. Any bookmarks associated with the
202 202 changeset. Also sets 'active', the name of the active bookmark.
203 203 """
204 204 repo = context.resource(mapping, b'repo')
205 205 ctx = context.resource(mapping, b'ctx')
206 206 bookmarks = ctx.bookmarks()
207 207 active = repo._activebookmark
208 208 makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active}
209 209 f = _showcompatlist(context, mapping, b'bookmark', bookmarks)
210 210 return _hybrid(f, bookmarks, makemap, pycompat.identity)
211 211
212 212
213 213 @templatekeyword(b'children', requires={b'ctx'})
214 214 def showchildren(context, mapping):
215 215 """List of strings. The children of the changeset."""
216 216 ctx = context.resource(mapping, b'ctx')
217 217 childrevs = [b'%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
218 218 return compatlist(
219 219 context, mapping, b'children', childrevs, element=b'child'
220 220 )
221 221
222 222
223 223 # Deprecated, but kept alive for help generation a purpose.
224 224 @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'})
225 225 def showcurrentbookmark(context, mapping):
226 226 """String. The active bookmark, if it is associated with the changeset.
227 227 (DEPRECATED)"""
228 228 return showactivebookmark(context, mapping)
229 229
230 230
231 231 @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'})
232 232 def showactivebookmark(context, mapping):
233 233 """String. The active bookmark, if it is associated with the changeset."""
234 234 repo = context.resource(mapping, b'repo')
235 235 ctx = context.resource(mapping, b'ctx')
236 236 active = repo._activebookmark
237 237 if active and active in ctx.bookmarks():
238 238 return active
239 239 return b''
240 240
241 241
242 242 @templatekeyword(b'date', requires={b'ctx'})
243 243 def showdate(context, mapping):
244 244 """Date information. The date when the changeset was committed."""
245 245 ctx = context.resource(mapping, b'ctx')
246 246 # the default string format is '<float(unixtime)><tzoffset>' because
247 247 # python-hglib splits date at decimal separator.
248 248 return templateutil.date(ctx.date(), showfmt=b'%d.0%d')
249 249
250 250
251 251 @templatekeyword(b'desc', requires={b'ctx'})
252 252 def showdescription(context, mapping):
253 253 """String. The text of the changeset description."""
254 254 ctx = context.resource(mapping, b'ctx')
255 255 s = ctx.description()
256 256 if isinstance(s, encoding.localstr):
257 257 # try hard to preserve utf-8 bytes
258 258 return encoding.tolocal(encoding.fromlocal(s).strip())
259 259 elif isinstance(s, encoding.safelocalstr):
260 260 return encoding.safelocalstr(s.strip())
261 261 else:
262 262 return s.strip()
263 263
264 264
265 265 @templatekeyword(b'diffstat', requires={b'ui', b'ctx'})
266 266 def showdiffstat(context, mapping):
267 267 """String. Statistics of changes with the following format:
268 268 "modified files: +added/-removed lines"
269 269 """
270 270 ui = context.resource(mapping, b'ui')
271 271 ctx = context.resource(mapping, b'ctx')
272 272 diffopts = diffutil.diffallopts(ui, {b'noprefix': False})
273 273 diff = ctx.diff(opts=diffopts)
274 274 stats = patch.diffstatdata(util.iterlines(diff))
275 275 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
276 276 return b'%d: +%d/-%d' % (len(stats), adds, removes)
277 277
278 278
279 279 @templatekeyword(b'envvars', requires={b'ui'})
280 280 def showenvvars(context, mapping):
281 281 """A dictionary of environment variables. (EXPERIMENTAL)"""
282 282 ui = context.resource(mapping, b'ui')
283 283 env = ui.exportableenviron()
284 284 env = util.sortdict((k, env[k]) for k in sorted(env))
285 285 return compatdict(context, mapping, b'envvar', env, plural=b'envvars')
286 286
287 287
288 288 @templatekeyword(b'extras', requires={b'ctx'})
289 289 def showextras(context, mapping):
290 290 """List of dicts with key, value entries of the 'extras'
291 291 field of this changeset."""
292 292 ctx = context.resource(mapping, b'ctx')
293 293 extras = ctx.extra()
294 294 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
295 295 makemap = lambda k: {b'key': k, b'value': extras[k]}
296 296 c = [makemap(k) for k in extras]
297 297 f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras')
298 298 return _hybrid(
299 299 f,
300 300 extras,
301 301 makemap,
302 302 lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])),
303 303 )
304 304
305 305
306 306 def _getfilestatus(context, mapping, listall=False):
307 307 ctx = context.resource(mapping, b'ctx')
308 308 revcache = context.resource(mapping, b'revcache')
309 309 if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall:
310 310 stat = ctx.p1().status(
311 311 ctx, listignored=listall, listclean=listall, listunknown=listall
312 312 )
313 313 revcache[b'filestatus'] = stat
314 314 revcache[b'filestatusall'] = listall
315 315 return revcache[b'filestatus']
316 316
317 317
318 318 def _getfilestatusmap(context, mapping, listall=False):
319 319 revcache = context.resource(mapping, b'revcache')
320 320 if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall:
321 321 stat = _getfilestatus(context, mapping, listall=listall)
322 322 revcache[b'filestatusmap'] = statmap = {}
323 323 for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat):
324 324 statmap.update((f, char) for f in files)
325 325 return revcache[b'filestatusmap'] # {path: statchar}
326 326
327 327
328 328 @templatekeyword(
329 329 b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'}
330 330 )
331 331 def showfilecopies(context, mapping):
332 332 """List of strings. Files copied in this changeset with
333 333 their sources.
334 334 """
335 335 repo = context.resource(mapping, b'repo')
336 336 ctx = context.resource(mapping, b'ctx')
337 337 cache = context.resource(mapping, b'cache')
338 338 copies = context.resource(mapping, b'revcache').get(b'copies')
339 339 if copies is None:
340 340 if b'getcopies' not in cache:
341 341 cache[b'getcopies'] = scmutil.getcopiesfn(repo)
342 342 getcopies = cache[b'getcopies']
343 343 copies = getcopies(ctx)
344 344 return templateutil.compatfilecopiesdict(
345 345 context, mapping, b'file_copy', copies
346 346 )
347 347
348 348
349 349 # showfilecopiesswitch() displays file copies only if copy records are
350 350 # provided before calling the templater, usually with a --copies
351 351 # command line switch.
352 352 @templatekeyword(b'file_copies_switch', requires={b'revcache'})
353 353 def showfilecopiesswitch(context, mapping):
354 354 """List of strings. Like "file_copies" but displayed
355 355 only if the --copied switch is set.
356 356 """
357 357 copies = context.resource(mapping, b'revcache').get(b'copies') or []
358 358 return templateutil.compatfilecopiesdict(
359 359 context, mapping, b'file_copy', copies
360 360 )
361 361
362 362
363 363 @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'})
364 364 def showfileadds(context, mapping):
365 365 """List of strings. Files added by this changeset."""
366 366 ctx = context.resource(mapping, b'ctx')
367 367 return templateutil.compatfileslist(
368 368 context, mapping, b'file_add', ctx.filesadded()
369 369 )
370 370
371 371
372 372 @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'})
373 373 def showfiledels(context, mapping):
374 374 """List of strings. Files removed by this changeset."""
375 375 ctx = context.resource(mapping, b'ctx')
376 376 return templateutil.compatfileslist(
377 377 context, mapping, b'file_del', ctx.filesremoved()
378 378 )
379 379
380 380
381 381 @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'})
382 382 def showfilemods(context, mapping):
383 383 """List of strings. Files modified by this changeset."""
384 384 ctx = context.resource(mapping, b'ctx')
385 385 return templateutil.compatfileslist(
386 386 context, mapping, b'file_mod', ctx.filesmodified()
387 387 )
388 388
389 389
390 390 @templatekeyword(b'files', requires={b'ctx'})
391 391 def showfiles(context, mapping):
392 392 """List of strings. All files modified, added, or removed by this
393 393 changeset.
394 394 """
395 395 ctx = context.resource(mapping, b'ctx')
396 396 return templateutil.compatfileslist(context, mapping, b'file', ctx.files())
397 397
398 398
399 399 @templatekeyword(b'graphnode', requires={b'repo', b'ctx', b'cache'})
400 400 def showgraphnode(context, mapping):
401 401 """String. The character representing the changeset node in an ASCII
402 402 revision graph."""
403 403 repo = context.resource(mapping, b'repo')
404 404 ctx = context.resource(mapping, b'ctx')
405 405 cache = context.resource(mapping, b'cache')
406 406 return getgraphnode(repo, ctx, cache)
407 407
408 408
409 409 def getgraphnode(repo, ctx, cache):
410 410 return getgraphnodecurrent(repo, ctx, cache) or getgraphnodesymbol(ctx)
411 411
412 412
413 413 def getgraphnodecurrent(repo, ctx, cache):
414 414 wpnodes = repo.dirstate.parents()
415 415 if wpnodes[1] == nullid:
416 416 wpnodes = wpnodes[:1]
417 417 if ctx.node() in wpnodes:
418 418 return b'@'
419 419 else:
420 420 merge_nodes = cache.get(b'merge_nodes')
421 421 if merge_nodes is None:
422 422 from . import mergestate as mergestatemod
423 423
424 424 mergestate = mergestatemod.mergestate.read(repo)
425 if mergestate.active():
425 if mergestate.unresolvedcount():
426 426 merge_nodes = (mergestate.local, mergestate.other)
427 427 else:
428 428 merge_nodes = ()
429 429 cache[b'merge_nodes'] = merge_nodes
430 430
431 431 if ctx.node() in merge_nodes:
432 432 return b'%'
433 433 return b''
434 434
435 435
436 436 def getgraphnodesymbol(ctx):
437 437 if ctx.obsolete():
438 438 return b'x'
439 439 elif ctx.isunstable():
440 440 return b'*'
441 441 elif ctx.closesbranch():
442 442 return b'_'
443 443 else:
444 444 return b'o'
445 445
446 446
447 447 @templatekeyword(b'graphwidth', requires=())
448 448 def showgraphwidth(context, mapping):
449 449 """Integer. The width of the graph drawn by 'log --graph' or zero."""
450 450 # just hosts documentation; should be overridden by template mapping
451 451 return 0
452 452
453 453
454 454 @templatekeyword(b'index', requires=())
455 455 def showindex(context, mapping):
456 456 """Integer. The current iteration of the loop. (0 indexed)"""
457 457 # just hosts documentation; should be overridden by template mapping
458 458 raise error.Abort(_(b"can't use index in this context"))
459 459
460 460
461 461 @templatekeyword(b'latesttag', requires={b'repo', b'ctx', b'cache'})
462 462 def showlatesttag(context, mapping):
463 463 """List of strings. The global tags on the most recent globally
464 464 tagged ancestor of this changeset. If no such tags exist, the list
465 465 consists of the single string "null".
466 466 """
467 467 return showlatesttags(context, mapping, None)
468 468
469 469
470 470 def showlatesttags(context, mapping, pattern):
471 471 """helper method for the latesttag keyword and function"""
472 472 latesttags = getlatesttags(context, mapping, pattern)
473 473
474 474 # latesttag[0] is an implementation detail for sorting csets on different
475 475 # branches in a stable manner- it is the date the tagged cset was created,
476 476 # not the date the tag was created. Therefore it isn't made visible here.
477 477 makemap = lambda v: {
478 478 b'changes': _showchangessincetag,
479 479 b'distance': latesttags[1],
480 480 b'latesttag': v, # BC with {latesttag % '{latesttag}'}
481 481 b'tag': v,
482 482 }
483 483
484 484 tags = latesttags[2]
485 485 f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':')
486 486 return _hybrid(f, tags, makemap, pycompat.identity)
487 487
488 488
489 489 @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'})
490 490 def showlatesttagdistance(context, mapping):
491 491 """Integer. Longest path to the latest tag."""
492 492 return getlatesttags(context, mapping)[1]
493 493
494 494
495 495 @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'})
496 496 def showchangessincelatesttag(context, mapping):
497 497 """Integer. All ancestors not in the latest tag."""
498 498 tag = getlatesttags(context, mapping)[2][0]
499 499 mapping = context.overlaymap(mapping, {b'tag': tag})
500 500 return _showchangessincetag(context, mapping)
501 501
502 502
503 503 def _showchangessincetag(context, mapping):
504 504 repo = context.resource(mapping, b'repo')
505 505 ctx = context.resource(mapping, b'ctx')
506 506 offset = 0
507 507 revs = [ctx.rev()]
508 508 tag = context.symbol(mapping, b'tag')
509 509
510 510 # The only() revset doesn't currently support wdir()
511 511 if ctx.rev() is None:
512 512 offset = 1
513 513 revs = [p.rev() for p in ctx.parents()]
514 514
515 515 return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset
516 516
517 517
518 518 # teach templater latesttags.changes is switched to (context, mapping) API
519 519 _showchangessincetag._requires = {b'repo', b'ctx'}
520 520
521 521
522 522 @templatekeyword(b'manifest', requires={b'repo', b'ctx'})
523 523 def showmanifest(context, mapping):
524 524 repo = context.resource(mapping, b'repo')
525 525 ctx = context.resource(mapping, b'ctx')
526 526 mnode = ctx.manifestnode()
527 527 if mnode is None:
528 528 mnode = wdirid
529 529 mrev = wdirrev
530 530 else:
531 531 mrev = repo.manifestlog.rev(mnode)
532 532 mhex = hex(mnode)
533 533 mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex})
534 534 f = context.process(b'manifest', mapping)
535 535 return templateutil.hybriditem(
536 536 f, None, f, lambda x: {b'rev': mrev, b'node': mhex}
537 537 )
538 538
539 539
540 540 @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'})
541 541 def showobsfate(context, mapping):
542 542 # this function returns a list containing pre-formatted obsfate strings.
543 543 #
544 544 # This function will be replaced by templates fragments when we will have
545 545 # the verbosity templatekw available.
546 546 succsandmarkers = showsuccsandmarkers(context, mapping)
547 547
548 548 ui = context.resource(mapping, b'ui')
549 549 repo = context.resource(mapping, b'repo')
550 550 values = []
551 551
552 552 for x in succsandmarkers.tovalue(context, mapping):
553 553 v = obsutil.obsfateprinter(
554 554 ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid
555 555 )
556 556 values.append(v)
557 557
558 558 return compatlist(context, mapping, b"fate", values)
559 559
560 560
561 561 def shownames(context, mapping, namespace):
562 562 """helper method to generate a template keyword for a namespace"""
563 563 repo = context.resource(mapping, b'repo')
564 564 ctx = context.resource(mapping, b'ctx')
565 565 ns = repo.names.get(namespace)
566 566 if ns is None:
567 567 # namespaces.addnamespace() registers new template keyword, but
568 568 # the registered namespace might not exist in the current repo.
569 569 return
570 570 names = ns.names(repo, ctx.node())
571 571 return compatlist(
572 572 context, mapping, ns.templatename, names, plural=namespace
573 573 )
574 574
575 575
576 576 @templatekeyword(b'namespaces', requires={b'repo', b'ctx'})
577 577 def shownamespaces(context, mapping):
578 578 """Dict of lists. Names attached to this changeset per
579 579 namespace."""
580 580 repo = context.resource(mapping, b'repo')
581 581 ctx = context.resource(mapping, b'ctx')
582 582
583 583 namespaces = util.sortdict()
584 584
585 585 def makensmapfn(ns):
586 586 # 'name' for iterating over namespaces, templatename for local reference
587 587 return lambda v: {b'name': v, ns.templatename: v}
588 588
589 589 for k, ns in pycompat.iteritems(repo.names):
590 590 names = ns.names(repo, ctx.node())
591 591 f = _showcompatlist(context, mapping, b'name', names)
592 592 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
593 593
594 594 f = _showcompatlist(context, mapping, b'namespace', list(namespaces))
595 595
596 596 def makemap(ns):
597 597 return {
598 598 b'namespace': ns,
599 599 b'names': namespaces[ns],
600 600 b'builtin': repo.names[ns].builtin,
601 601 b'colorname': repo.names[ns].colorname,
602 602 }
603 603
604 604 return _hybrid(f, namespaces, makemap, pycompat.identity)
605 605
606 606
607 607 @templatekeyword(b'negrev', requires={b'repo', b'ctx'})
608 608 def shownegrev(context, mapping):
609 609 """Integer. The repository-local changeset negative revision number,
610 610 which counts in the opposite direction."""
611 611 ctx = context.resource(mapping, b'ctx')
612 612 rev = ctx.rev()
613 613 if rev is None or rev < 0: # wdir() or nullrev?
614 614 return None
615 615 repo = context.resource(mapping, b'repo')
616 616 return rev - len(repo)
617 617
618 618
619 619 @templatekeyword(b'node', requires={b'ctx'})
620 620 def shownode(context, mapping):
621 621 """String. The changeset identification hash, as a 40 hexadecimal
622 622 digit string.
623 623 """
624 624 ctx = context.resource(mapping, b'ctx')
625 625 return ctx.hex()
626 626
627 627
628 628 @templatekeyword(b'obsolete', requires={b'ctx'})
629 629 def showobsolete(context, mapping):
630 630 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
631 631 ctx = context.resource(mapping, b'ctx')
632 632 if ctx.obsolete():
633 633 return b'obsolete'
634 634 return b''
635 635
636 636
637 637 @templatekeyword(b'path', requires={b'fctx'})
638 638 def showpath(context, mapping):
639 639 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
640 640 fctx = context.resource(mapping, b'fctx')
641 641 return fctx.path()
642 642
643 643
644 644 @templatekeyword(b'peerurls', requires={b'repo'})
645 645 def showpeerurls(context, mapping):
646 646 """A dictionary of repository locations defined in the [paths] section
647 647 of your configuration file."""
648 648 repo = context.resource(mapping, b'repo')
649 649 # see commands.paths() for naming of dictionary keys
650 650 paths = repo.ui.paths
651 651 urls = util.sortdict(
652 652 (k, p.rawloc) for k, p in sorted(pycompat.iteritems(paths))
653 653 )
654 654
655 655 def makemap(k):
656 656 p = paths[k]
657 657 d = {b'name': k, b'url': p.rawloc}
658 658 d.update((o, v) for o, v in sorted(pycompat.iteritems(p.suboptions)))
659 659 return d
660 660
661 661 return _hybrid(None, urls, makemap, lambda k: b'%s=%s' % (k, urls[k]))
662 662
663 663
664 664 @templatekeyword(b"predecessors", requires={b'repo', b'ctx'})
665 665 def showpredecessors(context, mapping):
666 666 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)"""
667 667 repo = context.resource(mapping, b'repo')
668 668 ctx = context.resource(mapping, b'ctx')
669 669 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
670 670 predecessors = pycompat.maplist(hex, predecessors)
671 671
672 672 return _hybrid(
673 673 None,
674 674 predecessors,
675 675 lambda x: {b'ctx': repo[x]},
676 676 lambda x: scmutil.formatchangeid(repo[x]),
677 677 )
678 678
679 679
680 680 @templatekeyword(b'reporoot', requires={b'repo'})
681 681 def showreporoot(context, mapping):
682 682 """String. The root directory of the current repository."""
683 683 repo = context.resource(mapping, b'repo')
684 684 return repo.root
685 685
686 686
687 687 @templatekeyword(b'size', requires={b'fctx'})
688 688 def showsize(context, mapping):
689 689 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
690 690 fctx = context.resource(mapping, b'fctx')
691 691 return fctx.size()
692 692
693 693
694 694 # requires 'fctx' to denote {status} depends on (ctx, path) pair
695 695 @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'})
696 696 def showstatus(context, mapping):
697 697 """String. Status code of the current file. (EXPERIMENTAL)"""
698 698 path = templateutil.runsymbol(context, mapping, b'path')
699 699 path = templateutil.stringify(context, mapping, path)
700 700 if not path:
701 701 return
702 702 statmap = _getfilestatusmap(context, mapping)
703 703 if path not in statmap:
704 704 statmap = _getfilestatusmap(context, mapping, listall=True)
705 705 return statmap.get(path)
706 706
707 707
708 708 @templatekeyword(b"successorssets", requires={b'repo', b'ctx'})
709 709 def showsuccessorssets(context, mapping):
710 710 """Returns a string of sets of successors for a changectx. Format used
711 711 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2
712 712 while also diverged into ctx3. (EXPERIMENTAL)"""
713 713 repo = context.resource(mapping, b'repo')
714 714 ctx = context.resource(mapping, b'ctx')
715 715 if not ctx.obsolete():
716 716 return b''
717 717
718 718 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
719 719 ssets = [[hex(n) for n in ss] for ss in ssets]
720 720
721 721 data = []
722 722 for ss in ssets:
723 723 h = _hybrid(
724 724 None,
725 725 ss,
726 726 lambda x: {b'ctx': repo[x]},
727 727 lambda x: scmutil.formatchangeid(repo[x]),
728 728 )
729 729 data.append(h)
730 730
731 731 # Format the successorssets
732 732 def render(d):
733 733 return templateutil.stringify(context, mapping, d)
734 734
735 735 def gen(data):
736 736 yield b"; ".join(render(d) for d in data)
737 737
738 738 return _hybrid(
739 739 gen(data), data, lambda x: {b'successorset': x}, pycompat.identity
740 740 )
741 741
742 742
743 743 @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'})
744 744 def showsuccsandmarkers(context, mapping):
745 745 """Returns a list of dict for each final successor of ctx. The dict
746 746 contains successors node id in "successors" keys and the list of
747 747 obs-markers from ctx to the set of successors in "markers".
748 748 (EXPERIMENTAL)
749 749 """
750 750 repo = context.resource(mapping, b'repo')
751 751 ctx = context.resource(mapping, b'ctx')
752 752
753 753 values = obsutil.successorsandmarkers(repo, ctx)
754 754
755 755 if values is None:
756 756 values = []
757 757
758 758 # Format successors and markers to avoid exposing binary to templates
759 759 data = []
760 760 for i in values:
761 761 # Format successors
762 762 successors = i[b'successors']
763 763
764 764 successors = [hex(n) for n in successors]
765 765 successors = _hybrid(
766 766 None,
767 767 successors,
768 768 lambda x: {b'ctx': repo[x]},
769 769 lambda x: scmutil.formatchangeid(repo[x]),
770 770 )
771 771
772 772 # Format markers
773 773 finalmarkers = []
774 774 for m in i[b'markers']:
775 775 hexprec = hex(m[0])
776 776 hexsucs = tuple(hex(n) for n in m[1])
777 777 hexparents = None
778 778 if m[5] is not None:
779 779 hexparents = tuple(hex(n) for n in m[5])
780 780 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
781 781 finalmarkers.append(newmarker)
782 782
783 783 data.append({b'successors': successors, b'markers': finalmarkers})
784 784
785 785 return templateutil.mappinglist(data)
786 786
787 787
788 788 @templatekeyword(b'p1', requires={b'ctx'})
789 789 def showp1(context, mapping):
790 790 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision
791 791 number, and ``{p1.node}`` for the identification hash."""
792 792 ctx = context.resource(mapping, b'ctx')
793 793 return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl)
794 794
795 795
796 796 @templatekeyword(b'p2', requires={b'ctx'})
797 797 def showp2(context, mapping):
798 798 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision
799 799 number, and ``{p2.node}`` for the identification hash."""
800 800 ctx = context.resource(mapping, b'ctx')
801 801 return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl)
802 802
803 803
804 804 @templatekeyword(b'p1rev', requires={b'ctx'})
805 805 def showp1rev(context, mapping):
806 806 """Integer. The repository-local revision number of the changeset's
807 807 first parent, or -1 if the changeset has no parents. (DEPRECATED)"""
808 808 ctx = context.resource(mapping, b'ctx')
809 809 return ctx.p1().rev()
810 810
811 811
812 812 @templatekeyword(b'p2rev', requires={b'ctx'})
813 813 def showp2rev(context, mapping):
814 814 """Integer. The repository-local revision number of the changeset's
815 815 second parent, or -1 if the changeset has no second parent. (DEPRECATED)"""
816 816 ctx = context.resource(mapping, b'ctx')
817 817 return ctx.p2().rev()
818 818
819 819
820 820 @templatekeyword(b'p1node', requires={b'ctx'})
821 821 def showp1node(context, mapping):
822 822 """String. The identification hash of the changeset's first parent,
823 823 as a 40 digit hexadecimal string. If the changeset has no parents, all
824 824 digits are 0. (DEPRECATED)"""
825 825 ctx = context.resource(mapping, b'ctx')
826 826 return ctx.p1().hex()
827 827
828 828
829 829 @templatekeyword(b'p2node', requires={b'ctx'})
830 830 def showp2node(context, mapping):
831 831 """String. The identification hash of the changeset's second
832 832 parent, as a 40 digit hexadecimal string. If the changeset has no second
833 833 parent, all digits are 0. (DEPRECATED)"""
834 834 ctx = context.resource(mapping, b'ctx')
835 835 return ctx.p2().hex()
836 836
837 837
838 838 @templatekeyword(b'parents', requires={b'repo', b'ctx'})
839 839 def showparents(context, mapping):
840 840 """List of strings. The parents of the changeset in "rev:node"
841 841 format. If the changeset has only one "natural" parent (the predecessor
842 842 revision) nothing is shown."""
843 843 repo = context.resource(mapping, b'repo')
844 844 ctx = context.resource(mapping, b'ctx')
845 845 pctxs = scmutil.meaningfulparents(repo, ctx)
846 846 prevs = [p.rev() for p in pctxs]
847 847 parents = [
848 848 [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())]
849 849 for p in pctxs
850 850 ]
851 851 f = _showcompatlist(context, mapping, b'parent', parents)
852 852 return _hybrid(
853 853 f,
854 854 prevs,
855 855 lambda x: {b'ctx': repo[x]},
856 856 lambda x: scmutil.formatchangeid(repo[x]),
857 857 keytype=int,
858 858 )
859 859
860 860
861 861 @templatekeyword(b'phase', requires={b'ctx'})
862 862 def showphase(context, mapping):
863 863 """String. The changeset phase name."""
864 864 ctx = context.resource(mapping, b'ctx')
865 865 return ctx.phasestr()
866 866
867 867
868 868 @templatekeyword(b'phaseidx', requires={b'ctx'})
869 869 def showphaseidx(context, mapping):
870 870 """Integer. The changeset phase index. (ADVANCED)"""
871 871 ctx = context.resource(mapping, b'ctx')
872 872 return ctx.phase()
873 873
874 874
875 875 @templatekeyword(b'rev', requires={b'ctx'})
876 876 def showrev(context, mapping):
877 877 """Integer. The repository-local changeset revision number."""
878 878 ctx = context.resource(mapping, b'ctx')
879 879 return scmutil.intrev(ctx)
880 880
881 881
882 882 @templatekeyword(b'subrepos', requires={b'ctx'})
883 883 def showsubrepos(context, mapping):
884 884 """List of strings. Updated subrepositories in the changeset."""
885 885 ctx = context.resource(mapping, b'ctx')
886 886 substate = ctx.substate
887 887 if not substate:
888 888 return compatlist(context, mapping, b'subrepo', [])
889 889 psubstate = ctx.p1().substate or {}
890 890 subrepos = []
891 891 for sub in substate:
892 892 if sub not in psubstate or substate[sub] != psubstate[sub]:
893 893 subrepos.append(sub) # modified or newly added in ctx
894 894 for sub in psubstate:
895 895 if sub not in substate:
896 896 subrepos.append(sub) # removed in ctx
897 897 return compatlist(context, mapping, b'subrepo', sorted(subrepos))
898 898
899 899
900 900 # don't remove "showtags" definition, even though namespaces will put
901 901 # a helper function for "tags" keyword into "keywords" map automatically,
902 902 # because online help text is built without namespaces initialization
903 903 @templatekeyword(b'tags', requires={b'repo', b'ctx'})
904 904 def showtags(context, mapping):
905 905 """List of strings. Any tags associated with the changeset."""
906 906 return shownames(context, mapping, b'tags')
907 907
908 908
909 909 @templatekeyword(b'termwidth', requires={b'ui'})
910 910 def showtermwidth(context, mapping):
911 911 """Integer. The width of the current terminal."""
912 912 ui = context.resource(mapping, b'ui')
913 913 return ui.termwidth()
914 914
915 915
916 916 @templatekeyword(b'user', requires={b'ctx'})
917 917 def showuser(context, mapping):
918 918 """String. The unmodified author of the changeset."""
919 919 ctx = context.resource(mapping, b'ctx')
920 920 return ctx.user()
921 921
922 922
923 923 @templatekeyword(b'instabilities', requires={b'ctx'})
924 924 def showinstabilities(context, mapping):
925 925 """List of strings. Evolution instabilities affecting the changeset.
926 926 (EXPERIMENTAL)
927 927 """
928 928 ctx = context.resource(mapping, b'ctx')
929 929 return compatlist(
930 930 context,
931 931 mapping,
932 932 b'instability',
933 933 ctx.instabilities(),
934 934 plural=b'instabilities',
935 935 )
936 936
937 937
938 938 @templatekeyword(b'verbosity', requires={b'ui'})
939 939 def showverbosity(context, mapping):
940 940 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
941 941 or ''."""
942 942 ui = context.resource(mapping, b'ui')
943 943 # see logcmdutil.changesettemplater for priority of these flags
944 944 if ui.debugflag:
945 945 return b'debug'
946 946 elif ui.quiet:
947 947 return b'quiet'
948 948 elif ui.verbose:
949 949 return b'verbose'
950 950 return b''
951 951
952 952
953 953 @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'})
954 954 def showwhyunstable(context, mapping):
955 955 """List of dicts explaining all instabilities of a changeset.
956 956 (EXPERIMENTAL)
957 957 """
958 958 repo = context.resource(mapping, b'repo')
959 959 ctx = context.resource(mapping, b'ctx')
960 960
961 961 def formatnode(ctx):
962 962 return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
963 963
964 964 entries = obsutil.whyunstable(repo, ctx)
965 965
966 966 for entry in entries:
967 967 if entry.get(b'divergentnodes'):
968 968 dnodes = entry[b'divergentnodes']
969 969 dnhybrid = _hybrid(
970 970 None,
971 971 [dnode.hex() for dnode in dnodes],
972 972 lambda x: {b'ctx': repo[x]},
973 973 lambda x: formatnode(repo[x]),
974 974 )
975 975 entry[b'divergentnodes'] = dnhybrid
976 976
977 977 tmpl = (
978 978 b'{instability}:{if(divergentnodes, " ")}{divergentnodes} '
979 979 b'{reason} {node|short}'
980 980 )
981 981 return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n')
982 982
983 983
984 984 def loadkeyword(ui, extname, registrarobj):
985 985 """Load template keyword from specified registrarobj
986 986 """
987 987 for name, func in pycompat.iteritems(registrarobj._table):
988 988 keywords[name] = func
989 989
990 990
991 991 # tell hggettext to extract docstrings from these functions:
992 992 i18nfunctions = keywords.values()
@@ -1,771 +1,771 b''
1 1 #testcases abortcommand abortflag
2 2
3 3 #if abortflag
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [alias]
6 6 > abort = graft --abort
7 7 > EOF
8 8 #endif
9 9
10 10
11 11 Testing the reading of old format graftstate file with newer mercurial
12 12
13 13 $ hg init oldgraft
14 14 $ cd oldgraft
15 15 $ for ch in a b c; do echo foo > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
16 16 $ hg log -GT "{rev}:{node|short} {desc}\n"
17 17 @ 2:8be98ac1a569 added c
18 18 |
19 19 o 1:80e6d2c47cfe added b
20 20 |
21 21 o 0:f7ad41964313 added a
22 22
23 23 $ hg up 0
24 24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
25 25 $ echo bar > b
26 26 $ hg add b
27 27 $ hg ci -m "bar to b"
28 28 created new head
29 29 $ hg graft -r 1 -r 2
30 30 grafting 1:80e6d2c47cfe "added b"
31 31 merging b
32 32 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
33 33 abort: unresolved conflicts, can't continue
34 34 (use 'hg resolve' and 'hg graft --continue')
35 35 [1]
36 36
37 37 Writing the nodes in old format to graftstate
38 38
39 39 $ hg log -r 1 -r 2 -T '{node}\n' > .hg/graftstate
40 40 $ echo foo > b
41 41 $ hg resolve -m
42 42 (no more unresolved files)
43 43 continue: hg graft --continue
44 44 $ hg graft --continue
45 45 grafting 1:80e6d2c47cfe "added b"
46 46 grafting 2:8be98ac1a569 "added c"
47 47
48 48 Testing that --user is preserved during conflicts and value is reused while
49 49 running `hg graft --continue`
50 50
51 51 $ hg log -G
52 52 @ changeset: 5:711e9fa999f1
53 53 | tag: tip
54 54 | user: test
55 55 | date: Thu Jan 01 00:00:00 1970 +0000
56 56 | summary: added c
57 57 |
58 58 o changeset: 4:e5ad7353b408
59 59 | user: test
60 60 | date: Thu Jan 01 00:00:00 1970 +0000
61 61 | summary: added b
62 62 |
63 63 o changeset: 3:9e887f7a939c
64 64 | parent: 0:f7ad41964313
65 65 | user: test
66 66 | date: Thu Jan 01 00:00:00 1970 +0000
67 67 | summary: bar to b
68 68 |
69 69 | o changeset: 2:8be98ac1a569
70 70 | | user: test
71 71 | | date: Thu Jan 01 00:00:00 1970 +0000
72 72 | | summary: added c
73 73 | |
74 74 | o changeset: 1:80e6d2c47cfe
75 75 |/ user: test
76 76 | date: Thu Jan 01 00:00:00 1970 +0000
77 77 | summary: added b
78 78 |
79 79 o changeset: 0:f7ad41964313
80 80 user: test
81 81 date: Thu Jan 01 00:00:00 1970 +0000
82 82 summary: added a
83 83
84 84
85 85 $ hg up '.^^'
86 86 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
87 87
88 88 $ hg graft -r 1 -r 2 --user batman
89 89 grafting 1:80e6d2c47cfe "added b"
90 90 merging b
91 91 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
92 92 abort: unresolved conflicts, can't continue
93 93 (use 'hg resolve' and 'hg graft --continue')
94 94 [1]
95 95
96 96 $ echo wat > b
97 97 $ hg resolve -m
98 98 (no more unresolved files)
99 99 continue: hg graft --continue
100 100
101 101 $ hg graft --continue
102 102 grafting 1:80e6d2c47cfe "added b"
103 103 grafting 2:8be98ac1a569 "added c"
104 104
105 105 $ hg log -Gr 3::
106 106 @ changeset: 7:11a36ffaacf2
107 107 | tag: tip
108 108 | user: batman
109 109 | date: Thu Jan 01 00:00:00 1970 +0000
110 110 | summary: added c
111 111 |
112 112 o changeset: 6:76803afc6511
113 113 | parent: 3:9e887f7a939c
114 114 | user: batman
115 115 | date: Thu Jan 01 00:00:00 1970 +0000
116 116 | summary: added b
117 117 |
118 118 | o changeset: 5:711e9fa999f1
119 119 | | user: test
120 120 | | date: Thu Jan 01 00:00:00 1970 +0000
121 121 | | summary: added c
122 122 | |
123 123 | o changeset: 4:e5ad7353b408
124 124 |/ user: test
125 125 | date: Thu Jan 01 00:00:00 1970 +0000
126 126 | summary: added b
127 127 |
128 128 o changeset: 3:9e887f7a939c
129 129 | parent: 0:f7ad41964313
130 130 ~ user: test
131 131 date: Thu Jan 01 00:00:00 1970 +0000
132 132 summary: bar to b
133 133
134 134 Test that --date is preserved and reused in `hg graft --continue`
135 135
136 136 $ hg up '.^^'
137 137 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
138 138 $ hg graft -r 1 -r 2 --date '1234560000 120'
139 139 grafting 1:80e6d2c47cfe "added b"
140 140 merging b
141 141 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
142 142 abort: unresolved conflicts, can't continue
143 143 (use 'hg resolve' and 'hg graft --continue')
144 144 [1]
145 145
146 146 $ echo foobar > b
147 147 $ hg resolve -m
148 148 (no more unresolved files)
149 149 continue: hg graft --continue
150 150 $ hg graft --continue
151 151 grafting 1:80e6d2c47cfe "added b"
152 152 grafting 2:8be98ac1a569 "added c"
153 153
154 154 $ hg log -Gr '.^^::.'
155 155 @ changeset: 9:1896b76e007a
156 156 | tag: tip
157 157 | user: test
158 158 | date: Fri Feb 13 21:18:00 2009 -0002
159 159 | summary: added c
160 160 |
161 161 o changeset: 8:ce2b4f1632af
162 162 | parent: 3:9e887f7a939c
163 163 | user: test
164 164 | date: Fri Feb 13 21:18:00 2009 -0002
165 165 | summary: added b
166 166 |
167 167 o changeset: 3:9e887f7a939c
168 168 | parent: 0:f7ad41964313
169 169 ~ user: test
170 170 date: Thu Jan 01 00:00:00 1970 +0000
171 171 summary: bar to b
172 172
173 173 Test that --log is preserved and reused in `hg graft --continue`
174 174
175 175 $ hg up '.^^'
176 176 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
177 177 $ hg graft -r 1 -r 2 --log
178 178 grafting 1:80e6d2c47cfe "added b"
179 179 merging b
180 180 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
181 181 abort: unresolved conflicts, can't continue
182 182 (use 'hg resolve' and 'hg graft --continue')
183 183 [1]
184 184
185 185 $ echo foobar > b
186 186 $ hg resolve -m
187 187 (no more unresolved files)
188 188 continue: hg graft --continue
189 189
190 190 $ hg graft --continue
191 191 grafting 1:80e6d2c47cfe "added b"
192 192 grafting 2:8be98ac1a569 "added c"
193 193
194 194 $ hg log -GT "{rev}:{node|short} {desc}" -r '.^^::.'
195 195 @ 11:30c1050a58b2 added c
196 196 | (grafted from 8be98ac1a56990c2d9ca6861041b8390af7bd6f3)
197 197 o 10:ec7eda2313e2 added b
198 198 | (grafted from 80e6d2c47cfe5b3185519568327a17a061c7efb6)
199 199 o 3:9e887f7a939c bar to b
200 200 |
201 201 ~
202 202
203 203 $ cd ..
204 204
205 205 Testing the --stop flag of `hg graft` which stops the interrupted graft
206 206
207 207 $ hg init stopgraft
208 208 $ cd stopgraft
209 209 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
210 210
211 211 $ hg log -G
212 212 @ changeset: 3:9150fe93bec6
213 213 | tag: tip
214 214 | user: test
215 215 | date: Thu Jan 01 00:00:00 1970 +0000
216 216 | summary: added d
217 217 |
218 218 o changeset: 2:155349b645be
219 219 | user: test
220 220 | date: Thu Jan 01 00:00:00 1970 +0000
221 221 | summary: added c
222 222 |
223 223 o changeset: 1:5f6d8a4bf34a
224 224 | user: test
225 225 | date: Thu Jan 01 00:00:00 1970 +0000
226 226 | summary: added b
227 227 |
228 228 o changeset: 0:9092f1db7931
229 229 user: test
230 230 date: Thu Jan 01 00:00:00 1970 +0000
231 231 summary: added a
232 232
233 233 $ hg up '.^^'
234 234 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
235 235
236 236 $ echo foo > d
237 237 $ hg ci -Aqm "added foo to d"
238 238
239 239 $ hg graft --stop
240 240 abort: no interrupted graft found
241 241 [255]
242 242
243 243 $ hg graft -r 3
244 244 grafting 3:9150fe93bec6 "added d"
245 245 merging d
246 246 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
247 247 abort: unresolved conflicts, can't continue
248 248 (use 'hg resolve' and 'hg graft --continue')
249 249 [1]
250 250
251 251 $ hg graft --stop --continue
252 252 abort: cannot specify both --stop and --continue
253 253 [255]
254 254
255 255 $ hg graft --stop -U
256 256 abort: cannot specify both --stop and --user
257 257 [255]
258 258 $ hg graft --stop --rev 4
259 259 abort: cannot specify both --stop and --rev
260 260 [255]
261 261 $ hg graft --stop --log
262 262 abort: cannot specify both --stop and --log
263 263 [255]
264 264
265 265 $ hg graft --stop
266 266 stopped the interrupted graft
267 267 working directory is now at a0deacecd59d
268 268
269 269 $ hg diff
270 270
271 271 $ hg log -Gr '.'
272 272 @ changeset: 4:a0deacecd59d
273 273 | tag: tip
274 274 ~ parent: 1:5f6d8a4bf34a
275 275 user: test
276 276 date: Thu Jan 01 00:00:00 1970 +0000
277 277 summary: added foo to d
278 278
279 279 $ hg graft -r 2 -r 3
280 280 grafting 2:155349b645be "added c"
281 281 grafting 3:9150fe93bec6 "added d"
282 282 merging d
283 283 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
284 284 abort: unresolved conflicts, can't continue
285 285 (use 'hg resolve' and 'hg graft --continue')
286 286 [1]
287 287
288 288 $ hg graft --stop
289 289 stopped the interrupted graft
290 290 working directory is now at 75b447541a9e
291 291
292 292 $ hg diff
293 293
294 294 $ hg log -G -T "{rev}:{node|short} {desc}"
295 295 @ 5:75b447541a9e added c
296 296 |
297 297 o 4:a0deacecd59d added foo to d
298 298 |
299 299 | o 3:9150fe93bec6 added d
300 300 | |
301 301 | o 2:155349b645be added c
302 302 |/
303 303 o 1:5f6d8a4bf34a added b
304 304 |
305 305 o 0:9092f1db7931 added a
306 306
307 307 $ cd ..
308 308
309 309 Testing the --abort flag for `hg graft` which aborts and rollback to state
310 310 before the graft
311 311
312 312 $ hg init abortgraft
313 313 $ cd abortgraft
314 314 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
315 315
316 316 $ hg up '.^^'
317 317 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
318 318
319 319 $ echo x > x
320 320 $ hg ci -Aqm "added x"
321 321 $ hg up '.^'
322 322 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
323 323 $ echo foo > c
324 324 $ hg ci -Aqm "added foo to c"
325 325
326 326 $ hg log -GT "{rev}:{node|short} {desc}"
327 327 @ 5:36b793615f78 added foo to c
328 328 |
329 329 | o 4:863a25e1a9ea added x
330 330 |/
331 331 | o 3:9150fe93bec6 added d
332 332 | |
333 333 | o 2:155349b645be added c
334 334 |/
335 335 o 1:5f6d8a4bf34a added b
336 336 |
337 337 o 0:9092f1db7931 added a
338 338
339 339 $ hg up 9150fe93bec6
340 340 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
341 341
342 342 $ hg abort
343 343 abort: no interrupted graft to abort (abortflag !)
344 344 abort: no operation in progress (abortcommand !)
345 345 [255]
346 346
347 347 when stripping is required
348 348 $ hg graft -r 4 -r 5
349 349 grafting 4:863a25e1a9ea "added x"
350 350 grafting 5:36b793615f78 "added foo to c" (tip)
351 351 merging c
352 352 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
353 353 abort: unresolved conflicts, can't continue
354 354 (use 'hg resolve' and 'hg graft --continue')
355 355 [1]
356 356
357 357 $ hg graft --continue --abort
358 358 abort: cannot specify both --abort and --continue
359 359 [255]
360 360
361 361 $ hg graft --abort --stop
362 362 abort: cannot specify both --abort and --stop
363 363 [255]
364 364
365 365 $ hg graft --abort --currentuser
366 366 abort: cannot specify both --abort and --user
367 367 [255]
368 368
369 369 $ hg graft --abort --edit
370 370 abort: cannot specify both --abort and --edit
371 371 [255]
372 372
373 373 #if abortcommand
374 374 when in dry-run mode
375 375 $ hg abort --dry-run
376 376 graft in progress, will be aborted
377 377 #endif
378 378
379 379 $ hg abort
380 380 graft aborted
381 381 working directory is now at 9150fe93bec6
382 382 $ hg log -GT "{rev}:{node|short} {desc}"
383 383 o 5:36b793615f78 added foo to c
384 384 |
385 385 | o 4:863a25e1a9ea added x
386 386 |/
387 387 | @ 3:9150fe93bec6 added d
388 388 | |
389 389 | o 2:155349b645be added c
390 390 |/
391 391 o 1:5f6d8a4bf34a added b
392 392 |
393 393 o 0:9092f1db7931 added a
394 394
395 395 when stripping is not required
396 396 $ hg graft -r 5
397 397 grafting 5:36b793615f78 "added foo to c" (tip)
398 398 merging c
399 399 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
400 400 abort: unresolved conflicts, can't continue
401 401 (use 'hg resolve' and 'hg graft --continue')
402 402 [1]
403 403
404 404 $ hg abort
405 405 graft aborted
406 406 working directory is now at 9150fe93bec6
407 407 $ hg log -GT "{rev}:{node|short} {desc}"
408 408 o 5:36b793615f78 added foo to c
409 409 |
410 410 | o 4:863a25e1a9ea added x
411 411 |/
412 412 | @ 3:9150fe93bec6 added d
413 413 | |
414 414 | o 2:155349b645be added c
415 415 |/
416 416 o 1:5f6d8a4bf34a added b
417 417 |
418 418 o 0:9092f1db7931 added a
419 419
420 420 when some of the changesets became public
421 421
422 422 $ hg graft -r 4 -r 5
423 423 grafting 4:863a25e1a9ea "added x"
424 424 grafting 5:36b793615f78 "added foo to c" (tip)
425 425 merging c
426 426 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
427 427 abort: unresolved conflicts, can't continue
428 428 (use 'hg resolve' and 'hg graft --continue')
429 429 [1]
430 430
431 431 $ hg log -GT "{rev}:{node|short} {desc}"
432 432 @ 6:6ec71c037d94 added x
433 433 |
434 434 | % 5:36b793615f78 added foo to c
435 435 | |
436 436 | | o 4:863a25e1a9ea added x
437 437 | |/
438 438 o | 3:9150fe93bec6 added d
439 439 | |
440 440 o | 2:155349b645be added c
441 441 |/
442 442 o 1:5f6d8a4bf34a added b
443 443 |
444 444 o 0:9092f1db7931 added a
445 445
446 446 $ hg phase -r 6 --public
447 447
448 448 $ hg abort
449 449 cannot clean up public changesets 6ec71c037d94
450 450 graft aborted
451 451 working directory is now at 6ec71c037d94
452 452
453 453 when we created new changesets on top of existing one
454 454
455 455 $ hg up '.^^'
456 456 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
457 457 $ echo y > y
458 458 $ hg ci -Aqm "added y"
459 459 $ echo z > z
460 460 $ hg ci -Aqm "added z"
461 461
462 462 $ hg up 3
463 463 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
464 464 $ hg log -GT "{rev}:{node|short} {desc}"
465 465 o 8:637f9e9bbfd4 added z
466 466 |
467 467 o 7:123221671fd4 added y
468 468 |
469 469 | o 6:6ec71c037d94 added x
470 470 | |
471 471 | | o 5:36b793615f78 added foo to c
472 472 | | |
473 473 | | | o 4:863a25e1a9ea added x
474 474 | | |/
475 475 | @ | 3:9150fe93bec6 added d
476 476 |/ /
477 477 o / 2:155349b645be added c
478 478 |/
479 479 o 1:5f6d8a4bf34a added b
480 480 |
481 481 o 0:9092f1db7931 added a
482 482
483 483 $ hg graft -r 8 -r 7 -r 5
484 484 grafting 8:637f9e9bbfd4 "added z" (tip)
485 485 grafting 7:123221671fd4 "added y"
486 486 grafting 5:36b793615f78 "added foo to c"
487 487 merging c
488 488 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
489 489 abort: unresolved conflicts, can't continue
490 490 (use 'hg resolve' and 'hg graft --continue')
491 491 [1]
492 492
493 493 $ cd ..
494 494 $ hg init pullrepo
495 495 $ cd pullrepo
496 496 $ cat >> .hg/hgrc <<EOF
497 497 > [phases]
498 498 > publish=False
499 499 > EOF
500 500 $ hg pull ../abortgraft --config phases.publish=False
501 501 pulling from ../abortgraft
502 502 requesting all changes
503 503 adding changesets
504 504 adding manifests
505 505 adding file changes
506 506 added 11 changesets with 9 changes to 8 files (+4 heads)
507 507 new changesets 9092f1db7931:6b98ff0062dd (6 drafts)
508 508 (run 'hg heads' to see heads, 'hg merge' to merge)
509 509 $ hg up 9
510 510 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
511 511 $ echo w > w
512 512 $ hg ci -Aqm "added w" --config phases.publish=False
513 513
514 514 $ cd ../abortgraft
515 515 $ hg pull ../pullrepo
516 516 pulling from ../pullrepo
517 517 searching for changes
518 518 adding changesets
519 519 adding manifests
520 520 adding file changes
521 521 added 1 changesets with 1 changes to 1 files (+1 heads)
522 522 new changesets 311dfc6cf3bf (1 drafts)
523 523 (run 'hg heads .' to see heads, 'hg merge' to merge)
524 524
525 525 $ hg abort
526 526 new changesets detected on destination branch, can't strip
527 527 graft aborted
528 528 working directory is now at 6b98ff0062dd
529 529
530 530 $ cd ..
531 531
532 532 ============================
533 533 Testing --no-commit option:|
534 534 ============================
535 535
536 536 $ hg init nocommit
537 537 $ cd nocommit
538 538 $ echo a > a
539 539 $ hg ci -qAma
540 540 $ echo b > b
541 541 $ hg ci -qAmb
542 542 $ hg up -q 0
543 543 $ echo c > c
544 544 $ hg ci -qAmc
545 545 $ hg log -GT "{rev}:{node|short} {desc}\n"
546 546 @ 2:d36c0562f908 c
547 547 |
548 548 | o 1:d2ae7f538514 b
549 549 |/
550 550 o 0:cb9a9f314b8b a
551 551
552 552
553 553 Check reporting when --no-commit used with non-applicable options:
554 554
555 555 $ hg graft 1 --no-commit -e
556 556 abort: cannot specify both --no-commit and --edit
557 557 [255]
558 558
559 559 $ hg graft 1 --no-commit --log
560 560 abort: cannot specify both --no-commit and --log
561 561 [255]
562 562
563 563 $ hg graft 1 --no-commit -D
564 564 abort: cannot specify both --no-commit and --currentdate
565 565 [255]
566 566
567 567 Test --no-commit is working:
568 568 $ hg graft 1 --no-commit
569 569 grafting 1:d2ae7f538514 "b"
570 570
571 571 $ hg log -GT "{rev}:{node|short} {desc}\n"
572 572 @ 2:d36c0562f908 c
573 573 |
574 574 | o 1:d2ae7f538514 b
575 575 |/
576 576 o 0:cb9a9f314b8b a
577 577
578 578
579 579 $ hg diff
580 580 diff -r d36c0562f908 b
581 581 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
582 582 +++ b/b Thu Jan 01 00:00:00 1970 +0000
583 583 @@ -0,0 +1,1 @@
584 584 +b
585 585
586 586 Prepare wrdir to check --no-commit is resepected after --continue:
587 587
588 588 $ hg up -qC
589 589 $ echo A>a
590 590 $ hg ci -qm "A in file a"
591 591 $ hg up -q 1
592 592 $ echo B>a
593 593 $ hg ci -qm "B in file a"
594 594 $ hg log -GT "{rev}:{node|short} {desc}\n"
595 595 @ 4:2aa9ad1006ff B in file a
596 596 |
597 597 | o 3:09e253b87e17 A in file a
598 598 | |
599 599 | o 2:d36c0562f908 c
600 600 | |
601 601 o | 1:d2ae7f538514 b
602 602 |/
603 603 o 0:cb9a9f314b8b a
604 604
605 605
606 606 $ hg graft 3 --no-commit
607 607 grafting 3:09e253b87e17 "A in file a"
608 608 merging a
609 609 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
610 610 abort: unresolved conflicts, can't continue
611 611 (use 'hg resolve' and 'hg graft --continue')
612 612 [1]
613 613
614 614 Resolve conflict:
615 615 $ echo A>a
616 616 $ hg resolve --mark
617 617 (no more unresolved files)
618 618 continue: hg graft --continue
619 619
620 620 $ hg graft --continue
621 621 grafting 3:09e253b87e17 "A in file a"
622 622 $ hg log -GT "{rev}:{node|short} {desc}\n"
623 623 @ 4:2aa9ad1006ff B in file a
624 624 |
625 | % 3:09e253b87e17 A in file a
625 | o 3:09e253b87e17 A in file a
626 626 | |
627 627 | o 2:d36c0562f908 c
628 628 | |
629 629 o | 1:d2ae7f538514 b
630 630 |/
631 631 o 0:cb9a9f314b8b a
632 632
633 633 $ hg diff
634 634 diff -r 2aa9ad1006ff a
635 635 --- a/a Thu Jan 01 00:00:00 1970 +0000
636 636 +++ b/a Thu Jan 01 00:00:00 1970 +0000
637 637 @@ -1,1 +1,1 @@
638 638 -B
639 639 +A
640 640
641 641 $ hg up -qC
642 642
643 643 Check --no-commit is resepected when passed with --continue:
644 644
645 645 $ hg graft 3
646 646 grafting 3:09e253b87e17 "A in file a"
647 647 merging a
648 648 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
649 649 abort: unresolved conflicts, can't continue
650 650 (use 'hg resolve' and 'hg graft --continue')
651 651 [1]
652 652
653 653 Resolve conflict:
654 654 $ echo A>a
655 655 $ hg resolve --mark
656 656 (no more unresolved files)
657 657 continue: hg graft --continue
658 658
659 659 $ hg graft --continue --no-commit
660 660 grafting 3:09e253b87e17 "A in file a"
661 661 $ hg diff
662 662 diff -r 2aa9ad1006ff a
663 663 --- a/a Thu Jan 01 00:00:00 1970 +0000
664 664 +++ b/a Thu Jan 01 00:00:00 1970 +0000
665 665 @@ -1,1 +1,1 @@
666 666 -B
667 667 +A
668 668
669 669 $ hg log -GT "{rev}:{node|short} {desc}\n"
670 670 @ 4:2aa9ad1006ff B in file a
671 671 |
672 | % 3:09e253b87e17 A in file a
672 | o 3:09e253b87e17 A in file a
673 673 | |
674 674 | o 2:d36c0562f908 c
675 675 | |
676 676 o | 1:d2ae7f538514 b
677 677 |/
678 678 o 0:cb9a9f314b8b a
679 679
680 680 $ hg up -qC
681 681
682 682 Test --no-commit when graft multiple revisions:
683 683 When there is conflict:
684 684 $ hg graft -r "2::3" --no-commit
685 685 grafting 2:d36c0562f908 "c"
686 686 grafting 3:09e253b87e17 "A in file a"
687 687 merging a
688 688 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
689 689 abort: unresolved conflicts, can't continue
690 690 (use 'hg resolve' and 'hg graft --continue')
691 691 [1]
692 692
693 693 $ echo A>a
694 694 $ hg resolve --mark
695 695 (no more unresolved files)
696 696 continue: hg graft --continue
697 697 $ hg graft --continue
698 698 grafting 3:09e253b87e17 "A in file a"
699 699 $ hg diff
700 700 diff -r 2aa9ad1006ff a
701 701 --- a/a Thu Jan 01 00:00:00 1970 +0000
702 702 +++ b/a Thu Jan 01 00:00:00 1970 +0000
703 703 @@ -1,1 +1,1 @@
704 704 -B
705 705 +A
706 706 diff -r 2aa9ad1006ff c
707 707 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
708 708 +++ b/c Thu Jan 01 00:00:00 1970 +0000
709 709 @@ -0,0 +1,1 @@
710 710 +c
711 711
712 712 $ hg log -GT "{rev}:{node|short} {desc}\n"
713 713 @ 4:2aa9ad1006ff B in file a
714 714 |
715 | % 3:09e253b87e17 A in file a
715 | o 3:09e253b87e17 A in file a
716 716 | |
717 717 | o 2:d36c0562f908 c
718 718 | |
719 719 o | 1:d2ae7f538514 b
720 720 |/
721 721 o 0:cb9a9f314b8b a
722 722
723 723 $ hg up -qC
724 724
725 725 When there is no conflict:
726 726 $ echo d>d
727 727 $ hg add d -q
728 728 $ hg ci -qmd
729 729 $ hg up 3 -q
730 730 $ hg log -GT "{rev}:{node|short} {desc}\n"
731 731 o 5:baefa8927fc0 d
732 732 |
733 733 o 4:2aa9ad1006ff B in file a
734 734 |
735 735 | @ 3:09e253b87e17 A in file a
736 736 | |
737 737 | o 2:d36c0562f908 c
738 738 | |
739 739 o | 1:d2ae7f538514 b
740 740 |/
741 741 o 0:cb9a9f314b8b a
742 742
743 743
744 744 $ hg graft -r 1 -r 5 --no-commit
745 745 grafting 1:d2ae7f538514 "b"
746 746 grafting 5:baefa8927fc0 "d" (tip)
747 747 $ hg diff
748 748 diff -r 09e253b87e17 b
749 749 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
750 750 +++ b/b Thu Jan 01 00:00:00 1970 +0000
751 751 @@ -0,0 +1,1 @@
752 752 +b
753 753 diff -r 09e253b87e17 d
754 754 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
755 755 +++ b/d Thu Jan 01 00:00:00 1970 +0000
756 756 @@ -0,0 +1,1 @@
757 757 +d
758 758 $ hg log -GT "{rev}:{node|short} {desc}\n"
759 759 o 5:baefa8927fc0 d
760 760 |
761 761 o 4:2aa9ad1006ff B in file a
762 762 |
763 763 | @ 3:09e253b87e17 A in file a
764 764 | |
765 765 | o 2:d36c0562f908 c
766 766 | |
767 767 o | 1:d2ae7f538514 b
768 768 |/
769 769 o 0:cb9a9f314b8b a
770 770
771 771 $ cd ..
@@ -1,776 +1,776 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > rebase=
4 4 > mq=
5 5 > drawdag=$TESTDIR/drawdag.py
6 6 >
7 7 > [phases]
8 8 > publish=False
9 9 >
10 10 > [alias]
11 11 > tglog = log -G --template "{rev}: {node|short} '{desc}' {branches}\n"
12 12 > tglogp = log -G --template "{rev}: {node|short} {phase} '{desc}' {branches}\n"
13 13 > EOF
14 14
15 15 Highest phase of source commits is used:
16 16
17 17 $ hg init phase
18 18 $ cd phase
19 19 $ hg debugdrawdag << 'EOF'
20 20 > D
21 21 > |
22 22 > F C
23 23 > | |
24 24 > E B
25 25 > |/
26 26 > A
27 27 > EOF
28 28
29 29 $ hg phase --force --secret D
30 30
31 31 $ cat > $TESTTMP/editor.sh <<EOF
32 32 > echo "==== before editing"
33 33 > cat \$1
34 34 > echo "===="
35 35 > echo "edited manually" >> \$1
36 36 > EOF
37 37 $ HGEDITOR="sh $TESTTMP/editor.sh" hg rebase --collapse --keepbranches -e --source B --dest F
38 38 rebasing 1:112478962961 "B" (B)
39 39 rebasing 3:26805aba1e60 "C" (C)
40 40 rebasing 5:f585351a92f8 "D" (D tip)
41 41 ==== before editing
42 42 Collapsed revision
43 43 * B
44 44 * C
45 45 * D
46 46
47 47
48 48 HG: Enter commit message. Lines beginning with 'HG:' are removed.
49 49 HG: Leave message empty to abort commit.
50 50 HG: --
51 51 HG: user: test
52 52 HG: branch 'default'
53 53 HG: added B
54 54 HG: added C
55 55 HG: added D
56 56 ====
57 57 saved backup bundle to $TESTTMP/phase/.hg/strip-backup/112478962961-cb2a9b47-rebase.hg
58 58
59 59 $ hg tglogp
60 60 o 3: 92fa5f5fe108 secret 'Collapsed revision
61 61 | * B
62 62 | * C
63 63 | * D
64 64 |
65 65 |
66 66 | edited manually'
67 67 o 2: 64a8289d2492 draft 'F'
68 68 |
69 69 o 1: 7fb047a69f22 draft 'E'
70 70 |
71 71 o 0: 426bada5c675 draft 'A'
72 72
73 73 $ hg manifest --rev tip
74 74 A
75 75 B
76 76 C
77 77 D
78 78 E
79 79 F
80 80
81 81 $ cd ..
82 82
83 83
84 84 Merge gets linearized:
85 85
86 86 $ hg init linearized-merge
87 87 $ cd linearized-merge
88 88
89 89 $ hg debugdrawdag << 'EOF'
90 90 > F D
91 91 > |/|
92 92 > C B
93 93 > |/
94 94 > A
95 95 > EOF
96 96
97 97 $ hg phase --force --secret D
98 98 $ hg rebase --source B --collapse --dest F
99 99 rebasing 1:112478962961 "B" (B)
100 100 rebasing 3:4e4f9194f9f1 "D" (D)
101 101 saved backup bundle to $TESTTMP/linearized-merge/.hg/strip-backup/112478962961-e389075b-rebase.hg
102 102
103 103 $ hg tglog
104 104 o 3: 5bdc08b7da2b 'Collapsed revision
105 105 | * B
106 106 | * D'
107 107 o 2: afc707c82df0 'F'
108 108 |
109 109 o 1: dc0947a82db8 'C'
110 110 |
111 111 o 0: 426bada5c675 'A'
112 112
113 113 $ hg manifest --rev tip
114 114 A
115 115 B
116 116 C
117 117 F
118 118
119 119 $ cd ..
120 120
121 121 Custom message:
122 122
123 123 $ hg init message
124 124 $ cd message
125 125
126 126 $ hg debugdrawdag << 'EOF'
127 127 > C
128 128 > |
129 129 > D B
130 130 > |/
131 131 > A
132 132 > EOF
133 133
134 134
135 135 $ hg rebase --base B -m 'custom message'
136 136 abort: message can only be specified with collapse
137 137 [255]
138 138
139 139 $ cat > $TESTTMP/checkeditform.sh <<EOF
140 140 > env | grep HGEDITFORM
141 141 > true
142 142 > EOF
143 143 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg rebase --source B --collapse -m 'custom message' -e --dest D
144 144 rebasing 1:112478962961 "B" (B)
145 145 rebasing 3:26805aba1e60 "C" (C tip)
146 146 HGEDITFORM=rebase.collapse
147 147 saved backup bundle to $TESTTMP/message/.hg/strip-backup/112478962961-f4131707-rebase.hg
148 148
149 149 $ hg tglog
150 150 o 2: 2f197b9a08f3 'custom message'
151 151 |
152 152 o 1: b18e25de2cf5 'D'
153 153 |
154 154 o 0: 426bada5c675 'A'
155 155
156 156 $ hg manifest --rev tip
157 157 A
158 158 B
159 159 C
160 160 D
161 161
162 162 $ cd ..
163 163
164 164 Rebase and collapse - more than one external (fail):
165 165
166 166 $ hg init multiple-external-parents
167 167 $ cd multiple-external-parents
168 168
169 169 $ hg debugdrawdag << 'EOF'
170 170 > G
171 171 > |\
172 172 > | F
173 173 > | |
174 174 > D E
175 175 > |\|
176 176 > H C B
177 177 > \|/
178 178 > A
179 179 > EOF
180 180
181 181 $ hg rebase -s C --dest H --collapse
182 182 abort: unable to collapse on top of 3, there is more than one external parent: 1, 6
183 183 [255]
184 184
185 185 Rebase and collapse - E onto H:
186 186
187 187 $ hg rebase -s E --dest H --collapse # root (E) is not a merge
188 188 rebasing 5:49cb92066bfd "E" (E)
189 189 rebasing 6:11abe3fb10b8 "F" (F)
190 190 rebasing 7:64e264db77f0 "G" (G tip)
191 191 saved backup bundle to $TESTTMP/multiple-external-parents/.hg/strip-backup/49cb92066bfd-ee8a8a79-rebase.hg
192 192
193 193 $ hg tglog
194 194 o 5: 8b2315790719 'Collapsed revision
195 195 |\ * E
196 196 | | * F
197 197 | | * G'
198 198 | o 4: 4e4f9194f9f1 'D'
199 199 | |\
200 200 o | | 3: 575c4b5ec114 'H'
201 201 | | |
202 202 +---o 2: dc0947a82db8 'C'
203 203 | |
204 204 | o 1: 112478962961 'B'
205 205 |/
206 206 o 0: 426bada5c675 'A'
207 207
208 208 $ hg manifest --rev tip
209 209 A
210 210 C
211 211 E
212 212 F
213 213 H
214 214
215 215 $ cd ..
216 216
217 217
218 218
219 219
220 220 Test that branchheads cache is updated correctly when doing a strip in which
221 221 the parent of the ancestor node to be stripped does not become a head and also,
222 222 the parent of a node that is a child of the node stripped becomes a head (node
223 223 3). The code is now much simpler and we could just test a simpler scenario
224 224 We keep it the test this way in case new complexity is injected.
225 225
226 226 Create repo b:
227 227
228 228 $ hg init branch-heads
229 229 $ cd branch-heads
230 230
231 231 $ hg debugdrawdag << 'EOF'
232 232 > G
233 233 > |\
234 234 > | F
235 235 > | |
236 236 > D E
237 237 > |\|
238 238 > H C B
239 239 > \|/
240 240 > A
241 241 > EOF
242 242
243 243 $ hg heads --template="{rev}:{node} {branch}\n"
244 244 7:64e264db77f061f16d9132b70c5a58e2461fb630 default
245 245 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default
246 246
247 247 $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served
248 248 64e264db77f061f16d9132b70c5a58e2461fb630 7
249 249 575c4b5ec114d64b681d33f8792853568bfb2b2c o default
250 250 64e264db77f061f16d9132b70c5a58e2461fb630 o default
251 251
252 252 $ hg strip 4
253 253 saved backup bundle to $TESTTMP/branch-heads/.hg/strip-backup/4e4f9194f9f1-5ec4b5e6-backup.hg
254 254
255 255 $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served
256 256 11abe3fb10b8689b560681094b17fe161871d043 5
257 257 dc0947a82db884575bb76ea10ac97b08536bfa03 o default
258 258 575c4b5ec114d64b681d33f8792853568bfb2b2c o default
259 259 11abe3fb10b8689b560681094b17fe161871d043 o default
260 260
261 261 $ hg heads --template="{rev}:{node} {branch}\n"
262 262 5:11abe3fb10b8689b560681094b17fe161871d043 default
263 263 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default
264 264 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default
265 265
266 266 $ cd ..
267 267
268 268
269 269
270 270 Preserves external parent
271 271
272 272 $ hg init external-parent
273 273 $ cd external-parent
274 274
275 275 $ hg debugdrawdag << 'EOF'
276 276 > H
277 277 > |\
278 278 > | G
279 279 > | |
280 280 > | F # F/E = F\n
281 281 > | |
282 282 > D E # D/D = D\n
283 283 > |\|
284 284 > I C B
285 285 > \|/
286 286 > A
287 287 > EOF
288 288
289 289 $ hg rebase -s F --dest I --collapse # root (F) is not a merge
290 290 rebasing 6:c82b08f646f1 "F" (F)
291 291 file 'E' was deleted in local [dest] but was modified in other [source].
292 292 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
293 293 What do you want to do? u
294 294 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
295 295 [1]
296 296
297 297 $ echo F > E
298 298 $ hg resolve -m
299 299 (no more unresolved files)
300 300 continue: hg rebase --continue
301 301 $ hg rebase -c
302 302 rebasing 6:c82b08f646f1 "F" (F)
303 303 rebasing 7:a6db7fa104e1 "G" (G)
304 304 rebasing 8:e1d201b72d91 "H" (H tip)
305 305 saved backup bundle to $TESTTMP/external-parent/.hg/strip-backup/c82b08f646f1-f2721fbf-rebase.hg
306 306
307 307 $ hg tglog
308 308 o 6: 681daa3e686d 'Collapsed revision
309 309 |\ * F
310 310 | | * G
311 311 | | * H'
312 312 | | o 5: 49cb92066bfd 'E'
313 313 | | |
314 314 | o | 4: 09143c0bf13e 'D'
315 315 | |\|
316 316 o | | 3: 08ebfeb61bac 'I'
317 317 | | |
318 318 | o | 2: dc0947a82db8 'C'
319 319 |/ /
320 320 | o 1: 112478962961 'B'
321 321 |/
322 322 o 0: 426bada5c675 'A'
323 323
324 324 $ hg manifest --rev tip
325 325 A
326 326 C
327 327 D
328 328 E
329 329 F
330 330 G
331 331 I
332 332
333 333 $ hg up tip -q
334 334 $ cat E
335 335 F
336 336
337 337 $ cd ..
338 338
339 339 Rebasing from multiple bases:
340 340
341 341 $ hg init multiple-bases
342 342 $ cd multiple-bases
343 343 $ hg debugdrawdag << 'EOF'
344 344 > C B
345 345 > D |/
346 346 > |/
347 347 > A
348 348 > EOF
349 349 $ hg rebase --collapse -r 'B+C' -d D
350 350 rebasing 1:fc2b737bb2e5 "B" (B)
351 351 rebasing 2:dc0947a82db8 "C" (C)
352 352 saved backup bundle to $TESTTMP/multiple-bases/.hg/strip-backup/dc0947a82db8-b0c1a7ea-rebase.hg
353 353 $ hg tglog
354 354 o 2: 2127ae44d291 'Collapsed revision
355 355 | * B
356 356 | * C'
357 357 o 1: b18e25de2cf5 'D'
358 358 |
359 359 o 0: 426bada5c675 'A'
360 360
361 361 $ cd ..
362 362
363 363 With non-contiguous commits:
364 364
365 365 $ hg init non-contiguous
366 366 $ cd non-contiguous
367 367 $ cat >> .hg/hgrc <<EOF
368 368 > [experimental]
369 369 > evolution=all
370 370 > EOF
371 371
372 372 $ hg debugdrawdag << 'EOF'
373 373 > F
374 374 > |
375 375 > E
376 376 > |
377 377 > D
378 378 > |
379 379 > C
380 380 > |
381 381 > B G
382 382 > |/
383 383 > A
384 384 > EOF
385 385
386 386 BROKEN: should be allowed
387 387 $ hg rebase --collapse -r 'B+D+F' -d G
388 388 abort: unable to collapse on top of 2, there is more than one external parent: 3, 5
389 389 [255]
390 390 $ cd ..
391 391
392 392
393 393 $ hg init multiple-external-parents-2
394 394 $ cd multiple-external-parents-2
395 395 $ hg debugdrawdag << 'EOF'
396 396 > D G
397 397 > |\ /|
398 398 > B C E F
399 399 > \| |/
400 400 > \ H /
401 401 > \|/
402 402 > A
403 403 > EOF
404 404
405 405 $ hg rebase --collapse -d H -s 'B+F'
406 406 abort: unable to collapse on top of 5, there is more than one external parent: 1, 3
407 407 [255]
408 408 $ cd ..
409 409
410 410 With internal merge:
411 411
412 412 $ hg init internal-merge
413 413 $ cd internal-merge
414 414
415 415 $ hg debugdrawdag << 'EOF'
416 416 > E
417 417 > |\
418 418 > C D
419 419 > |/
420 420 > F B
421 421 > |/
422 422 > A
423 423 > EOF
424 424
425 425
426 426 $ hg rebase -s B --collapse --dest F
427 427 rebasing 1:112478962961 "B" (B)
428 428 rebasing 3:26805aba1e60 "C" (C)
429 429 rebasing 4:be0ef73c17ad "D" (D)
430 430 rebasing 5:02c4367d6973 "E" (E tip)
431 431 saved backup bundle to $TESTTMP/internal-merge/.hg/strip-backup/112478962961-1dfb057b-rebase.hg
432 432
433 433 $ hg tglog
434 434 o 2: c0512a1797b0 'Collapsed revision
435 435 | * B
436 436 | * C
437 437 | * D
438 438 | * E'
439 439 o 1: 8908a377a434 'F'
440 440 |
441 441 o 0: 426bada5c675 'A'
442 442
443 443 $ hg manifest --rev tip
444 444 A
445 445 B
446 446 C
447 447 D
448 448 F
449 449 $ cd ..
450 450
451 451 Interactions between collapse and keepbranches
452 452 $ hg init e
453 453 $ cd e
454 454 $ echo 'a' > a
455 455 $ hg ci -Am 'A'
456 456 adding a
457 457
458 458 $ hg branch 'one'
459 459 marked working directory as branch one
460 460 (branches are permanent and global, did you want a bookmark?)
461 461 $ echo 'b' > b
462 462 $ hg ci -Am 'B'
463 463 adding b
464 464
465 465 $ hg branch 'two'
466 466 marked working directory as branch two
467 467 $ echo 'c' > c
468 468 $ hg ci -Am 'C'
469 469 adding c
470 470
471 471 $ hg up -q 0
472 472 $ echo 'd' > d
473 473 $ hg ci -Am 'D'
474 474 adding d
475 475
476 476 $ hg tglog
477 477 @ 3: 41acb9dca9eb 'D'
478 478 |
479 479 | o 2: 8ac4a08debf1 'C' two
480 480 | |
481 481 | o 1: 1ba175478953 'B' one
482 482 |/
483 483 o 0: 1994f17a630e 'A'
484 484
485 485 $ hg rebase --keepbranches --collapse -s 1 -d 3
486 486 abort: cannot collapse multiple named branches
487 487 [255]
488 488
489 489 $ cd ..
490 490
491 491 Rebase, collapse and copies
492 492
493 493 $ hg init copies
494 494 $ cd copies
495 495 $ hg unbundle "$TESTDIR/bundles/renames.hg"
496 496 adding changesets
497 497 adding manifests
498 498 adding file changes
499 499 added 4 changesets with 11 changes to 7 files (+1 heads)
500 500 new changesets f447d5abf5ea:338e84e2e558 (4 drafts)
501 501 (run 'hg heads' to see heads, 'hg merge' to merge)
502 502 $ hg up -q tip
503 503 $ hg tglog
504 504 @ 3: 338e84e2e558 'move2'
505 505 |
506 506 o 2: 6e7340ee38c0 'move1'
507 507 |
508 508 | o 1: 1352765a01d4 'change'
509 509 |/
510 510 o 0: f447d5abf5ea 'add'
511 511
512 512 $ hg rebase --collapse -d 1
513 513 rebasing 2:6e7340ee38c0 "move1"
514 514 merging a and d to d
515 515 merging b and e to e
516 516 merging c and f to f
517 517 rebasing 3:338e84e2e558 "move2" (tip)
518 518 merging f and c to c
519 519 merging e and g to g
520 520 saved backup bundle to $TESTTMP/copies/.hg/strip-backup/6e7340ee38c0-ef8ef003-rebase.hg
521 521 $ hg st
522 522 $ hg st --copies --change tip
523 523 A d
524 524 a
525 525 A g
526 526 b
527 527 R b
528 528 $ hg up tip -q
529 529 $ cat c
530 530 c
531 531 c
532 532 $ cat d
533 533 a
534 534 a
535 535 $ cat g
536 536 b
537 537 b
538 538 $ hg log -r . --template "{file_copies}\n"
539 539 d (a)g (b)
540 540
541 541 Test collapsing a middle revision in-place
542 542
543 543 $ hg tglog
544 544 @ 2: 64b456429f67 'Collapsed revision
545 545 | * move1
546 546 | * move2'
547 547 o 1: 1352765a01d4 'change'
548 548 |
549 549 o 0: f447d5abf5ea 'add'
550 550
551 551 $ hg rebase --collapse -r 1 -d 0
552 552 abort: cannot rebase changeset with children
553 553 (use --keep to keep original changesets)
554 554 [255]
555 555
556 556 Test collapsing in place
557 557
558 558 $ hg rebase --collapse -b . -d 0
559 559 rebasing 1:1352765a01d4 "change"
560 560 rebasing 2:64b456429f67 "Collapsed revision" (tip)
561 561 saved backup bundle to $TESTTMP/copies/.hg/strip-backup/1352765a01d4-45a352ea-rebase.hg
562 562 $ hg st --change tip --copies
563 563 M a
564 564 M c
565 565 A d
566 566 a
567 567 A g
568 568 b
569 569 R b
570 570 $ hg up tip -q
571 571 $ cat a
572 572 a
573 573 a
574 574 $ cat c
575 575 c
576 576 c
577 577 $ cat d
578 578 a
579 579 a
580 580 $ cat g
581 581 b
582 582 b
583 583 $ cd ..
584 584
585 585
586 586 Test stripping a revision with another child
587 587
588 588 $ hg init f
589 589 $ cd f
590 590
591 591 $ hg debugdrawdag << 'EOF'
592 592 > C B
593 593 > |/
594 594 > A
595 595 > EOF
596 596
597 597 $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
598 598 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default: C
599 599 1:112478962961147124edd43549aedd1a335e44bf default: B
600 600
601 601 $ hg strip C
602 602 saved backup bundle to $TESTTMP/f/.hg/strip-backup/dc0947a82db8-d21b92a4-backup.hg
603 603
604 604 $ hg tglog
605 605 o 1: 112478962961 'B'
606 606 |
607 607 o 0: 426bada5c675 'A'
608 608
609 609
610 610
611 611 $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
612 612 1:112478962961147124edd43549aedd1a335e44bf default: B
613 613
614 614 $ cd ..
615 615
616 616 Test collapsing changes that add then remove a file
617 617
618 618 $ hg init collapseaddremove
619 619 $ cd collapseaddremove
620 620
621 621 $ touch base
622 622 $ hg commit -Am base
623 623 adding base
624 624 $ touch a
625 625 $ hg commit -Am a
626 626 adding a
627 627 $ hg rm a
628 628 $ touch b
629 629 $ hg commit -Am b
630 630 adding b
631 631 $ hg book foo
632 632 $ hg rebase -d 0 -r "1::2" --collapse -m collapsed
633 633 rebasing 1:6d8d9f24eec3 "a"
634 634 rebasing 2:1cc73eca5ecc "b" (foo tip)
635 635 saved backup bundle to $TESTTMP/collapseaddremove/.hg/strip-backup/6d8d9f24eec3-77d3b6e2-rebase.hg
636 636 $ hg log -G --template "{rev}: '{desc}' {bookmarks}"
637 637 @ 1: 'collapsed' foo
638 638 |
639 639 o 0: 'base'
640 640
641 641 $ hg manifest --rev tip
642 642 b
643 643 base
644 644
645 645 $ cd ..
646 646
647 647 Test that rebase --collapse will remember message after
648 648 running into merge conflict and invoking rebase --continue.
649 649
650 650 $ hg init collapse_remember_message
651 651 $ cd collapse_remember_message
652 652 $ hg debugdrawdag << 'EOF'
653 653 > C B # B/A = B\n
654 654 > |/ # C/A = C\n
655 655 > A
656 656 > EOF
657 657 $ hg rebase --collapse -m "new message" -b B -d C
658 658 rebasing 1:81e5401e4d37 "B" (B)
659 659 merging A
660 660 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
661 661 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
662 662 [1]
663 663 $ rm A.orig
664 664 $ hg resolve --mark A
665 665 (no more unresolved files)
666 666 continue: hg rebase --continue
667 667 $ hg rebase --continue
668 668 rebasing 1:81e5401e4d37 "B" (B)
669 669 saved backup bundle to $TESTTMP/collapse_remember_message/.hg/strip-backup/81e5401e4d37-96c3dd30-rebase.hg
670 670 $ hg log
671 671 changeset: 2:17186933e123
672 672 tag: tip
673 673 user: test
674 674 date: Thu Jan 01 00:00:00 1970 +0000
675 675 summary: new message
676 676
677 677 changeset: 1:043039e9df84
678 678 tag: C
679 679 user: test
680 680 date: Thu Jan 01 00:00:00 1970 +0000
681 681 summary: C
682 682
683 683 changeset: 0:426bada5c675
684 684 tag: A
685 685 user: test
686 686 date: Thu Jan 01 00:00:00 1970 +0000
687 687 summary: A
688 688
689 689 $ cd ..
690 690
691 691 Test aborted editor on final message
692 692
693 693 $ HGMERGE=:merge3
694 694 $ export HGMERGE
695 695 $ hg init aborted-editor
696 696 $ cd aborted-editor
697 697 $ hg debugdrawdag << 'EOF'
698 698 > C # D/A = D\n
699 699 > | # C/A = C\n
700 700 > B D # B/A = B\n
701 701 > |/ # A/A = A\n
702 702 > A
703 703 > EOF
704 704 $ hg rebase --collapse -t internal:merge3 -s B -d D
705 705 rebasing 1:f899f3910ce7 "B" (B)
706 706 merging A
707 707 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
708 708 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
709 709 [1]
710 710 $ hg tglog
711 711 o 3: 63668d570d21 'C'
712 712 |
713 713 | @ 2: 82b8abf9c185 'D'
714 714 | |
715 715 % | 1: f899f3910ce7 'B'
716 716 |/
717 717 o 0: 4a2df7238c3b 'A'
718 718
719 719 $ cat A
720 720 <<<<<<< dest: 82b8abf9c185 D - test: D
721 721 D
722 722 ||||||| base
723 723 A
724 724 =======
725 725 B
726 726 >>>>>>> source: f899f3910ce7 B - test: B
727 727 $ echo BC > A
728 728 $ hg resolve -m
729 729 (no more unresolved files)
730 730 continue: hg rebase --continue
731 731 $ hg rebase --continue
732 732 rebasing 1:f899f3910ce7 "B" (B)
733 733 rebasing 3:63668d570d21 "C" (C tip)
734 734 merging A
735 735 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
736 736 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
737 737 [1]
738 738 $ hg tglog
739 739 % 3: 63668d570d21 'C'
740 740 |
741 741 | @ 2: 82b8abf9c185 'D'
742 742 | |
743 743 o | 1: f899f3910ce7 'B'
744 744 |/
745 745 o 0: 4a2df7238c3b 'A'
746 746
747 747 $ cat A
748 748 <<<<<<< dest: 82b8abf9c185 D - test: D
749 749 BC
750 750 ||||||| base
751 751 B
752 752 =======
753 753 C
754 754 >>>>>>> source: 63668d570d21 C tip - test: C
755 755 $ echo BD > A
756 756 $ hg resolve -m
757 757 (no more unresolved files)
758 758 continue: hg rebase --continue
759 759 $ HGEDITOR=false hg rebase --continue --config ui.interactive=1
760 760 already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185
761 761 rebasing 3:63668d570d21 "C" (C tip)
762 762 abort: edit failed: false exited with status 1
763 763 [255]
764 764 $ hg tglog
765 % 3: 63668d570d21 'C'
765 o 3: 63668d570d21 'C'
766 766 |
767 767 | @ 2: 82b8abf9c185 'D'
768 768 | |
769 769 o | 1: f899f3910ce7 'B'
770 770 |/
771 771 o 0: 4a2df7238c3b 'A'
772 772
773 773 $ hg rebase --continue
774 774 already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185
775 775 already rebased 3:63668d570d21 "C" (C tip) as 82b8abf9c185
776 776 saved backup bundle to $TESTTMP/aborted-editor/.hg/strip-backup/f899f3910ce7-7cab5e15-rebase.hg
General Comments 0
You need to be logged in to leave comments. Login now