##// END OF EJS Templates
debugmergestate: make templated...
Martin von Zweigbergk -
r44841:088ab52a default draft
parent child Browse files
Show More
@@ -1,4367 +1,4330 b''
1 1 # debugcommands.py - command processing for debug* commands
2 2 #
3 3 # Copyright 2005-2016 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 import codecs
11 11 import collections
12 12 import difflib
13 13 import errno
14 14 import operator
15 15 import os
16 16 import platform
17 17 import random
18 18 import re
19 19 import socket
20 20 import ssl
21 21 import stat
22 22 import string
23 23 import subprocess
24 24 import sys
25 25 import time
26 26
27 27 from .i18n import _
28 28 from .node import (
29 29 bin,
30 30 hex,
31 nullhex,
32 31 nullid,
33 32 nullrev,
34 33 short,
35 34 )
36 35 from .pycompat import (
37 36 getattr,
38 37 open,
39 38 )
40 39 from . import (
41 40 bundle2,
42 41 changegroup,
43 42 cmdutil,
44 43 color,
45 44 context,
46 45 copies,
47 46 dagparser,
48 47 encoding,
49 48 error,
50 49 exchange,
51 50 extensions,
52 51 filemerge,
53 52 filesetlang,
54 53 formatter,
55 54 hg,
56 55 httppeer,
57 56 localrepo,
58 57 lock as lockmod,
59 58 logcmdutil,
60 59 merge as mergemod,
61 60 obsolete,
62 61 obsutil,
63 62 pathutil,
64 63 phases,
65 64 policy,
66 65 pvec,
67 66 pycompat,
68 67 registrar,
69 68 repair,
70 69 revlog,
71 70 revset,
72 71 revsetlang,
73 72 scmutil,
74 73 setdiscovery,
75 74 simplemerge,
76 75 sshpeer,
77 76 sslutil,
78 77 streamclone,
79 78 tags as tagsmod,
80 79 templater,
81 80 treediscovery,
82 81 upgrade,
83 82 url as urlmod,
84 83 util,
85 84 vfs as vfsmod,
86 85 wireprotoframing,
87 86 wireprotoserver,
88 87 wireprotov2peer,
89 88 )
90 89 from .utils import (
91 90 cborutil,
92 91 compression,
93 92 dateutil,
94 93 procutil,
95 94 stringutil,
96 95 )
97 96
98 97 from .revlogutils import (
99 98 deltas as deltautil,
100 99 nodemap,
101 100 )
102 101
103 102 release = lockmod.release
104 103
105 104 command = registrar.command()
106 105
107 106
108 107 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
109 108 def debugancestor(ui, repo, *args):
110 109 """find the ancestor revision of two revisions in a given index"""
111 110 if len(args) == 3:
112 111 index, rev1, rev2 = args
113 112 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
114 113 lookup = r.lookup
115 114 elif len(args) == 2:
116 115 if not repo:
117 116 raise error.Abort(
118 117 _(b'there is no Mercurial repository here (.hg not found)')
119 118 )
120 119 rev1, rev2 = args
121 120 r = repo.changelog
122 121 lookup = repo.lookup
123 122 else:
124 123 raise error.Abort(_(b'either two or three arguments required'))
125 124 a = r.ancestor(lookup(rev1), lookup(rev2))
126 125 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
127 126
128 127
129 128 @command(b'debugapplystreamclonebundle', [], b'FILE')
130 129 def debugapplystreamclonebundle(ui, repo, fname):
131 130 """apply a stream clone bundle file"""
132 131 f = hg.openpath(ui, fname)
133 132 gen = exchange.readbundle(ui, f, fname)
134 133 gen.apply(repo)
135 134
136 135
137 136 @command(
138 137 b'debugbuilddag',
139 138 [
140 139 (
141 140 b'm',
142 141 b'mergeable-file',
143 142 None,
144 143 _(b'add single file mergeable changes'),
145 144 ),
146 145 (
147 146 b'o',
148 147 b'overwritten-file',
149 148 None,
150 149 _(b'add single file all revs overwrite'),
151 150 ),
152 151 (b'n', b'new-file', None, _(b'add new file at each rev')),
153 152 ],
154 153 _(b'[OPTION]... [TEXT]'),
155 154 )
156 155 def debugbuilddag(
157 156 ui,
158 157 repo,
159 158 text=None,
160 159 mergeable_file=False,
161 160 overwritten_file=False,
162 161 new_file=False,
163 162 ):
164 163 """builds a repo with a given DAG from scratch in the current empty repo
165 164
166 165 The description of the DAG is read from stdin if not given on the
167 166 command line.
168 167
169 168 Elements:
170 169
171 170 - "+n" is a linear run of n nodes based on the current default parent
172 171 - "." is a single node based on the current default parent
173 172 - "$" resets the default parent to null (implied at the start);
174 173 otherwise the default parent is always the last node created
175 174 - "<p" sets the default parent to the backref p
176 175 - "*p" is a fork at parent p, which is a backref
177 176 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
178 177 - "/p2" is a merge of the preceding node and p2
179 178 - ":tag" defines a local tag for the preceding node
180 179 - "@branch" sets the named branch for subsequent nodes
181 180 - "#...\\n" is a comment up to the end of the line
182 181
183 182 Whitespace between the above elements is ignored.
184 183
185 184 A backref is either
186 185
187 186 - a number n, which references the node curr-n, where curr is the current
188 187 node, or
189 188 - the name of a local tag you placed earlier using ":tag", or
190 189 - empty to denote the default parent.
191 190
192 191 All string valued-elements are either strictly alphanumeric, or must
193 192 be enclosed in double quotes ("..."), with "\\" as escape character.
194 193 """
195 194
196 195 if text is None:
197 196 ui.status(_(b"reading DAG from stdin\n"))
198 197 text = ui.fin.read()
199 198
200 199 cl = repo.changelog
201 200 if len(cl) > 0:
202 201 raise error.Abort(_(b'repository is not empty'))
203 202
204 203 # determine number of revs in DAG
205 204 total = 0
206 205 for type, data in dagparser.parsedag(text):
207 206 if type == b'n':
208 207 total += 1
209 208
210 209 if mergeable_file:
211 210 linesperrev = 2
212 211 # make a file with k lines per rev
213 212 initialmergedlines = [
214 213 b'%d' % i for i in pycompat.xrange(0, total * linesperrev)
215 214 ]
216 215 initialmergedlines.append(b"")
217 216
218 217 tags = []
219 218 progress = ui.makeprogress(
220 219 _(b'building'), unit=_(b'revisions'), total=total
221 220 )
222 221 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
223 222 at = -1
224 223 atbranch = b'default'
225 224 nodeids = []
226 225 id = 0
227 226 progress.update(id)
228 227 for type, data in dagparser.parsedag(text):
229 228 if type == b'n':
230 229 ui.note((b'node %s\n' % pycompat.bytestr(data)))
231 230 id, ps = data
232 231
233 232 files = []
234 233 filecontent = {}
235 234
236 235 p2 = None
237 236 if mergeable_file:
238 237 fn = b"mf"
239 238 p1 = repo[ps[0]]
240 239 if len(ps) > 1:
241 240 p2 = repo[ps[1]]
242 241 pa = p1.ancestor(p2)
243 242 base, local, other = [
244 243 x[fn].data() for x in (pa, p1, p2)
245 244 ]
246 245 m3 = simplemerge.Merge3Text(base, local, other)
247 246 ml = [l.strip() for l in m3.merge_lines()]
248 247 ml.append(b"")
249 248 elif at > 0:
250 249 ml = p1[fn].data().split(b"\n")
251 250 else:
252 251 ml = initialmergedlines
253 252 ml[id * linesperrev] += b" r%i" % id
254 253 mergedtext = b"\n".join(ml)
255 254 files.append(fn)
256 255 filecontent[fn] = mergedtext
257 256
258 257 if overwritten_file:
259 258 fn = b"of"
260 259 files.append(fn)
261 260 filecontent[fn] = b"r%i\n" % id
262 261
263 262 if new_file:
264 263 fn = b"nf%i" % id
265 264 files.append(fn)
266 265 filecontent[fn] = b"r%i\n" % id
267 266 if len(ps) > 1:
268 267 if not p2:
269 268 p2 = repo[ps[1]]
270 269 for fn in p2:
271 270 if fn.startswith(b"nf"):
272 271 files.append(fn)
273 272 filecontent[fn] = p2[fn].data()
274 273
275 274 def fctxfn(repo, cx, path):
276 275 if path in filecontent:
277 276 return context.memfilectx(
278 277 repo, cx, path, filecontent[path]
279 278 )
280 279 return None
281 280
282 281 if len(ps) == 0 or ps[0] < 0:
283 282 pars = [None, None]
284 283 elif len(ps) == 1:
285 284 pars = [nodeids[ps[0]], None]
286 285 else:
287 286 pars = [nodeids[p] for p in ps]
288 287 cx = context.memctx(
289 288 repo,
290 289 pars,
291 290 b"r%i" % id,
292 291 files,
293 292 fctxfn,
294 293 date=(id, 0),
295 294 user=b"debugbuilddag",
296 295 extra={b'branch': atbranch},
297 296 )
298 297 nodeid = repo.commitctx(cx)
299 298 nodeids.append(nodeid)
300 299 at = id
301 300 elif type == b'l':
302 301 id, name = data
303 302 ui.note((b'tag %s\n' % name))
304 303 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
305 304 elif type == b'a':
306 305 ui.note((b'branch %s\n' % data))
307 306 atbranch = data
308 307 progress.update(id)
309 308
310 309 if tags:
311 310 repo.vfs.write(b"localtags", b"".join(tags))
312 311
313 312
314 313 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
315 314 indent_string = b' ' * indent
316 315 if all:
317 316 ui.writenoi18n(
318 317 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
319 318 % indent_string
320 319 )
321 320
322 321 def showchunks(named):
323 322 ui.write(b"\n%s%s\n" % (indent_string, named))
324 323 for deltadata in gen.deltaiter():
325 324 node, p1, p2, cs, deltabase, delta, flags = deltadata
326 325 ui.write(
327 326 b"%s%s %s %s %s %s %d\n"
328 327 % (
329 328 indent_string,
330 329 hex(node),
331 330 hex(p1),
332 331 hex(p2),
333 332 hex(cs),
334 333 hex(deltabase),
335 334 len(delta),
336 335 )
337 336 )
338 337
339 338 gen.changelogheader()
340 339 showchunks(b"changelog")
341 340 gen.manifestheader()
342 341 showchunks(b"manifest")
343 342 for chunkdata in iter(gen.filelogheader, {}):
344 343 fname = chunkdata[b'filename']
345 344 showchunks(fname)
346 345 else:
347 346 if isinstance(gen, bundle2.unbundle20):
348 347 raise error.Abort(_(b'use debugbundle2 for this file'))
349 348 gen.changelogheader()
350 349 for deltadata in gen.deltaiter():
351 350 node, p1, p2, cs, deltabase, delta, flags = deltadata
352 351 ui.write(b"%s%s\n" % (indent_string, hex(node)))
353 352
354 353
355 354 def _debugobsmarkers(ui, part, indent=0, **opts):
356 355 """display version and markers contained in 'data'"""
357 356 opts = pycompat.byteskwargs(opts)
358 357 data = part.read()
359 358 indent_string = b' ' * indent
360 359 try:
361 360 version, markers = obsolete._readmarkers(data)
362 361 except error.UnknownVersion as exc:
363 362 msg = b"%sunsupported version: %s (%d bytes)\n"
364 363 msg %= indent_string, exc.version, len(data)
365 364 ui.write(msg)
366 365 else:
367 366 msg = b"%sversion: %d (%d bytes)\n"
368 367 msg %= indent_string, version, len(data)
369 368 ui.write(msg)
370 369 fm = ui.formatter(b'debugobsolete', opts)
371 370 for rawmarker in sorted(markers):
372 371 m = obsutil.marker(None, rawmarker)
373 372 fm.startitem()
374 373 fm.plain(indent_string)
375 374 cmdutil.showmarker(fm, m)
376 375 fm.end()
377 376
378 377
379 378 def _debugphaseheads(ui, data, indent=0):
380 379 """display version and markers contained in 'data'"""
381 380 indent_string = b' ' * indent
382 381 headsbyphase = phases.binarydecode(data)
383 382 for phase in phases.allphases:
384 383 for head in headsbyphase[phase]:
385 384 ui.write(indent_string)
386 385 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
387 386
388 387
389 388 def _quasirepr(thing):
390 389 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
391 390 return b'{%s}' % (
392 391 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
393 392 )
394 393 return pycompat.bytestr(repr(thing))
395 394
396 395
397 396 def _debugbundle2(ui, gen, all=None, **opts):
398 397 """lists the contents of a bundle2"""
399 398 if not isinstance(gen, bundle2.unbundle20):
400 399 raise error.Abort(_(b'not a bundle2 file'))
401 400 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
402 401 parttypes = opts.get('part_type', [])
403 402 for part in gen.iterparts():
404 403 if parttypes and part.type not in parttypes:
405 404 continue
406 405 msg = b'%s -- %s (mandatory: %r)\n'
407 406 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
408 407 if part.type == b'changegroup':
409 408 version = part.params.get(b'version', b'01')
410 409 cg = changegroup.getunbundler(version, part, b'UN')
411 410 if not ui.quiet:
412 411 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
413 412 if part.type == b'obsmarkers':
414 413 if not ui.quiet:
415 414 _debugobsmarkers(ui, part, indent=4, **opts)
416 415 if part.type == b'phase-heads':
417 416 if not ui.quiet:
418 417 _debugphaseheads(ui, part, indent=4)
419 418
420 419
421 420 @command(
422 421 b'debugbundle',
423 422 [
424 423 (b'a', b'all', None, _(b'show all details')),
425 424 (b'', b'part-type', [], _(b'show only the named part type')),
426 425 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
427 426 ],
428 427 _(b'FILE'),
429 428 norepo=True,
430 429 )
431 430 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
432 431 """lists the contents of a bundle"""
433 432 with hg.openpath(ui, bundlepath) as f:
434 433 if spec:
435 434 spec = exchange.getbundlespec(ui, f)
436 435 ui.write(b'%s\n' % spec)
437 436 return
438 437
439 438 gen = exchange.readbundle(ui, f, bundlepath)
440 439 if isinstance(gen, bundle2.unbundle20):
441 440 return _debugbundle2(ui, gen, all=all, **opts)
442 441 _debugchangegroup(ui, gen, all=all, **opts)
443 442
444 443
445 444 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
446 445 def debugcapabilities(ui, path, **opts):
447 446 """lists the capabilities of a remote peer"""
448 447 opts = pycompat.byteskwargs(opts)
449 448 peer = hg.peer(ui, opts, path)
450 449 caps = peer.capabilities()
451 450 ui.writenoi18n(b'Main capabilities:\n')
452 451 for c in sorted(caps):
453 452 ui.write(b' %s\n' % c)
454 453 b2caps = bundle2.bundle2caps(peer)
455 454 if b2caps:
456 455 ui.writenoi18n(b'Bundle2 capabilities:\n')
457 456 for key, values in sorted(pycompat.iteritems(b2caps)):
458 457 ui.write(b' %s\n' % key)
459 458 for v in values:
460 459 ui.write(b' %s\n' % v)
461 460
462 461
463 462 @command(b'debugcheckstate', [], b'')
464 463 def debugcheckstate(ui, repo):
465 464 """validate the correctness of the current dirstate"""
466 465 parent1, parent2 = repo.dirstate.parents()
467 466 m1 = repo[parent1].manifest()
468 467 m2 = repo[parent2].manifest()
469 468 errors = 0
470 469 for f in repo.dirstate:
471 470 state = repo.dirstate[f]
472 471 if state in b"nr" and f not in m1:
473 472 ui.warn(_(b"%s in state %s, but not in manifest1\n") % (f, state))
474 473 errors += 1
475 474 if state in b"a" and f in m1:
476 475 ui.warn(_(b"%s in state %s, but also in manifest1\n") % (f, state))
477 476 errors += 1
478 477 if state in b"m" and f not in m1 and f not in m2:
479 478 ui.warn(
480 479 _(b"%s in state %s, but not in either manifest\n") % (f, state)
481 480 )
482 481 errors += 1
483 482 for f in m1:
484 483 state = repo.dirstate[f]
485 484 if state not in b"nrm":
486 485 ui.warn(_(b"%s in manifest1, but listed as state %s") % (f, state))
487 486 errors += 1
488 487 if errors:
489 488 errstr = _(b".hg/dirstate inconsistent with current parent's manifest")
490 489 raise error.Abort(errstr)
491 490
492 491
493 492 @command(
494 493 b'debugcolor',
495 494 [(b'', b'style', None, _(b'show all configured styles'))],
496 495 b'hg debugcolor',
497 496 )
498 497 def debugcolor(ui, repo, **opts):
499 498 """show available color, effects or style"""
500 499 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
501 500 if opts.get('style'):
502 501 return _debugdisplaystyle(ui)
503 502 else:
504 503 return _debugdisplaycolor(ui)
505 504
506 505
507 506 def _debugdisplaycolor(ui):
508 507 ui = ui.copy()
509 508 ui._styles.clear()
510 509 for effect in color._activeeffects(ui).keys():
511 510 ui._styles[effect] = effect
512 511 if ui._terminfoparams:
513 512 for k, v in ui.configitems(b'color'):
514 513 if k.startswith(b'color.'):
515 514 ui._styles[k] = k[6:]
516 515 elif k.startswith(b'terminfo.'):
517 516 ui._styles[k] = k[9:]
518 517 ui.write(_(b'available colors:\n'))
519 518 # sort label with a '_' after the other to group '_background' entry.
520 519 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
521 520 for colorname, label in items:
522 521 ui.write(b'%s\n' % colorname, label=label)
523 522
524 523
525 524 def _debugdisplaystyle(ui):
526 525 ui.write(_(b'available style:\n'))
527 526 if not ui._styles:
528 527 return
529 528 width = max(len(s) for s in ui._styles)
530 529 for label, effects in sorted(ui._styles.items()):
531 530 ui.write(b'%s' % label, label=label)
532 531 if effects:
533 532 # 50
534 533 ui.write(b': ')
535 534 ui.write(b' ' * (max(0, width - len(label))))
536 535 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
537 536 ui.write(b'\n')
538 537
539 538
540 539 @command(b'debugcreatestreamclonebundle', [], b'FILE')
541 540 def debugcreatestreamclonebundle(ui, repo, fname):
542 541 """create a stream clone bundle file
543 542
544 543 Stream bundles are special bundles that are essentially archives of
545 544 revlog files. They are commonly used for cloning very quickly.
546 545 """
547 546 # TODO we may want to turn this into an abort when this functionality
548 547 # is moved into `hg bundle`.
549 548 if phases.hassecret(repo):
550 549 ui.warn(
551 550 _(
552 551 b'(warning: stream clone bundle will contain secret '
553 552 b'revisions)\n'
554 553 )
555 554 )
556 555
557 556 requirements, gen = streamclone.generatebundlev1(repo)
558 557 changegroup.writechunks(ui, gen, fname)
559 558
560 559 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
561 560
562 561
563 562 @command(
564 563 b'debugdag',
565 564 [
566 565 (b't', b'tags', None, _(b'use tags as labels')),
567 566 (b'b', b'branches', None, _(b'annotate with branch names')),
568 567 (b'', b'dots', None, _(b'use dots for runs')),
569 568 (b's', b'spaces', None, _(b'separate elements by spaces')),
570 569 ],
571 570 _(b'[OPTION]... [FILE [REV]...]'),
572 571 optionalrepo=True,
573 572 )
574 573 def debugdag(ui, repo, file_=None, *revs, **opts):
575 574 """format the changelog or an index DAG as a concise textual description
576 575
577 576 If you pass a revlog index, the revlog's DAG is emitted. If you list
578 577 revision numbers, they get labeled in the output as rN.
579 578
580 579 Otherwise, the changelog DAG of the current repo is emitted.
581 580 """
582 581 spaces = opts.get('spaces')
583 582 dots = opts.get('dots')
584 583 if file_:
585 584 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
586 585 revs = set((int(r) for r in revs))
587 586
588 587 def events():
589 588 for r in rlog:
590 589 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
591 590 if r in revs:
592 591 yield b'l', (r, b"r%i" % r)
593 592
594 593 elif repo:
595 594 cl = repo.changelog
596 595 tags = opts.get('tags')
597 596 branches = opts.get('branches')
598 597 if tags:
599 598 labels = {}
600 599 for l, n in repo.tags().items():
601 600 labels.setdefault(cl.rev(n), []).append(l)
602 601
603 602 def events():
604 603 b = b"default"
605 604 for r in cl:
606 605 if branches:
607 606 newb = cl.read(cl.node(r))[5][b'branch']
608 607 if newb != b:
609 608 yield b'a', newb
610 609 b = newb
611 610 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
612 611 if tags:
613 612 ls = labels.get(r)
614 613 if ls:
615 614 for l in ls:
616 615 yield b'l', (r, l)
617 616
618 617 else:
619 618 raise error.Abort(_(b'need repo for changelog dag'))
620 619
621 620 for line in dagparser.dagtextlines(
622 621 events(),
623 622 addspaces=spaces,
624 623 wraplabels=True,
625 624 wrapannotations=True,
626 625 wrapnonlinear=dots,
627 626 usedots=dots,
628 627 maxlinewidth=70,
629 628 ):
630 629 ui.write(line)
631 630 ui.write(b"\n")
632 631
633 632
634 633 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
635 634 def debugdata(ui, repo, file_, rev=None, **opts):
636 635 """dump the contents of a data file revision"""
637 636 opts = pycompat.byteskwargs(opts)
638 637 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
639 638 if rev is not None:
640 639 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
641 640 file_, rev = None, file_
642 641 elif rev is None:
643 642 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
644 643 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
645 644 try:
646 645 ui.write(r.rawdata(r.lookup(rev)))
647 646 except KeyError:
648 647 raise error.Abort(_(b'invalid revision identifier %s') % rev)
649 648
650 649
651 650 @command(
652 651 b'debugdate',
653 652 [(b'e', b'extended', None, _(b'try extended date formats'))],
654 653 _(b'[-e] DATE [RANGE]'),
655 654 norepo=True,
656 655 optionalrepo=True,
657 656 )
658 657 def debugdate(ui, date, range=None, **opts):
659 658 """parse and display a date"""
660 659 if opts["extended"]:
661 660 d = dateutil.parsedate(date, dateutil.extendeddateformats)
662 661 else:
663 662 d = dateutil.parsedate(date)
664 663 ui.writenoi18n(b"internal: %d %d\n" % d)
665 664 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
666 665 if range:
667 666 m = dateutil.matchdate(range)
668 667 ui.writenoi18n(b"match: %s\n" % m(d[0]))
669 668
670 669
671 670 @command(
672 671 b'debugdeltachain',
673 672 cmdutil.debugrevlogopts + cmdutil.formatteropts,
674 673 _(b'-c|-m|FILE'),
675 674 optionalrepo=True,
676 675 )
677 676 def debugdeltachain(ui, repo, file_=None, **opts):
678 677 """dump information about delta chains in a revlog
679 678
680 679 Output can be templatized. Available template keywords are:
681 680
682 681 :``rev``: revision number
683 682 :``chainid``: delta chain identifier (numbered by unique base)
684 683 :``chainlen``: delta chain length to this revision
685 684 :``prevrev``: previous revision in delta chain
686 685 :``deltatype``: role of delta / how it was computed
687 686 :``compsize``: compressed size of revision
688 687 :``uncompsize``: uncompressed size of revision
689 688 :``chainsize``: total size of compressed revisions in chain
690 689 :``chainratio``: total chain size divided by uncompressed revision size
691 690 (new delta chains typically start at ratio 2.00)
692 691 :``lindist``: linear distance from base revision in delta chain to end
693 692 of this revision
694 693 :``extradist``: total size of revisions not part of this delta chain from
695 694 base of delta chain to end of this revision; a measurement
696 695 of how much extra data we need to read/seek across to read
697 696 the delta chain for this revision
698 697 :``extraratio``: extradist divided by chainsize; another representation of
699 698 how much unrelated data is needed to load this delta chain
700 699
701 700 If the repository is configured to use the sparse read, additional keywords
702 701 are available:
703 702
704 703 :``readsize``: total size of data read from the disk for a revision
705 704 (sum of the sizes of all the blocks)
706 705 :``largestblock``: size of the largest block of data read from the disk
707 706 :``readdensity``: density of useful bytes in the data read from the disk
708 707 :``srchunks``: in how many data hunks the whole revision would be read
709 708
710 709 The sparse read can be enabled with experimental.sparse-read = True
711 710 """
712 711 opts = pycompat.byteskwargs(opts)
713 712 r = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
714 713 index = r.index
715 714 start = r.start
716 715 length = r.length
717 716 generaldelta = r.version & revlog.FLAG_GENERALDELTA
718 717 withsparseread = getattr(r, '_withsparseread', False)
719 718
720 719 def revinfo(rev):
721 720 e = index[rev]
722 721 compsize = e[1]
723 722 uncompsize = e[2]
724 723 chainsize = 0
725 724
726 725 if generaldelta:
727 726 if e[3] == e[5]:
728 727 deltatype = b'p1'
729 728 elif e[3] == e[6]:
730 729 deltatype = b'p2'
731 730 elif e[3] == rev - 1:
732 731 deltatype = b'prev'
733 732 elif e[3] == rev:
734 733 deltatype = b'base'
735 734 else:
736 735 deltatype = b'other'
737 736 else:
738 737 if e[3] == rev:
739 738 deltatype = b'base'
740 739 else:
741 740 deltatype = b'prev'
742 741
743 742 chain = r._deltachain(rev)[0]
744 743 for iterrev in chain:
745 744 e = index[iterrev]
746 745 chainsize += e[1]
747 746
748 747 return compsize, uncompsize, deltatype, chain, chainsize
749 748
750 749 fm = ui.formatter(b'debugdeltachain', opts)
751 750
752 751 fm.plain(
753 752 b' rev chain# chainlen prev delta '
754 753 b'size rawsize chainsize ratio lindist extradist '
755 754 b'extraratio'
756 755 )
757 756 if withsparseread:
758 757 fm.plain(b' readsize largestblk rddensity srchunks')
759 758 fm.plain(b'\n')
760 759
761 760 chainbases = {}
762 761 for rev in r:
763 762 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
764 763 chainbase = chain[0]
765 764 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
766 765 basestart = start(chainbase)
767 766 revstart = start(rev)
768 767 lineardist = revstart + comp - basestart
769 768 extradist = lineardist - chainsize
770 769 try:
771 770 prevrev = chain[-2]
772 771 except IndexError:
773 772 prevrev = -1
774 773
775 774 if uncomp != 0:
776 775 chainratio = float(chainsize) / float(uncomp)
777 776 else:
778 777 chainratio = chainsize
779 778
780 779 if chainsize != 0:
781 780 extraratio = float(extradist) / float(chainsize)
782 781 else:
783 782 extraratio = extradist
784 783
785 784 fm.startitem()
786 785 fm.write(
787 786 b'rev chainid chainlen prevrev deltatype compsize '
788 787 b'uncompsize chainsize chainratio lindist extradist '
789 788 b'extraratio',
790 789 b'%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
791 790 rev,
792 791 chainid,
793 792 len(chain),
794 793 prevrev,
795 794 deltatype,
796 795 comp,
797 796 uncomp,
798 797 chainsize,
799 798 chainratio,
800 799 lineardist,
801 800 extradist,
802 801 extraratio,
803 802 rev=rev,
804 803 chainid=chainid,
805 804 chainlen=len(chain),
806 805 prevrev=prevrev,
807 806 deltatype=deltatype,
808 807 compsize=comp,
809 808 uncompsize=uncomp,
810 809 chainsize=chainsize,
811 810 chainratio=chainratio,
812 811 lindist=lineardist,
813 812 extradist=extradist,
814 813 extraratio=extraratio,
815 814 )
816 815 if withsparseread:
817 816 readsize = 0
818 817 largestblock = 0
819 818 srchunks = 0
820 819
821 820 for revschunk in deltautil.slicechunk(r, chain):
822 821 srchunks += 1
823 822 blkend = start(revschunk[-1]) + length(revschunk[-1])
824 823 blksize = blkend - start(revschunk[0])
825 824
826 825 readsize += blksize
827 826 if largestblock < blksize:
828 827 largestblock = blksize
829 828
830 829 if readsize:
831 830 readdensity = float(chainsize) / float(readsize)
832 831 else:
833 832 readdensity = 1
834 833
835 834 fm.write(
836 835 b'readsize largestblock readdensity srchunks',
837 836 b' %10d %10d %9.5f %8d',
838 837 readsize,
839 838 largestblock,
840 839 readdensity,
841 840 srchunks,
842 841 readsize=readsize,
843 842 largestblock=largestblock,
844 843 readdensity=readdensity,
845 844 srchunks=srchunks,
846 845 )
847 846
848 847 fm.plain(b'\n')
849 848
850 849 fm.end()
851 850
852 851
853 852 @command(
854 853 b'debugdirstate|debugstate',
855 854 [
856 855 (
857 856 b'',
858 857 b'nodates',
859 858 None,
860 859 _(b'do not display the saved mtime (DEPRECATED)'),
861 860 ),
862 861 (b'', b'dates', True, _(b'display the saved mtime')),
863 862 (b'', b'datesort', None, _(b'sort by saved mtime')),
864 863 ],
865 864 _(b'[OPTION]...'),
866 865 )
867 866 def debugstate(ui, repo, **opts):
868 867 """show the contents of the current dirstate"""
869 868
870 869 nodates = not opts['dates']
871 870 if opts.get('nodates') is not None:
872 871 nodates = True
873 872 datesort = opts.get('datesort')
874 873
875 874 if datesort:
876 875 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
877 876 else:
878 877 keyfunc = None # sort by filename
879 878 for file_, ent in sorted(pycompat.iteritems(repo.dirstate), key=keyfunc):
880 879 if ent[3] == -1:
881 880 timestr = b'unset '
882 881 elif nodates:
883 882 timestr = b'set '
884 883 else:
885 884 timestr = time.strftime(
886 885 "%Y-%m-%d %H:%M:%S ", time.localtime(ent[3])
887 886 )
888 887 timestr = encoding.strtolocal(timestr)
889 888 if ent[1] & 0o20000:
890 889 mode = b'lnk'
891 890 else:
892 891 mode = b'%3o' % (ent[1] & 0o777 & ~util.umask)
893 892 ui.write(b"%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
894 893 for f in repo.dirstate.copies():
895 894 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
896 895
897 896
898 897 @command(
899 898 b'debugdiscovery',
900 899 [
901 900 (b'', b'old', None, _(b'use old-style discovery')),
902 901 (
903 902 b'',
904 903 b'nonheads',
905 904 None,
906 905 _(b'use old-style discovery with non-heads included'),
907 906 ),
908 907 (b'', b'rev', [], b'restrict discovery to this set of revs'),
909 908 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
910 909 ]
911 910 + cmdutil.remoteopts,
912 911 _(b'[--rev REV] [OTHER]'),
913 912 )
914 913 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
915 914 """runs the changeset discovery protocol in isolation"""
916 915 opts = pycompat.byteskwargs(opts)
917 916 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
918 917 remote = hg.peer(repo, opts, remoteurl)
919 918 ui.status(_(b'comparing with %s\n') % util.hidepassword(remoteurl))
920 919
921 920 # make sure tests are repeatable
922 921 random.seed(int(opts[b'seed']))
923 922
924 923 if opts.get(b'old'):
925 924
926 925 def doit(pushedrevs, remoteheads, remote=remote):
927 926 if not util.safehasattr(remote, b'branches'):
928 927 # enable in-client legacy support
929 928 remote = localrepo.locallegacypeer(remote.local())
930 929 common, _in, hds = treediscovery.findcommonincoming(
931 930 repo, remote, force=True
932 931 )
933 932 common = set(common)
934 933 if not opts.get(b'nonheads'):
935 934 ui.writenoi18n(
936 935 b"unpruned common: %s\n"
937 936 % b" ".join(sorted(short(n) for n in common))
938 937 )
939 938
940 939 clnode = repo.changelog.node
941 940 common = repo.revs(b'heads(::%ln)', common)
942 941 common = {clnode(r) for r in common}
943 942 return common, hds
944 943
945 944 else:
946 945
947 946 def doit(pushedrevs, remoteheads, remote=remote):
948 947 nodes = None
949 948 if pushedrevs:
950 949 revs = scmutil.revrange(repo, pushedrevs)
951 950 nodes = [repo[r].node() for r in revs]
952 951 common, any, hds = setdiscovery.findcommonheads(
953 952 ui, repo, remote, ancestorsof=nodes
954 953 )
955 954 return common, hds
956 955
957 956 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
958 957 localrevs = opts[b'rev']
959 958 with util.timedcm('debug-discovery') as t:
960 959 common, hds = doit(localrevs, remoterevs)
961 960
962 961 # compute all statistics
963 962 common = set(common)
964 963 rheads = set(hds)
965 964 lheads = set(repo.heads())
966 965
967 966 data = {}
968 967 data[b'elapsed'] = t.elapsed
969 968 data[b'nb-common'] = len(common)
970 969 data[b'nb-common-local'] = len(common & lheads)
971 970 data[b'nb-common-remote'] = len(common & rheads)
972 971 data[b'nb-common-both'] = len(common & rheads & lheads)
973 972 data[b'nb-local'] = len(lheads)
974 973 data[b'nb-local-missing'] = data[b'nb-local'] - data[b'nb-common-local']
975 974 data[b'nb-remote'] = len(rheads)
976 975 data[b'nb-remote-unknown'] = data[b'nb-remote'] - data[b'nb-common-remote']
977 976 data[b'nb-revs'] = len(repo.revs(b'all()'))
978 977 data[b'nb-revs-common'] = len(repo.revs(b'::%ln', common))
979 978 data[b'nb-revs-missing'] = data[b'nb-revs'] - data[b'nb-revs-common']
980 979
981 980 # display discovery summary
982 981 ui.writenoi18n(b"elapsed time: %(elapsed)f seconds\n" % data)
983 982 ui.writenoi18n(b"heads summary:\n")
984 983 ui.writenoi18n(b" total common heads: %(nb-common)9d\n" % data)
985 984 ui.writenoi18n(b" also local heads: %(nb-common-local)9d\n" % data)
986 985 ui.writenoi18n(b" also remote heads: %(nb-common-remote)9d\n" % data)
987 986 ui.writenoi18n(b" both: %(nb-common-both)9d\n" % data)
988 987 ui.writenoi18n(b" local heads: %(nb-local)9d\n" % data)
989 988 ui.writenoi18n(b" common: %(nb-common-local)9d\n" % data)
990 989 ui.writenoi18n(b" missing: %(nb-local-missing)9d\n" % data)
991 990 ui.writenoi18n(b" remote heads: %(nb-remote)9d\n" % data)
992 991 ui.writenoi18n(b" common: %(nb-common-remote)9d\n" % data)
993 992 ui.writenoi18n(b" unknown: %(nb-remote-unknown)9d\n" % data)
994 993 ui.writenoi18n(b"local changesets: %(nb-revs)9d\n" % data)
995 994 ui.writenoi18n(b" common: %(nb-revs-common)9d\n" % data)
996 995 ui.writenoi18n(b" missing: %(nb-revs-missing)9d\n" % data)
997 996
998 997 if ui.verbose:
999 998 ui.writenoi18n(
1000 999 b"common heads: %s\n" % b" ".join(sorted(short(n) for n in common))
1001 1000 )
1002 1001
1003 1002
1004 1003 _chunksize = 4 << 10
1005 1004
1006 1005
1007 1006 @command(
1008 1007 b'debugdownload', [(b'o', b'output', b'', _(b'path')),], optionalrepo=True
1009 1008 )
1010 1009 def debugdownload(ui, repo, url, output=None, **opts):
1011 1010 """download a resource using Mercurial logic and config
1012 1011 """
1013 1012 fh = urlmod.open(ui, url, output)
1014 1013
1015 1014 dest = ui
1016 1015 if output:
1017 1016 dest = open(output, b"wb", _chunksize)
1018 1017 try:
1019 1018 data = fh.read(_chunksize)
1020 1019 while data:
1021 1020 dest.write(data)
1022 1021 data = fh.read(_chunksize)
1023 1022 finally:
1024 1023 if output:
1025 1024 dest.close()
1026 1025
1027 1026
1028 1027 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1029 1028 def debugextensions(ui, repo, **opts):
1030 1029 '''show information about active extensions'''
1031 1030 opts = pycompat.byteskwargs(opts)
1032 1031 exts = extensions.extensions(ui)
1033 1032 hgver = util.version()
1034 1033 fm = ui.formatter(b'debugextensions', opts)
1035 1034 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1036 1035 isinternal = extensions.ismoduleinternal(extmod)
1037 1036 extsource = None
1038 1037
1039 1038 if util.safehasattr(extmod, '__file__'):
1040 1039 extsource = pycompat.fsencode(extmod.__file__)
1041 1040 elif getattr(sys, 'oxidized', False):
1042 1041 extsource = pycompat.sysexecutable
1043 1042 if isinternal:
1044 1043 exttestedwith = [] # never expose magic string to users
1045 1044 else:
1046 1045 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1047 1046 extbuglink = getattr(extmod, 'buglink', None)
1048 1047
1049 1048 fm.startitem()
1050 1049
1051 1050 if ui.quiet or ui.verbose:
1052 1051 fm.write(b'name', b'%s\n', extname)
1053 1052 else:
1054 1053 fm.write(b'name', b'%s', extname)
1055 1054 if isinternal or hgver in exttestedwith:
1056 1055 fm.plain(b'\n')
1057 1056 elif not exttestedwith:
1058 1057 fm.plain(_(b' (untested!)\n'))
1059 1058 else:
1060 1059 lasttestedversion = exttestedwith[-1]
1061 1060 fm.plain(b' (%s!)\n' % lasttestedversion)
1062 1061
1063 1062 fm.condwrite(
1064 1063 ui.verbose and extsource,
1065 1064 b'source',
1066 1065 _(b' location: %s\n'),
1067 1066 extsource or b"",
1068 1067 )
1069 1068
1070 1069 if ui.verbose:
1071 1070 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1072 1071 fm.data(bundled=isinternal)
1073 1072
1074 1073 fm.condwrite(
1075 1074 ui.verbose and exttestedwith,
1076 1075 b'testedwith',
1077 1076 _(b' tested with: %s\n'),
1078 1077 fm.formatlist(exttestedwith, name=b'ver'),
1079 1078 )
1080 1079
1081 1080 fm.condwrite(
1082 1081 ui.verbose and extbuglink,
1083 1082 b'buglink',
1084 1083 _(b' bug reporting: %s\n'),
1085 1084 extbuglink or b"",
1086 1085 )
1087 1086
1088 1087 fm.end()
1089 1088
1090 1089
1091 1090 @command(
1092 1091 b'debugfileset',
1093 1092 [
1094 1093 (
1095 1094 b'r',
1096 1095 b'rev',
1097 1096 b'',
1098 1097 _(b'apply the filespec on this revision'),
1099 1098 _(b'REV'),
1100 1099 ),
1101 1100 (
1102 1101 b'',
1103 1102 b'all-files',
1104 1103 False,
1105 1104 _(b'test files from all revisions and working directory'),
1106 1105 ),
1107 1106 (
1108 1107 b's',
1109 1108 b'show-matcher',
1110 1109 None,
1111 1110 _(b'print internal representation of matcher'),
1112 1111 ),
1113 1112 (
1114 1113 b'p',
1115 1114 b'show-stage',
1116 1115 [],
1117 1116 _(b'print parsed tree at the given stage'),
1118 1117 _(b'NAME'),
1119 1118 ),
1120 1119 ],
1121 1120 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1122 1121 )
1123 1122 def debugfileset(ui, repo, expr, **opts):
1124 1123 '''parse and apply a fileset specification'''
1125 1124 from . import fileset
1126 1125
1127 1126 fileset.symbols # force import of fileset so we have predicates to optimize
1128 1127 opts = pycompat.byteskwargs(opts)
1129 1128 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
1130 1129
1131 1130 stages = [
1132 1131 (b'parsed', pycompat.identity),
1133 1132 (b'analyzed', filesetlang.analyze),
1134 1133 (b'optimized', filesetlang.optimize),
1135 1134 ]
1136 1135 stagenames = set(n for n, f in stages)
1137 1136
1138 1137 showalways = set()
1139 1138 if ui.verbose and not opts[b'show_stage']:
1140 1139 # show parsed tree by --verbose (deprecated)
1141 1140 showalways.add(b'parsed')
1142 1141 if opts[b'show_stage'] == [b'all']:
1143 1142 showalways.update(stagenames)
1144 1143 else:
1145 1144 for n in opts[b'show_stage']:
1146 1145 if n not in stagenames:
1147 1146 raise error.Abort(_(b'invalid stage name: %s') % n)
1148 1147 showalways.update(opts[b'show_stage'])
1149 1148
1150 1149 tree = filesetlang.parse(expr)
1151 1150 for n, f in stages:
1152 1151 tree = f(tree)
1153 1152 if n in showalways:
1154 1153 if opts[b'show_stage'] or n != b'parsed':
1155 1154 ui.write(b"* %s:\n" % n)
1156 1155 ui.write(filesetlang.prettyformat(tree), b"\n")
1157 1156
1158 1157 files = set()
1159 1158 if opts[b'all_files']:
1160 1159 for r in repo:
1161 1160 c = repo[r]
1162 1161 files.update(c.files())
1163 1162 files.update(c.substate)
1164 1163 if opts[b'all_files'] or ctx.rev() is None:
1165 1164 wctx = repo[None]
1166 1165 files.update(
1167 1166 repo.dirstate.walk(
1168 1167 scmutil.matchall(repo),
1169 1168 subrepos=list(wctx.substate),
1170 1169 unknown=True,
1171 1170 ignored=True,
1172 1171 )
1173 1172 )
1174 1173 files.update(wctx.substate)
1175 1174 else:
1176 1175 files.update(ctx.files())
1177 1176 files.update(ctx.substate)
1178 1177
1179 1178 m = ctx.matchfileset(repo.getcwd(), expr)
1180 1179 if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose):
1181 1180 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1182 1181 for f in sorted(files):
1183 1182 if not m(f):
1184 1183 continue
1185 1184 ui.write(b"%s\n" % f)
1186 1185
1187 1186
1188 1187 @command(b'debugformat', [] + cmdutil.formatteropts)
1189 1188 def debugformat(ui, repo, **opts):
1190 1189 """display format information about the current repository
1191 1190
1192 1191 Use --verbose to get extra information about current config value and
1193 1192 Mercurial default."""
1194 1193 opts = pycompat.byteskwargs(opts)
1195 1194 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1196 1195 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1197 1196
1198 1197 def makeformatname(name):
1199 1198 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1200 1199
1201 1200 fm = ui.formatter(b'debugformat', opts)
1202 1201 if fm.isplain():
1203 1202
1204 1203 def formatvalue(value):
1205 1204 if util.safehasattr(value, b'startswith'):
1206 1205 return value
1207 1206 if value:
1208 1207 return b'yes'
1209 1208 else:
1210 1209 return b'no'
1211 1210
1212 1211 else:
1213 1212 formatvalue = pycompat.identity
1214 1213
1215 1214 fm.plain(b'format-variant')
1216 1215 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1217 1216 fm.plain(b' repo')
1218 1217 if ui.verbose:
1219 1218 fm.plain(b' config default')
1220 1219 fm.plain(b'\n')
1221 1220 for fv in upgrade.allformatvariant:
1222 1221 fm.startitem()
1223 1222 repovalue = fv.fromrepo(repo)
1224 1223 configvalue = fv.fromconfig(repo)
1225 1224
1226 1225 if repovalue != configvalue:
1227 1226 namelabel = b'formatvariant.name.mismatchconfig'
1228 1227 repolabel = b'formatvariant.repo.mismatchconfig'
1229 1228 elif repovalue != fv.default:
1230 1229 namelabel = b'formatvariant.name.mismatchdefault'
1231 1230 repolabel = b'formatvariant.repo.mismatchdefault'
1232 1231 else:
1233 1232 namelabel = b'formatvariant.name.uptodate'
1234 1233 repolabel = b'formatvariant.repo.uptodate'
1235 1234
1236 1235 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1237 1236 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1238 1237 if fv.default != configvalue:
1239 1238 configlabel = b'formatvariant.config.special'
1240 1239 else:
1241 1240 configlabel = b'formatvariant.config.default'
1242 1241 fm.condwrite(
1243 1242 ui.verbose,
1244 1243 b'config',
1245 1244 b' %6s',
1246 1245 formatvalue(configvalue),
1247 1246 label=configlabel,
1248 1247 )
1249 1248 fm.condwrite(
1250 1249 ui.verbose,
1251 1250 b'default',
1252 1251 b' %7s',
1253 1252 formatvalue(fv.default),
1254 1253 label=b'formatvariant.default',
1255 1254 )
1256 1255 fm.plain(b'\n')
1257 1256 fm.end()
1258 1257
1259 1258
1260 1259 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1261 1260 def debugfsinfo(ui, path=b"."):
1262 1261 """show information detected about current filesystem"""
1263 1262 ui.writenoi18n(b'path: %s\n' % path)
1264 1263 ui.writenoi18n(
1265 1264 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1266 1265 )
1267 1266 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1268 1267 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1269 1268 ui.writenoi18n(
1270 1269 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1271 1270 )
1272 1271 ui.writenoi18n(
1273 1272 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1274 1273 )
1275 1274 casesensitive = b'(unknown)'
1276 1275 try:
1277 1276 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1278 1277 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1279 1278 except OSError:
1280 1279 pass
1281 1280 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1282 1281
1283 1282
1284 1283 @command(
1285 1284 b'debuggetbundle',
1286 1285 [
1287 1286 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1288 1287 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1289 1288 (
1290 1289 b't',
1291 1290 b'type',
1292 1291 b'bzip2',
1293 1292 _(b'bundle compression type to use'),
1294 1293 _(b'TYPE'),
1295 1294 ),
1296 1295 ],
1297 1296 _(b'REPO FILE [-H|-C ID]...'),
1298 1297 norepo=True,
1299 1298 )
1300 1299 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1301 1300 """retrieves a bundle from a repo
1302 1301
1303 1302 Every ID must be a full-length hex node id string. Saves the bundle to the
1304 1303 given file.
1305 1304 """
1306 1305 opts = pycompat.byteskwargs(opts)
1307 1306 repo = hg.peer(ui, opts, repopath)
1308 1307 if not repo.capable(b'getbundle'):
1309 1308 raise error.Abort(b"getbundle() not supported by target repository")
1310 1309 args = {}
1311 1310 if common:
1312 1311 args['common'] = [bin(s) for s in common]
1313 1312 if head:
1314 1313 args['heads'] = [bin(s) for s in head]
1315 1314 # TODO: get desired bundlecaps from command line.
1316 1315 args['bundlecaps'] = None
1317 1316 bundle = repo.getbundle(b'debug', **args)
1318 1317
1319 1318 bundletype = opts.get(b'type', b'bzip2').lower()
1320 1319 btypes = {
1321 1320 b'none': b'HG10UN',
1322 1321 b'bzip2': b'HG10BZ',
1323 1322 b'gzip': b'HG10GZ',
1324 1323 b'bundle2': b'HG20',
1325 1324 }
1326 1325 bundletype = btypes.get(bundletype)
1327 1326 if bundletype not in bundle2.bundletypes:
1328 1327 raise error.Abort(_(b'unknown bundle type specified with --type'))
1329 1328 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1330 1329
1331 1330
1332 1331 @command(b'debugignore', [], b'[FILE]')
1333 1332 def debugignore(ui, repo, *files, **opts):
1334 1333 """display the combined ignore pattern and information about ignored files
1335 1334
1336 1335 With no argument display the combined ignore pattern.
1337 1336
1338 1337 Given space separated file names, shows if the given file is ignored and
1339 1338 if so, show the ignore rule (file and line number) that matched it.
1340 1339 """
1341 1340 ignore = repo.dirstate._ignore
1342 1341 if not files:
1343 1342 # Show all the patterns
1344 1343 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1345 1344 else:
1346 1345 m = scmutil.match(repo[None], pats=files)
1347 1346 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1348 1347 for f in m.files():
1349 1348 nf = util.normpath(f)
1350 1349 ignored = None
1351 1350 ignoredata = None
1352 1351 if nf != b'.':
1353 1352 if ignore(nf):
1354 1353 ignored = nf
1355 1354 ignoredata = repo.dirstate._ignorefileandline(nf)
1356 1355 else:
1357 1356 for p in pathutil.finddirs(nf):
1358 1357 if ignore(p):
1359 1358 ignored = p
1360 1359 ignoredata = repo.dirstate._ignorefileandline(p)
1361 1360 break
1362 1361 if ignored:
1363 1362 if ignored == nf:
1364 1363 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1365 1364 else:
1366 1365 ui.write(
1367 1366 _(
1368 1367 b"%s is ignored because of "
1369 1368 b"containing directory %s\n"
1370 1369 )
1371 1370 % (uipathfn(f), ignored)
1372 1371 )
1373 1372 ignorefile, lineno, line = ignoredata
1374 1373 ui.write(
1375 1374 _(b"(ignore rule in %s, line %d: '%s')\n")
1376 1375 % (ignorefile, lineno, line)
1377 1376 )
1378 1377 else:
1379 1378 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1380 1379
1381 1380
1382 1381 @command(
1383 1382 b'debugindex',
1384 1383 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1385 1384 _(b'-c|-m|FILE'),
1386 1385 )
1387 1386 def debugindex(ui, repo, file_=None, **opts):
1388 1387 """dump index data for a storage primitive"""
1389 1388 opts = pycompat.byteskwargs(opts)
1390 1389 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1391 1390
1392 1391 if ui.debugflag:
1393 1392 shortfn = hex
1394 1393 else:
1395 1394 shortfn = short
1396 1395
1397 1396 idlen = 12
1398 1397 for i in store:
1399 1398 idlen = len(shortfn(store.node(i)))
1400 1399 break
1401 1400
1402 1401 fm = ui.formatter(b'debugindex', opts)
1403 1402 fm.plain(
1404 1403 b' rev linkrev %s %s p2\n'
1405 1404 % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
1406 1405 )
1407 1406
1408 1407 for rev in store:
1409 1408 node = store.node(rev)
1410 1409 parents = store.parents(node)
1411 1410
1412 1411 fm.startitem()
1413 1412 fm.write(b'rev', b'%6d ', rev)
1414 1413 fm.write(b'linkrev', b'%7d ', store.linkrev(rev))
1415 1414 fm.write(b'node', b'%s ', shortfn(node))
1416 1415 fm.write(b'p1', b'%s ', shortfn(parents[0]))
1417 1416 fm.write(b'p2', b'%s', shortfn(parents[1]))
1418 1417 fm.plain(b'\n')
1419 1418
1420 1419 fm.end()
1421 1420
1422 1421
1423 1422 @command(
1424 1423 b'debugindexdot',
1425 1424 cmdutil.debugrevlogopts,
1426 1425 _(b'-c|-m|FILE'),
1427 1426 optionalrepo=True,
1428 1427 )
1429 1428 def debugindexdot(ui, repo, file_=None, **opts):
1430 1429 """dump an index DAG as a graphviz dot file"""
1431 1430 opts = pycompat.byteskwargs(opts)
1432 1431 r = cmdutil.openstorage(repo, b'debugindexdot', file_, opts)
1433 1432 ui.writenoi18n(b"digraph G {\n")
1434 1433 for i in r:
1435 1434 node = r.node(i)
1436 1435 pp = r.parents(node)
1437 1436 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1438 1437 if pp[1] != nullid:
1439 1438 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1440 1439 ui.write(b"}\n")
1441 1440
1442 1441
1443 1442 @command(b'debugindexstats', [])
1444 1443 def debugindexstats(ui, repo):
1445 1444 """show stats related to the changelog index"""
1446 1445 repo.changelog.shortest(nullid, 1)
1447 1446 index = repo.changelog.index
1448 1447 if not util.safehasattr(index, b'stats'):
1449 1448 raise error.Abort(_(b'debugindexstats only works with native code'))
1450 1449 for k, v in sorted(index.stats().items()):
1451 1450 ui.write(b'%s: %d\n' % (k, v))
1452 1451
1453 1452
1454 1453 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1455 1454 def debuginstall(ui, **opts):
1456 1455 '''test Mercurial installation
1457 1456
1458 1457 Returns 0 on success.
1459 1458 '''
1460 1459 opts = pycompat.byteskwargs(opts)
1461 1460
1462 1461 problems = 0
1463 1462
1464 1463 fm = ui.formatter(b'debuginstall', opts)
1465 1464 fm.startitem()
1466 1465
1467 1466 # encoding
1468 1467 fm.write(b'encoding', _(b"checking encoding (%s)...\n"), encoding.encoding)
1469 1468 err = None
1470 1469 try:
1471 1470 codecs.lookup(pycompat.sysstr(encoding.encoding))
1472 1471 except LookupError as inst:
1473 1472 err = stringutil.forcebytestr(inst)
1474 1473 problems += 1
1475 1474 fm.condwrite(
1476 1475 err,
1477 1476 b'encodingerror',
1478 1477 _(b" %s\n (check that your locale is properly set)\n"),
1479 1478 err,
1480 1479 )
1481 1480
1482 1481 # Python
1483 1482 pythonlib = None
1484 1483 if util.safehasattr(os, '__file__'):
1485 1484 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1486 1485 elif getattr(sys, 'oxidized', False):
1487 1486 pythonlib = pycompat.sysexecutable
1488 1487
1489 1488 fm.write(
1490 1489 b'pythonexe',
1491 1490 _(b"checking Python executable (%s)\n"),
1492 1491 pycompat.sysexecutable or _(b"unknown"),
1493 1492 )
1494 1493 fm.write(
1495 1494 b'pythonimplementation',
1496 1495 _(b"checking Python implementation (%s)\n"),
1497 1496 pycompat.sysbytes(platform.python_implementation()),
1498 1497 )
1499 1498 fm.write(
1500 1499 b'pythonver',
1501 1500 _(b"checking Python version (%s)\n"),
1502 1501 (b"%d.%d.%d" % sys.version_info[:3]),
1503 1502 )
1504 1503 fm.write(
1505 1504 b'pythonlib',
1506 1505 _(b"checking Python lib (%s)...\n"),
1507 1506 pythonlib or _(b"unknown"),
1508 1507 )
1509 1508
1510 1509 security = set(sslutil.supportedprotocols)
1511 1510 if sslutil.hassni:
1512 1511 security.add(b'sni')
1513 1512
1514 1513 fm.write(
1515 1514 b'pythonsecurity',
1516 1515 _(b"checking Python security support (%s)\n"),
1517 1516 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1518 1517 )
1519 1518
1520 1519 # These are warnings, not errors. So don't increment problem count. This
1521 1520 # may change in the future.
1522 1521 if b'tls1.2' not in security:
1523 1522 fm.plain(
1524 1523 _(
1525 1524 b' TLS 1.2 not supported by Python install; '
1526 1525 b'network connections lack modern security\n'
1527 1526 )
1528 1527 )
1529 1528 if b'sni' not in security:
1530 1529 fm.plain(
1531 1530 _(
1532 1531 b' SNI not supported by Python install; may have '
1533 1532 b'connectivity issues with some servers\n'
1534 1533 )
1535 1534 )
1536 1535
1537 1536 # TODO print CA cert info
1538 1537
1539 1538 # hg version
1540 1539 hgver = util.version()
1541 1540 fm.write(
1542 1541 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1543 1542 )
1544 1543 fm.write(
1545 1544 b'hgverextra',
1546 1545 _(b"checking Mercurial custom build (%s)\n"),
1547 1546 b'+'.join(hgver.split(b'+')[1:]),
1548 1547 )
1549 1548
1550 1549 # compiled modules
1551 1550 hgmodules = None
1552 1551 if util.safehasattr(sys.modules[__name__], '__file__'):
1553 1552 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1554 1553 elif getattr(sys, 'oxidized', False):
1555 1554 hgmodules = pycompat.sysexecutable
1556 1555
1557 1556 fm.write(
1558 1557 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1559 1558 )
1560 1559 fm.write(
1561 1560 b'hgmodules',
1562 1561 _(b"checking installed modules (%s)...\n"),
1563 1562 hgmodules or _(b"unknown"),
1564 1563 )
1565 1564
1566 1565 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1567 1566 rustext = rustandc # for now, that's the only case
1568 1567 cext = policy.policy in (b'c', b'allow') or rustandc
1569 1568 nopure = cext or rustext
1570 1569 if nopure:
1571 1570 err = None
1572 1571 try:
1573 1572 if cext:
1574 1573 from .cext import ( # pytype: disable=import-error
1575 1574 base85,
1576 1575 bdiff,
1577 1576 mpatch,
1578 1577 osutil,
1579 1578 )
1580 1579
1581 1580 # quiet pyflakes
1582 1581 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
1583 1582 if rustext:
1584 1583 from .rustext import ( # pytype: disable=import-error
1585 1584 ancestor,
1586 1585 dirstate,
1587 1586 )
1588 1587
1589 1588 dir(ancestor), dir(dirstate) # quiet pyflakes
1590 1589 except Exception as inst:
1591 1590 err = stringutil.forcebytestr(inst)
1592 1591 problems += 1
1593 1592 fm.condwrite(err, b'extensionserror', b" %s\n", err)
1594 1593
1595 1594 compengines = util.compengines._engines.values()
1596 1595 fm.write(
1597 1596 b'compengines',
1598 1597 _(b'checking registered compression engines (%s)\n'),
1599 1598 fm.formatlist(
1600 1599 sorted(e.name() for e in compengines),
1601 1600 name=b'compengine',
1602 1601 fmt=b'%s',
1603 1602 sep=b', ',
1604 1603 ),
1605 1604 )
1606 1605 fm.write(
1607 1606 b'compenginesavail',
1608 1607 _(b'checking available compression engines (%s)\n'),
1609 1608 fm.formatlist(
1610 1609 sorted(e.name() for e in compengines if e.available()),
1611 1610 name=b'compengine',
1612 1611 fmt=b'%s',
1613 1612 sep=b', ',
1614 1613 ),
1615 1614 )
1616 1615 wirecompengines = compression.compengines.supportedwireengines(
1617 1616 compression.SERVERROLE
1618 1617 )
1619 1618 fm.write(
1620 1619 b'compenginesserver',
1621 1620 _(
1622 1621 b'checking available compression engines '
1623 1622 b'for wire protocol (%s)\n'
1624 1623 ),
1625 1624 fm.formatlist(
1626 1625 [e.name() for e in wirecompengines if e.wireprotosupport()],
1627 1626 name=b'compengine',
1628 1627 fmt=b'%s',
1629 1628 sep=b', ',
1630 1629 ),
1631 1630 )
1632 1631 re2 = b'missing'
1633 1632 if util._re2:
1634 1633 re2 = b'available'
1635 1634 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
1636 1635 fm.data(re2=bool(util._re2))
1637 1636
1638 1637 # templates
1639 1638 p = templater.templatepaths()
1640 1639 fm.write(b'templatedirs', b'checking templates (%s)...\n', b' '.join(p))
1641 1640 fm.condwrite(not p, b'', _(b" no template directories found\n"))
1642 1641 if p:
1643 1642 m = templater.templatepath(b"map-cmdline.default")
1644 1643 if m:
1645 1644 # template found, check if it is working
1646 1645 err = None
1647 1646 try:
1648 1647 templater.templater.frommapfile(m)
1649 1648 except Exception as inst:
1650 1649 err = stringutil.forcebytestr(inst)
1651 1650 p = None
1652 1651 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
1653 1652 else:
1654 1653 p = None
1655 1654 fm.condwrite(
1656 1655 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
1657 1656 )
1658 1657 fm.condwrite(
1659 1658 not m,
1660 1659 b'defaulttemplatenotfound',
1661 1660 _(b" template '%s' not found\n"),
1662 1661 b"default",
1663 1662 )
1664 1663 if not p:
1665 1664 problems += 1
1666 1665 fm.condwrite(
1667 1666 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
1668 1667 )
1669 1668
1670 1669 # editor
1671 1670 editor = ui.geteditor()
1672 1671 editor = util.expandpath(editor)
1673 1672 editorbin = procutil.shellsplit(editor)[0]
1674 1673 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
1675 1674 cmdpath = procutil.findexe(editorbin)
1676 1675 fm.condwrite(
1677 1676 not cmdpath and editor == b'vi',
1678 1677 b'vinotfound',
1679 1678 _(
1680 1679 b" No commit editor set and can't find %s in PATH\n"
1681 1680 b" (specify a commit editor in your configuration"
1682 1681 b" file)\n"
1683 1682 ),
1684 1683 not cmdpath and editor == b'vi' and editorbin,
1685 1684 )
1686 1685 fm.condwrite(
1687 1686 not cmdpath and editor != b'vi',
1688 1687 b'editornotfound',
1689 1688 _(
1690 1689 b" Can't find editor '%s' in PATH\n"
1691 1690 b" (specify a commit editor in your configuration"
1692 1691 b" file)\n"
1693 1692 ),
1694 1693 not cmdpath and editorbin,
1695 1694 )
1696 1695 if not cmdpath and editor != b'vi':
1697 1696 problems += 1
1698 1697
1699 1698 # check username
1700 1699 username = None
1701 1700 err = None
1702 1701 try:
1703 1702 username = ui.username()
1704 1703 except error.Abort as e:
1705 1704 err = stringutil.forcebytestr(e)
1706 1705 problems += 1
1707 1706
1708 1707 fm.condwrite(
1709 1708 username, b'username', _(b"checking username (%s)\n"), username
1710 1709 )
1711 1710 fm.condwrite(
1712 1711 err,
1713 1712 b'usernameerror',
1714 1713 _(
1715 1714 b"checking username...\n %s\n"
1716 1715 b" (specify a username in your configuration file)\n"
1717 1716 ),
1718 1717 err,
1719 1718 )
1720 1719
1721 1720 for name, mod in extensions.extensions():
1722 1721 handler = getattr(mod, 'debuginstall', None)
1723 1722 if handler is not None:
1724 1723 problems += handler(ui, fm)
1725 1724
1726 1725 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
1727 1726 if not problems:
1728 1727 fm.data(problems=problems)
1729 1728 fm.condwrite(
1730 1729 problems,
1731 1730 b'problems',
1732 1731 _(b"%d problems detected, please check your install!\n"),
1733 1732 problems,
1734 1733 )
1735 1734 fm.end()
1736 1735
1737 1736 return problems
1738 1737
1739 1738
1740 1739 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
1741 1740 def debugknown(ui, repopath, *ids, **opts):
1742 1741 """test whether node ids are known to a repo
1743 1742
1744 1743 Every ID must be a full-length hex node id string. Returns a list of 0s
1745 1744 and 1s indicating unknown/known.
1746 1745 """
1747 1746 opts = pycompat.byteskwargs(opts)
1748 1747 repo = hg.peer(ui, opts, repopath)
1749 1748 if not repo.capable(b'known'):
1750 1749 raise error.Abort(b"known() not supported by target repository")
1751 1750 flags = repo.known([bin(s) for s in ids])
1752 1751 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
1753 1752
1754 1753
1755 1754 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
1756 1755 def debuglabelcomplete(ui, repo, *args):
1757 1756 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1758 1757 debugnamecomplete(ui, repo, *args)
1759 1758
1760 1759
1761 1760 @command(
1762 1761 b'debuglocks',
1763 1762 [
1764 1763 (b'L', b'force-lock', None, _(b'free the store lock (DANGEROUS)')),
1765 1764 (
1766 1765 b'W',
1767 1766 b'force-wlock',
1768 1767 None,
1769 1768 _(b'free the working state lock (DANGEROUS)'),
1770 1769 ),
1771 1770 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
1772 1771 (
1773 1772 b'S',
1774 1773 b'set-wlock',
1775 1774 None,
1776 1775 _(b'set the working state lock until stopped'),
1777 1776 ),
1778 1777 ],
1779 1778 _(b'[OPTION]...'),
1780 1779 )
1781 1780 def debuglocks(ui, repo, **opts):
1782 1781 """show or modify state of locks
1783 1782
1784 1783 By default, this command will show which locks are held. This
1785 1784 includes the user and process holding the lock, the amount of time
1786 1785 the lock has been held, and the machine name where the process is
1787 1786 running if it's not local.
1788 1787
1789 1788 Locks protect the integrity of Mercurial's data, so should be
1790 1789 treated with care. System crashes or other interruptions may cause
1791 1790 locks to not be properly released, though Mercurial will usually
1792 1791 detect and remove such stale locks automatically.
1793 1792
1794 1793 However, detecting stale locks may not always be possible (for
1795 1794 instance, on a shared filesystem). Removing locks may also be
1796 1795 blocked by filesystem permissions.
1797 1796
1798 1797 Setting a lock will prevent other commands from changing the data.
1799 1798 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1800 1799 The set locks are removed when the command exits.
1801 1800
1802 1801 Returns 0 if no locks are held.
1803 1802
1804 1803 """
1805 1804
1806 1805 if opts.get('force_lock'):
1807 1806 repo.svfs.unlink(b'lock')
1808 1807 if opts.get('force_wlock'):
1809 1808 repo.vfs.unlink(b'wlock')
1810 1809 if opts.get('force_lock') or opts.get('force_wlock'):
1811 1810 return 0
1812 1811
1813 1812 locks = []
1814 1813 try:
1815 1814 if opts.get('set_wlock'):
1816 1815 try:
1817 1816 locks.append(repo.wlock(False))
1818 1817 except error.LockHeld:
1819 1818 raise error.Abort(_(b'wlock is already held'))
1820 1819 if opts.get('set_lock'):
1821 1820 try:
1822 1821 locks.append(repo.lock(False))
1823 1822 except error.LockHeld:
1824 1823 raise error.Abort(_(b'lock is already held'))
1825 1824 if len(locks):
1826 1825 ui.promptchoice(_(b"ready to release the lock (y)? $$ &Yes"))
1827 1826 return 0
1828 1827 finally:
1829 1828 release(*locks)
1830 1829
1831 1830 now = time.time()
1832 1831 held = 0
1833 1832
1834 1833 def report(vfs, name, method):
1835 1834 # this causes stale locks to get reaped for more accurate reporting
1836 1835 try:
1837 1836 l = method(False)
1838 1837 except error.LockHeld:
1839 1838 l = None
1840 1839
1841 1840 if l:
1842 1841 l.release()
1843 1842 else:
1844 1843 try:
1845 1844 st = vfs.lstat(name)
1846 1845 age = now - st[stat.ST_MTIME]
1847 1846 user = util.username(st.st_uid)
1848 1847 locker = vfs.readlock(name)
1849 1848 if b":" in locker:
1850 1849 host, pid = locker.split(b':')
1851 1850 if host == socket.gethostname():
1852 1851 locker = b'user %s, process %s' % (user or b'None', pid)
1853 1852 else:
1854 1853 locker = b'user %s, process %s, host %s' % (
1855 1854 user or b'None',
1856 1855 pid,
1857 1856 host,
1858 1857 )
1859 1858 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
1860 1859 return 1
1861 1860 except OSError as e:
1862 1861 if e.errno != errno.ENOENT:
1863 1862 raise
1864 1863
1865 1864 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
1866 1865 return 0
1867 1866
1868 1867 held += report(repo.svfs, b"lock", repo.lock)
1869 1868 held += report(repo.vfs, b"wlock", repo.wlock)
1870 1869
1871 1870 return held
1872 1871
1873 1872
1874 1873 @command(
1875 1874 b'debugmanifestfulltextcache',
1876 1875 [
1877 1876 (b'', b'clear', False, _(b'clear the cache')),
1878 1877 (
1879 1878 b'a',
1880 1879 b'add',
1881 1880 [],
1882 1881 _(b'add the given manifest nodes to the cache'),
1883 1882 _(b'NODE'),
1884 1883 ),
1885 1884 ],
1886 1885 b'',
1887 1886 )
1888 1887 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
1889 1888 """show, clear or amend the contents of the manifest fulltext cache"""
1890 1889
1891 1890 def getcache():
1892 1891 r = repo.manifestlog.getstorage(b'')
1893 1892 try:
1894 1893 return r._fulltextcache
1895 1894 except AttributeError:
1896 1895 msg = _(
1897 1896 b"Current revlog implementation doesn't appear to have a "
1898 1897 b"manifest fulltext cache\n"
1899 1898 )
1900 1899 raise error.Abort(msg)
1901 1900
1902 1901 if opts.get('clear'):
1903 1902 with repo.wlock():
1904 1903 cache = getcache()
1905 1904 cache.clear(clear_persisted_data=True)
1906 1905 return
1907 1906
1908 1907 if add:
1909 1908 with repo.wlock():
1910 1909 m = repo.manifestlog
1911 1910 store = m.getstorage(b'')
1912 1911 for n in add:
1913 1912 try:
1914 1913 manifest = m[store.lookup(n)]
1915 1914 except error.LookupError as e:
1916 1915 raise error.Abort(e, hint=b"Check your manifest node id")
1917 1916 manifest.read() # stores revisision in cache too
1918 1917 return
1919 1918
1920 1919 cache = getcache()
1921 1920 if not len(cache):
1922 1921 ui.write(_(b'cache empty\n'))
1923 1922 else:
1924 1923 ui.write(
1925 1924 _(
1926 1925 b'cache contains %d manifest entries, in order of most to '
1927 1926 b'least recent:\n'
1928 1927 )
1929 1928 % (len(cache),)
1930 1929 )
1931 1930 totalsize = 0
1932 1931 for nodeid in cache:
1933 1932 # Use cache.get to not update the LRU order
1934 1933 data = cache.peek(nodeid)
1935 1934 size = len(data)
1936 1935 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
1937 1936 ui.write(
1938 1937 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
1939 1938 )
1940 1939 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
1941 1940 ui.write(
1942 1941 _(b'total cache data size %s, on-disk %s\n')
1943 1942 % (util.bytecount(totalsize), util.bytecount(ondisk))
1944 1943 )
1945 1944
1946 1945
1947 @command(b'debugmergestate', [], b'')
1948 def debugmergestate(ui, repo, *args):
1946 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
1947 def debugmergestate(ui, repo, *args, **opts):
1949 1948 """print merge state
1950 1949
1951 1950 Use --verbose to print out information about whether v1 or v2 merge state
1952 1951 was chosen."""
1953 1952
1954 def _hashornull(h):
1955 if h == nullhex:
1956 return b'null'
1957 else:
1958 return h
1959
1960 def printrecords(version):
1961 ui.writenoi18n(b'* version %d records\n' % version)
1962 if version == 1:
1963 records = v1records
1964 else:
1965 records = v2records
1966
1967 for rtype, record in records:
1968 # pretty print some record types
1969 if rtype == b'L':
1970 ui.writenoi18n(b'local: %s\n' % record)
1971 elif rtype == b'O':
1972 ui.writenoi18n(b'other: %s\n' % record)
1973 elif rtype == b'm':
1974 driver, mdstate = record.split(b'\0', 1)
1975 ui.writenoi18n(
1976 b'merge driver: %s (state "%s")\n' % (driver, mdstate)
1977 )
1978 elif rtype in b'FDC':
1979 r = record.split(b'\0')
1980 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1981 if version == 1:
1982 onode = b'not stored in v1 format'
1983 flags = r[7]
1984 else:
1985 onode, flags = r[7:9]
1986 ui.writenoi18n(
1987 b'file: %s (record type "%s", state "%s", hash %s)\n'
1988 % (f, rtype, state, _hashornull(hash))
1989 )
1990 ui.writenoi18n(
1991 b' local path: %s (flags "%s")\n' % (lfile, flags)
1992 )
1993 ui.writenoi18n(
1994 b' ancestor path: %s (node %s)\n'
1995 % (afile, _hashornull(anode))
1996 )
1997 ui.writenoi18n(
1998 b' other path: %s (node %s)\n'
1999 % (ofile, _hashornull(onode))
2000 )
2001 elif rtype == b'f':
2002 filename, rawextras = record.split(b'\0', 1)
2003 extras = rawextras.split(b'\0')
2004 i = 0
2005 extrastrings = []
2006 while i < len(extras):
2007 extrastrings.append(b'%s = %s' % (extras[i], extras[i + 1]))
2008 i += 2
2009
2010 ui.writenoi18n(
2011 b'file extras: %s (%s)\n'
2012 % (filename, b', '.join(extrastrings))
2013 )
2014 elif rtype == b'l':
2015 labels = record.split(b'\0', 2)
2016 labels = [l for l in labels if len(l) > 0]
2017 ui.writenoi18n(b'labels:\n')
2018 ui.write((b' local: %s\n' % labels[0]))
2019 ui.write((b' other: %s\n' % labels[1]))
2020 if len(labels) > 2:
2021 ui.write((b' base: %s\n' % labels[2]))
2022 else:
2023 ui.writenoi18n(
2024 b'unrecognized entry: %s\t%s\n'
2025 % (rtype, record.replace(b'\0', b'\t'))
2026 )
2027
2028 # Avoid mergestate.read() since it may raise an exception for unsupported
2029 # merge state records. We shouldn't be doing this, but this is OK since this
2030 # command is pretty low-level.
1953 if ui.verbose:
2031 1954 ms = mergemod.mergestate(repo)
2032 1955
2033 1956 # sort so that reasonable information is on top
2034 1957 v1records = ms._readrecordsv1()
2035 1958 v2records = ms._readrecordsv2()
2036 order = b'LOml'
2037
2038 def key(r):
2039 idx = order.find(r[0])
2040 if idx == -1:
2041 return (1, r[1])
2042 else:
2043 return (0, idx)
2044
2045 v1records.sort(key=key)
2046 v2records.sort(key=key)
2047 1959
2048 1960 if not v1records and not v2records:
2049 ui.writenoi18n(b'no merge state found\n')
1961 pass
2050 1962 elif not v2records:
2051 ui.notenoi18n(b'no version 2 merge state\n')
2052 printrecords(1)
1963 ui.writenoi18n(b'no version 2 merge state\n')
2053 1964 elif ms._v1v2match(v1records, v2records):
2054 ui.notenoi18n(b'v1 and v2 states match: using v2\n')
2055 printrecords(2)
1965 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2056 1966 else:
2057 ui.notenoi18n(b'v1 and v2 states mismatch: using v1\n')
2058 printrecords(1)
2059 if ui.verbose:
2060 printrecords(2)
1967 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
1968
1969 opts = pycompat.byteskwargs(opts)
1970 if not opts[b'template']:
1971 opts[b'template'] = (
1972 b'{if(commits, "", "no merge state found\n")}'
1973 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
1974 b'{files % "file: {path} (state \\"{state}\\")\n'
1975 b' local path: {local_path} (flags \\"{local_flags}\\")\n'
1976 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
1977 b' other path: {other_path} (node {other_node})\n'
1978 b'{extras % " extra: {key} = {value}\n"}'
1979 b'"}'
1980 )
1981
1982 ms = mergemod.mergestate.read(repo)
1983
1984 fm = ui.formatter(b'debugmergestate', opts)
1985 fm.startitem()
1986
1987 fm_commits = fm.nested(b'commits')
1988 if ms.active():
1989 for name, node, label_index in (
1990 (b'local', ms.local, 0),
1991 (b'other', ms.other, 1),
1992 ):
1993 fm_commits.startitem()
1994 fm_commits.data(name=name)
1995 fm_commits.data(node=hex(node))
1996 if ms._labels and len(ms._labels) > label_index:
1997 fm_commits.data(label=ms._labels[label_index])
1998 fm_commits.end()
1999
2000 fm_files = fm.nested(b'files')
2001 if ms.active():
2002 for f in ms:
2003 fm_files.startitem()
2004 fm_files.data(path=f)
2005 state = ms._state[f]
2006 fm_files.data(state=state[0])
2007 fm_files.data(local_key=state[1])
2008 fm_files.data(local_path=state[2])
2009 fm_files.data(ancestor_path=state[3])
2010 fm_files.data(ancestor_node=state[4])
2011 fm_files.data(other_path=state[5])
2012 fm_files.data(other_node=state[6])
2013 fm_files.data(local_flags=state[7])
2014 fm_extras = fm_files.nested(b'extras')
2015 for k, v in ms.extras(f).items():
2016 fm_extras.startitem()
2017 fm_extras.data(key=k)
2018 fm_extras.data(value=v)
2019 fm_extras.end()
2020
2021 fm_files.end()
2022
2023 fm.end()
2061 2024
2062 2025
2063 2026 @command(b'debugnamecomplete', [], _(b'NAME...'))
2064 2027 def debugnamecomplete(ui, repo, *args):
2065 2028 '''complete "names" - tags, open branch names, bookmark names'''
2066 2029
2067 2030 names = set()
2068 2031 # since we previously only listed open branches, we will handle that
2069 2032 # specially (after this for loop)
2070 2033 for name, ns in pycompat.iteritems(repo.names):
2071 2034 if name != b'branches':
2072 2035 names.update(ns.listnames(repo))
2073 2036 names.update(
2074 2037 tag
2075 2038 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2076 2039 if not closed
2077 2040 )
2078 2041 completions = set()
2079 2042 if not args:
2080 2043 args = [b'']
2081 2044 for a in args:
2082 2045 completions.update(n for n in names if n.startswith(a))
2083 2046 ui.write(b'\n'.join(sorted(completions)))
2084 2047 ui.write(b'\n')
2085 2048
2086 2049
2087 2050 @command(
2088 2051 b'debugnodemap',
2089 2052 [
2090 2053 (
2091 2054 b'',
2092 2055 b'dump-new',
2093 2056 False,
2094 2057 _(b'write a (new) persistent binary nodemap on stdin'),
2095 2058 ),
2096 2059 (b'', b'dump-disk', False, _(b'dump on-disk data on stdin')),
2097 2060 (
2098 2061 b'',
2099 2062 b'check',
2100 2063 False,
2101 2064 _(b'check that the data on disk data are correct.'),
2102 2065 ),
2103 2066 (
2104 2067 b'',
2105 2068 b'metadata',
2106 2069 False,
2107 2070 _(b'display the on disk meta data for the nodemap'),
2108 2071 ),
2109 2072 ],
2110 2073 )
2111 2074 def debugnodemap(ui, repo, **opts):
2112 2075 """write and inspect on disk nodemap
2113 2076 """
2114 2077 if opts['dump_new']:
2115 2078 unfi = repo.unfiltered()
2116 2079 cl = unfi.changelog
2117 2080 data = nodemap.persistent_data(cl.index)
2118 2081 ui.write(data)
2119 2082 elif opts['dump_disk']:
2120 2083 unfi = repo.unfiltered()
2121 2084 cl = unfi.changelog
2122 2085 nm_data = nodemap.persisted_data(cl)
2123 2086 if nm_data is not None:
2124 2087 docket, data = nm_data
2125 2088 ui.write(data)
2126 2089 elif opts['check']:
2127 2090 unfi = repo.unfiltered()
2128 2091 cl = unfi.changelog
2129 2092 nm_data = nodemap.persisted_data(cl)
2130 2093 if nm_data is not None:
2131 2094 docket, data = nm_data
2132 2095 return nodemap.check_data(ui, cl.index, data)
2133 2096 elif opts['metadata']:
2134 2097 unfi = repo.unfiltered()
2135 2098 cl = unfi.changelog
2136 2099 nm_data = nodemap.persisted_data(cl)
2137 2100 if nm_data is not None:
2138 2101 docket, data = nm_data
2139 2102 ui.write((b"uid: %s\n") % docket.uid)
2140 2103 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2141 2104 ui.write((b"data-length: %d\n") % docket.data_length)
2142 2105 ui.write((b"data-unused: %d\n") % docket.data_unused)
2143 2106
2144 2107
2145 2108 @command(
2146 2109 b'debugobsolete',
2147 2110 [
2148 2111 (b'', b'flags', 0, _(b'markers flag')),
2149 2112 (
2150 2113 b'',
2151 2114 b'record-parents',
2152 2115 False,
2153 2116 _(b'record parent information for the precursor'),
2154 2117 ),
2155 2118 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2156 2119 (
2157 2120 b'',
2158 2121 b'exclusive',
2159 2122 False,
2160 2123 _(b'restrict display to markers only relevant to REV'),
2161 2124 ),
2162 2125 (b'', b'index', False, _(b'display index of the marker')),
2163 2126 (b'', b'delete', [], _(b'delete markers specified by indices')),
2164 2127 ]
2165 2128 + cmdutil.commitopts2
2166 2129 + cmdutil.formatteropts,
2167 2130 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2168 2131 )
2169 2132 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2170 2133 """create arbitrary obsolete marker
2171 2134
2172 2135 With no arguments, displays the list of obsolescence markers."""
2173 2136
2174 2137 opts = pycompat.byteskwargs(opts)
2175 2138
2176 2139 def parsenodeid(s):
2177 2140 try:
2178 2141 # We do not use revsingle/revrange functions here to accept
2179 2142 # arbitrary node identifiers, possibly not present in the
2180 2143 # local repository.
2181 2144 n = bin(s)
2182 2145 if len(n) != len(nullid):
2183 2146 raise TypeError()
2184 2147 return n
2185 2148 except TypeError:
2186 2149 raise error.Abort(
2187 2150 b'changeset references must be full hexadecimal '
2188 2151 b'node identifiers'
2189 2152 )
2190 2153
2191 2154 if opts.get(b'delete'):
2192 2155 indices = []
2193 2156 for v in opts.get(b'delete'):
2194 2157 try:
2195 2158 indices.append(int(v))
2196 2159 except ValueError:
2197 2160 raise error.Abort(
2198 2161 _(b'invalid index value: %r') % v,
2199 2162 hint=_(b'use integers for indices'),
2200 2163 )
2201 2164
2202 2165 if repo.currenttransaction():
2203 2166 raise error.Abort(
2204 2167 _(b'cannot delete obsmarkers in the middle of transaction.')
2205 2168 )
2206 2169
2207 2170 with repo.lock():
2208 2171 n = repair.deleteobsmarkers(repo.obsstore, indices)
2209 2172 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2210 2173
2211 2174 return
2212 2175
2213 2176 if precursor is not None:
2214 2177 if opts[b'rev']:
2215 2178 raise error.Abort(b'cannot select revision when creating marker')
2216 2179 metadata = {}
2217 2180 metadata[b'user'] = encoding.fromlocal(opts[b'user'] or ui.username())
2218 2181 succs = tuple(parsenodeid(succ) for succ in successors)
2219 2182 l = repo.lock()
2220 2183 try:
2221 2184 tr = repo.transaction(b'debugobsolete')
2222 2185 try:
2223 2186 date = opts.get(b'date')
2224 2187 if date:
2225 2188 date = dateutil.parsedate(date)
2226 2189 else:
2227 2190 date = None
2228 2191 prec = parsenodeid(precursor)
2229 2192 parents = None
2230 2193 if opts[b'record_parents']:
2231 2194 if prec not in repo.unfiltered():
2232 2195 raise error.Abort(
2233 2196 b'cannot used --record-parents on '
2234 2197 b'unknown changesets'
2235 2198 )
2236 2199 parents = repo.unfiltered()[prec].parents()
2237 2200 parents = tuple(p.node() for p in parents)
2238 2201 repo.obsstore.create(
2239 2202 tr,
2240 2203 prec,
2241 2204 succs,
2242 2205 opts[b'flags'],
2243 2206 parents=parents,
2244 2207 date=date,
2245 2208 metadata=metadata,
2246 2209 ui=ui,
2247 2210 )
2248 2211 tr.close()
2249 2212 except ValueError as exc:
2250 2213 raise error.Abort(
2251 2214 _(b'bad obsmarker input: %s') % pycompat.bytestr(exc)
2252 2215 )
2253 2216 finally:
2254 2217 tr.release()
2255 2218 finally:
2256 2219 l.release()
2257 2220 else:
2258 2221 if opts[b'rev']:
2259 2222 revs = scmutil.revrange(repo, opts[b'rev'])
2260 2223 nodes = [repo[r].node() for r in revs]
2261 2224 markers = list(
2262 2225 obsutil.getmarkers(
2263 2226 repo, nodes=nodes, exclusive=opts[b'exclusive']
2264 2227 )
2265 2228 )
2266 2229 markers.sort(key=lambda x: x._data)
2267 2230 else:
2268 2231 markers = obsutil.getmarkers(repo)
2269 2232
2270 2233 markerstoiter = markers
2271 2234 isrelevant = lambda m: True
2272 2235 if opts.get(b'rev') and opts.get(b'index'):
2273 2236 markerstoiter = obsutil.getmarkers(repo)
2274 2237 markerset = set(markers)
2275 2238 isrelevant = lambda m: m in markerset
2276 2239
2277 2240 fm = ui.formatter(b'debugobsolete', opts)
2278 2241 for i, m in enumerate(markerstoiter):
2279 2242 if not isrelevant(m):
2280 2243 # marker can be irrelevant when we're iterating over a set
2281 2244 # of markers (markerstoiter) which is bigger than the set
2282 2245 # of markers we want to display (markers)
2283 2246 # this can happen if both --index and --rev options are
2284 2247 # provided and thus we need to iterate over all of the markers
2285 2248 # to get the correct indices, but only display the ones that
2286 2249 # are relevant to --rev value
2287 2250 continue
2288 2251 fm.startitem()
2289 2252 ind = i if opts.get(b'index') else None
2290 2253 cmdutil.showmarker(fm, m, index=ind)
2291 2254 fm.end()
2292 2255
2293 2256
2294 2257 @command(
2295 2258 b'debugp1copies',
2296 2259 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2297 2260 _(b'[-r REV]'),
2298 2261 )
2299 2262 def debugp1copies(ui, repo, **opts):
2300 2263 """dump copy information compared to p1"""
2301 2264
2302 2265 opts = pycompat.byteskwargs(opts)
2303 2266 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2304 2267 for dst, src in ctx.p1copies().items():
2305 2268 ui.write(b'%s -> %s\n' % (src, dst))
2306 2269
2307 2270
2308 2271 @command(
2309 2272 b'debugp2copies',
2310 2273 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2311 2274 _(b'[-r REV]'),
2312 2275 )
2313 2276 def debugp1copies(ui, repo, **opts):
2314 2277 """dump copy information compared to p2"""
2315 2278
2316 2279 opts = pycompat.byteskwargs(opts)
2317 2280 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2318 2281 for dst, src in ctx.p2copies().items():
2319 2282 ui.write(b'%s -> %s\n' % (src, dst))
2320 2283
2321 2284
2322 2285 @command(
2323 2286 b'debugpathcomplete',
2324 2287 [
2325 2288 (b'f', b'full', None, _(b'complete an entire path')),
2326 2289 (b'n', b'normal', None, _(b'show only normal files')),
2327 2290 (b'a', b'added', None, _(b'show only added files')),
2328 2291 (b'r', b'removed', None, _(b'show only removed files')),
2329 2292 ],
2330 2293 _(b'FILESPEC...'),
2331 2294 )
2332 2295 def debugpathcomplete(ui, repo, *specs, **opts):
2333 2296 '''complete part or all of a tracked path
2334 2297
2335 2298 This command supports shells that offer path name completion. It
2336 2299 currently completes only files already known to the dirstate.
2337 2300
2338 2301 Completion extends only to the next path segment unless
2339 2302 --full is specified, in which case entire paths are used.'''
2340 2303
2341 2304 def complete(path, acceptable):
2342 2305 dirstate = repo.dirstate
2343 2306 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2344 2307 rootdir = repo.root + pycompat.ossep
2345 2308 if spec != repo.root and not spec.startswith(rootdir):
2346 2309 return [], []
2347 2310 if os.path.isdir(spec):
2348 2311 spec += b'/'
2349 2312 spec = spec[len(rootdir) :]
2350 2313 fixpaths = pycompat.ossep != b'/'
2351 2314 if fixpaths:
2352 2315 spec = spec.replace(pycompat.ossep, b'/')
2353 2316 speclen = len(spec)
2354 2317 fullpaths = opts['full']
2355 2318 files, dirs = set(), set()
2356 2319 adddir, addfile = dirs.add, files.add
2357 2320 for f, st in pycompat.iteritems(dirstate):
2358 2321 if f.startswith(spec) and st[0] in acceptable:
2359 2322 if fixpaths:
2360 2323 f = f.replace(b'/', pycompat.ossep)
2361 2324 if fullpaths:
2362 2325 addfile(f)
2363 2326 continue
2364 2327 s = f.find(pycompat.ossep, speclen)
2365 2328 if s >= 0:
2366 2329 adddir(f[:s])
2367 2330 else:
2368 2331 addfile(f)
2369 2332 return files, dirs
2370 2333
2371 2334 acceptable = b''
2372 2335 if opts['normal']:
2373 2336 acceptable += b'nm'
2374 2337 if opts['added']:
2375 2338 acceptable += b'a'
2376 2339 if opts['removed']:
2377 2340 acceptable += b'r'
2378 2341 cwd = repo.getcwd()
2379 2342 if not specs:
2380 2343 specs = [b'.']
2381 2344
2382 2345 files, dirs = set(), set()
2383 2346 for spec in specs:
2384 2347 f, d = complete(spec, acceptable or b'nmar')
2385 2348 files.update(f)
2386 2349 dirs.update(d)
2387 2350 files.update(dirs)
2388 2351 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2389 2352 ui.write(b'\n')
2390 2353
2391 2354
2392 2355 @command(
2393 2356 b'debugpathcopies',
2394 2357 cmdutil.walkopts,
2395 2358 b'hg debugpathcopies REV1 REV2 [FILE]',
2396 2359 inferrepo=True,
2397 2360 )
2398 2361 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2399 2362 """show copies between two revisions"""
2400 2363 ctx1 = scmutil.revsingle(repo, rev1)
2401 2364 ctx2 = scmutil.revsingle(repo, rev2)
2402 2365 m = scmutil.match(ctx1, pats, opts)
2403 2366 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2404 2367 ui.write(b'%s -> %s\n' % (src, dst))
2405 2368
2406 2369
2407 2370 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2408 2371 def debugpeer(ui, path):
2409 2372 """establish a connection to a peer repository"""
2410 2373 # Always enable peer request logging. Requires --debug to display
2411 2374 # though.
2412 2375 overrides = {
2413 2376 (b'devel', b'debug.peer-request'): True,
2414 2377 }
2415 2378
2416 2379 with ui.configoverride(overrides):
2417 2380 peer = hg.peer(ui, {}, path)
2418 2381
2419 2382 local = peer.local() is not None
2420 2383 canpush = peer.canpush()
2421 2384
2422 2385 ui.write(_(b'url: %s\n') % peer.url())
2423 2386 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2424 2387 ui.write(_(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no')))
2425 2388
2426 2389
2427 2390 @command(
2428 2391 b'debugpickmergetool',
2429 2392 [
2430 2393 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2431 2394 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2432 2395 ]
2433 2396 + cmdutil.walkopts
2434 2397 + cmdutil.mergetoolopts,
2435 2398 _(b'[PATTERN]...'),
2436 2399 inferrepo=True,
2437 2400 )
2438 2401 def debugpickmergetool(ui, repo, *pats, **opts):
2439 2402 """examine which merge tool is chosen for specified file
2440 2403
2441 2404 As described in :hg:`help merge-tools`, Mercurial examines
2442 2405 configurations below in this order to decide which merge tool is
2443 2406 chosen for specified file.
2444 2407
2445 2408 1. ``--tool`` option
2446 2409 2. ``HGMERGE`` environment variable
2447 2410 3. configurations in ``merge-patterns`` section
2448 2411 4. configuration of ``ui.merge``
2449 2412 5. configurations in ``merge-tools`` section
2450 2413 6. ``hgmerge`` tool (for historical reason only)
2451 2414 7. default tool for fallback (``:merge`` or ``:prompt``)
2452 2415
2453 2416 This command writes out examination result in the style below::
2454 2417
2455 2418 FILE = MERGETOOL
2456 2419
2457 2420 By default, all files known in the first parent context of the
2458 2421 working directory are examined. Use file patterns and/or -I/-X
2459 2422 options to limit target files. -r/--rev is also useful to examine
2460 2423 files in another context without actual updating to it.
2461 2424
2462 2425 With --debug, this command shows warning messages while matching
2463 2426 against ``merge-patterns`` and so on, too. It is recommended to
2464 2427 use this option with explicit file patterns and/or -I/-X options,
2465 2428 because this option increases amount of output per file according
2466 2429 to configurations in hgrc.
2467 2430
2468 2431 With -v/--verbose, this command shows configurations below at
2469 2432 first (only if specified).
2470 2433
2471 2434 - ``--tool`` option
2472 2435 - ``HGMERGE`` environment variable
2473 2436 - configuration of ``ui.merge``
2474 2437
2475 2438 If merge tool is chosen before matching against
2476 2439 ``merge-patterns``, this command can't show any helpful
2477 2440 information, even with --debug. In such case, information above is
2478 2441 useful to know why a merge tool is chosen.
2479 2442 """
2480 2443 opts = pycompat.byteskwargs(opts)
2481 2444 overrides = {}
2482 2445 if opts[b'tool']:
2483 2446 overrides[(b'ui', b'forcemerge')] = opts[b'tool']
2484 2447 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts[b'tool'])))
2485 2448
2486 2449 with ui.configoverride(overrides, b'debugmergepatterns'):
2487 2450 hgmerge = encoding.environ.get(b"HGMERGE")
2488 2451 if hgmerge is not None:
2489 2452 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2490 2453 uimerge = ui.config(b"ui", b"merge")
2491 2454 if uimerge:
2492 2455 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2493 2456
2494 2457 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2495 2458 m = scmutil.match(ctx, pats, opts)
2496 2459 changedelete = opts[b'changedelete']
2497 2460 for path in ctx.walk(m):
2498 2461 fctx = ctx[path]
2499 2462 try:
2500 2463 if not ui.debugflag:
2501 2464 ui.pushbuffer(error=True)
2502 2465 tool, toolpath = filemerge._picktool(
2503 2466 repo,
2504 2467 ui,
2505 2468 path,
2506 2469 fctx.isbinary(),
2507 2470 b'l' in fctx.flags(),
2508 2471 changedelete,
2509 2472 )
2510 2473 finally:
2511 2474 if not ui.debugflag:
2512 2475 ui.popbuffer()
2513 2476 ui.write(b'%s = %s\n' % (path, tool))
2514 2477
2515 2478
2516 2479 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2517 2480 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2518 2481 '''access the pushkey key/value protocol
2519 2482
2520 2483 With two args, list the keys in the given namespace.
2521 2484
2522 2485 With five args, set a key to new if it currently is set to old.
2523 2486 Reports success or failure.
2524 2487 '''
2525 2488
2526 2489 target = hg.peer(ui, {}, repopath)
2527 2490 if keyinfo:
2528 2491 key, old, new = keyinfo
2529 2492 with target.commandexecutor() as e:
2530 2493 r = e.callcommand(
2531 2494 b'pushkey',
2532 2495 {
2533 2496 b'namespace': namespace,
2534 2497 b'key': key,
2535 2498 b'old': old,
2536 2499 b'new': new,
2537 2500 },
2538 2501 ).result()
2539 2502
2540 2503 ui.status(pycompat.bytestr(r) + b'\n')
2541 2504 return not r
2542 2505 else:
2543 2506 for k, v in sorted(pycompat.iteritems(target.listkeys(namespace))):
2544 2507 ui.write(
2545 2508 b"%s\t%s\n" % (stringutil.escapestr(k), stringutil.escapestr(v))
2546 2509 )
2547 2510
2548 2511
2549 2512 @command(b'debugpvec', [], _(b'A B'))
2550 2513 def debugpvec(ui, repo, a, b=None):
2551 2514 ca = scmutil.revsingle(repo, a)
2552 2515 cb = scmutil.revsingle(repo, b)
2553 2516 pa = pvec.ctxpvec(ca)
2554 2517 pb = pvec.ctxpvec(cb)
2555 2518 if pa == pb:
2556 2519 rel = b"="
2557 2520 elif pa > pb:
2558 2521 rel = b">"
2559 2522 elif pa < pb:
2560 2523 rel = b"<"
2561 2524 elif pa | pb:
2562 2525 rel = b"|"
2563 2526 ui.write(_(b"a: %s\n") % pa)
2564 2527 ui.write(_(b"b: %s\n") % pb)
2565 2528 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2566 2529 ui.write(
2567 2530 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
2568 2531 % (
2569 2532 abs(pa._depth - pb._depth),
2570 2533 pvec._hamming(pa._vec, pb._vec),
2571 2534 pa.distance(pb),
2572 2535 rel,
2573 2536 )
2574 2537 )
2575 2538
2576 2539
2577 2540 @command(
2578 2541 b'debugrebuilddirstate|debugrebuildstate',
2579 2542 [
2580 2543 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
2581 2544 (
2582 2545 b'',
2583 2546 b'minimal',
2584 2547 None,
2585 2548 _(
2586 2549 b'only rebuild files that are inconsistent with '
2587 2550 b'the working copy parent'
2588 2551 ),
2589 2552 ),
2590 2553 ],
2591 2554 _(b'[-r REV]'),
2592 2555 )
2593 2556 def debugrebuilddirstate(ui, repo, rev, **opts):
2594 2557 """rebuild the dirstate as it would look like for the given revision
2595 2558
2596 2559 If no revision is specified the first current parent will be used.
2597 2560
2598 2561 The dirstate will be set to the files of the given revision.
2599 2562 The actual working directory content or existing dirstate
2600 2563 information such as adds or removes is not considered.
2601 2564
2602 2565 ``minimal`` will only rebuild the dirstate status for files that claim to be
2603 2566 tracked but are not in the parent manifest, or that exist in the parent
2604 2567 manifest but are not in the dirstate. It will not change adds, removes, or
2605 2568 modified files that are in the working copy parent.
2606 2569
2607 2570 One use of this command is to make the next :hg:`status` invocation
2608 2571 check the actual file content.
2609 2572 """
2610 2573 ctx = scmutil.revsingle(repo, rev)
2611 2574 with repo.wlock():
2612 2575 dirstate = repo.dirstate
2613 2576 changedfiles = None
2614 2577 # See command doc for what minimal does.
2615 2578 if opts.get('minimal'):
2616 2579 manifestfiles = set(ctx.manifest().keys())
2617 2580 dirstatefiles = set(dirstate)
2618 2581 manifestonly = manifestfiles - dirstatefiles
2619 2582 dsonly = dirstatefiles - manifestfiles
2620 2583 dsnotadded = set(f for f in dsonly if dirstate[f] != b'a')
2621 2584 changedfiles = manifestonly | dsnotadded
2622 2585
2623 2586 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2624 2587
2625 2588
2626 2589 @command(b'debugrebuildfncache', [], b'')
2627 2590 def debugrebuildfncache(ui, repo):
2628 2591 """rebuild the fncache file"""
2629 2592 repair.rebuildfncache(ui, repo)
2630 2593
2631 2594
2632 2595 @command(
2633 2596 b'debugrename',
2634 2597 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2635 2598 _(b'[-r REV] [FILE]...'),
2636 2599 )
2637 2600 def debugrename(ui, repo, *pats, **opts):
2638 2601 """dump rename information"""
2639 2602
2640 2603 opts = pycompat.byteskwargs(opts)
2641 2604 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2642 2605 m = scmutil.match(ctx, pats, opts)
2643 2606 for abs in ctx.walk(m):
2644 2607 fctx = ctx[abs]
2645 2608 o = fctx.filelog().renamed(fctx.filenode())
2646 2609 rel = repo.pathto(abs)
2647 2610 if o:
2648 2611 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2649 2612 else:
2650 2613 ui.write(_(b"%s not renamed\n") % rel)
2651 2614
2652 2615
2653 2616 @command(
2654 2617 b'debugrevlog',
2655 2618 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
2656 2619 _(b'-c|-m|FILE'),
2657 2620 optionalrepo=True,
2658 2621 )
2659 2622 def debugrevlog(ui, repo, file_=None, **opts):
2660 2623 """show data and statistics about a revlog"""
2661 2624 opts = pycompat.byteskwargs(opts)
2662 2625 r = cmdutil.openrevlog(repo, b'debugrevlog', file_, opts)
2663 2626
2664 2627 if opts.get(b"dump"):
2665 2628 numrevs = len(r)
2666 2629 ui.write(
2667 2630 (
2668 2631 b"# rev p1rev p2rev start end deltastart base p1 p2"
2669 2632 b" rawsize totalsize compression heads chainlen\n"
2670 2633 )
2671 2634 )
2672 2635 ts = 0
2673 2636 heads = set()
2674 2637
2675 2638 for rev in pycompat.xrange(numrevs):
2676 2639 dbase = r.deltaparent(rev)
2677 2640 if dbase == -1:
2678 2641 dbase = rev
2679 2642 cbase = r.chainbase(rev)
2680 2643 clen = r.chainlen(rev)
2681 2644 p1, p2 = r.parentrevs(rev)
2682 2645 rs = r.rawsize(rev)
2683 2646 ts = ts + rs
2684 2647 heads -= set(r.parentrevs(rev))
2685 2648 heads.add(rev)
2686 2649 try:
2687 2650 compression = ts / r.end(rev)
2688 2651 except ZeroDivisionError:
2689 2652 compression = 0
2690 2653 ui.write(
2691 2654 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2692 2655 b"%11d %5d %8d\n"
2693 2656 % (
2694 2657 rev,
2695 2658 p1,
2696 2659 p2,
2697 2660 r.start(rev),
2698 2661 r.end(rev),
2699 2662 r.start(dbase),
2700 2663 r.start(cbase),
2701 2664 r.start(p1),
2702 2665 r.start(p2),
2703 2666 rs,
2704 2667 ts,
2705 2668 compression,
2706 2669 len(heads),
2707 2670 clen,
2708 2671 )
2709 2672 )
2710 2673 return 0
2711 2674
2712 2675 v = r.version
2713 2676 format = v & 0xFFFF
2714 2677 flags = []
2715 2678 gdelta = False
2716 2679 if v & revlog.FLAG_INLINE_DATA:
2717 2680 flags.append(b'inline')
2718 2681 if v & revlog.FLAG_GENERALDELTA:
2719 2682 gdelta = True
2720 2683 flags.append(b'generaldelta')
2721 2684 if not flags:
2722 2685 flags = [b'(none)']
2723 2686
2724 2687 ### tracks merge vs single parent
2725 2688 nummerges = 0
2726 2689
2727 2690 ### tracks ways the "delta" are build
2728 2691 # nodelta
2729 2692 numempty = 0
2730 2693 numemptytext = 0
2731 2694 numemptydelta = 0
2732 2695 # full file content
2733 2696 numfull = 0
2734 2697 # intermediate snapshot against a prior snapshot
2735 2698 numsemi = 0
2736 2699 # snapshot count per depth
2737 2700 numsnapdepth = collections.defaultdict(lambda: 0)
2738 2701 # delta against previous revision
2739 2702 numprev = 0
2740 2703 # delta against first or second parent (not prev)
2741 2704 nump1 = 0
2742 2705 nump2 = 0
2743 2706 # delta against neither prev nor parents
2744 2707 numother = 0
2745 2708 # delta against prev that are also first or second parent
2746 2709 # (details of `numprev`)
2747 2710 nump1prev = 0
2748 2711 nump2prev = 0
2749 2712
2750 2713 # data about delta chain of each revs
2751 2714 chainlengths = []
2752 2715 chainbases = []
2753 2716 chainspans = []
2754 2717
2755 2718 # data about each revision
2756 2719 datasize = [None, 0, 0]
2757 2720 fullsize = [None, 0, 0]
2758 2721 semisize = [None, 0, 0]
2759 2722 # snapshot count per depth
2760 2723 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
2761 2724 deltasize = [None, 0, 0]
2762 2725 chunktypecounts = {}
2763 2726 chunktypesizes = {}
2764 2727
2765 2728 def addsize(size, l):
2766 2729 if l[0] is None or size < l[0]:
2767 2730 l[0] = size
2768 2731 if size > l[1]:
2769 2732 l[1] = size
2770 2733 l[2] += size
2771 2734
2772 2735 numrevs = len(r)
2773 2736 for rev in pycompat.xrange(numrevs):
2774 2737 p1, p2 = r.parentrevs(rev)
2775 2738 delta = r.deltaparent(rev)
2776 2739 if format > 0:
2777 2740 addsize(r.rawsize(rev), datasize)
2778 2741 if p2 != nullrev:
2779 2742 nummerges += 1
2780 2743 size = r.length(rev)
2781 2744 if delta == nullrev:
2782 2745 chainlengths.append(0)
2783 2746 chainbases.append(r.start(rev))
2784 2747 chainspans.append(size)
2785 2748 if size == 0:
2786 2749 numempty += 1
2787 2750 numemptytext += 1
2788 2751 else:
2789 2752 numfull += 1
2790 2753 numsnapdepth[0] += 1
2791 2754 addsize(size, fullsize)
2792 2755 addsize(size, snapsizedepth[0])
2793 2756 else:
2794 2757 chainlengths.append(chainlengths[delta] + 1)
2795 2758 baseaddr = chainbases[delta]
2796 2759 revaddr = r.start(rev)
2797 2760 chainbases.append(baseaddr)
2798 2761 chainspans.append((revaddr - baseaddr) + size)
2799 2762 if size == 0:
2800 2763 numempty += 1
2801 2764 numemptydelta += 1
2802 2765 elif r.issnapshot(rev):
2803 2766 addsize(size, semisize)
2804 2767 numsemi += 1
2805 2768 depth = r.snapshotdepth(rev)
2806 2769 numsnapdepth[depth] += 1
2807 2770 addsize(size, snapsizedepth[depth])
2808 2771 else:
2809 2772 addsize(size, deltasize)
2810 2773 if delta == rev - 1:
2811 2774 numprev += 1
2812 2775 if delta == p1:
2813 2776 nump1prev += 1
2814 2777 elif delta == p2:
2815 2778 nump2prev += 1
2816 2779 elif delta == p1:
2817 2780 nump1 += 1
2818 2781 elif delta == p2:
2819 2782 nump2 += 1
2820 2783 elif delta != nullrev:
2821 2784 numother += 1
2822 2785
2823 2786 # Obtain data on the raw chunks in the revlog.
2824 2787 if util.safehasattr(r, b'_getsegmentforrevs'):
2825 2788 segment = r._getsegmentforrevs(rev, rev)[1]
2826 2789 else:
2827 2790 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
2828 2791 if segment:
2829 2792 chunktype = bytes(segment[0:1])
2830 2793 else:
2831 2794 chunktype = b'empty'
2832 2795
2833 2796 if chunktype not in chunktypecounts:
2834 2797 chunktypecounts[chunktype] = 0
2835 2798 chunktypesizes[chunktype] = 0
2836 2799
2837 2800 chunktypecounts[chunktype] += 1
2838 2801 chunktypesizes[chunktype] += size
2839 2802
2840 2803 # Adjust size min value for empty cases
2841 2804 for size in (datasize, fullsize, semisize, deltasize):
2842 2805 if size[0] is None:
2843 2806 size[0] = 0
2844 2807
2845 2808 numdeltas = numrevs - numfull - numempty - numsemi
2846 2809 numoprev = numprev - nump1prev - nump2prev
2847 2810 totalrawsize = datasize[2]
2848 2811 datasize[2] /= numrevs
2849 2812 fulltotal = fullsize[2]
2850 2813 if numfull == 0:
2851 2814 fullsize[2] = 0
2852 2815 else:
2853 2816 fullsize[2] /= numfull
2854 2817 semitotal = semisize[2]
2855 2818 snaptotal = {}
2856 2819 if numsemi > 0:
2857 2820 semisize[2] /= numsemi
2858 2821 for depth in snapsizedepth:
2859 2822 snaptotal[depth] = snapsizedepth[depth][2]
2860 2823 snapsizedepth[depth][2] /= numsnapdepth[depth]
2861 2824
2862 2825 deltatotal = deltasize[2]
2863 2826 if numdeltas > 0:
2864 2827 deltasize[2] /= numdeltas
2865 2828 totalsize = fulltotal + semitotal + deltatotal
2866 2829 avgchainlen = sum(chainlengths) / numrevs
2867 2830 maxchainlen = max(chainlengths)
2868 2831 maxchainspan = max(chainspans)
2869 2832 compratio = 1
2870 2833 if totalsize:
2871 2834 compratio = totalrawsize / totalsize
2872 2835
2873 2836 basedfmtstr = b'%%%dd\n'
2874 2837 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
2875 2838
2876 2839 def dfmtstr(max):
2877 2840 return basedfmtstr % len(str(max))
2878 2841
2879 2842 def pcfmtstr(max, padding=0):
2880 2843 return basepcfmtstr % (len(str(max)), b' ' * padding)
2881 2844
2882 2845 def pcfmt(value, total):
2883 2846 if total:
2884 2847 return (value, 100 * float(value) / total)
2885 2848 else:
2886 2849 return value, 100.0
2887 2850
2888 2851 ui.writenoi18n(b'format : %d\n' % format)
2889 2852 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
2890 2853
2891 2854 ui.write(b'\n')
2892 2855 fmt = pcfmtstr(totalsize)
2893 2856 fmt2 = dfmtstr(totalsize)
2894 2857 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
2895 2858 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
2896 2859 ui.writenoi18n(
2897 2860 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
2898 2861 )
2899 2862 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
2900 2863 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
2901 2864 ui.writenoi18n(
2902 2865 b' text : '
2903 2866 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
2904 2867 )
2905 2868 ui.writenoi18n(
2906 2869 b' delta : '
2907 2870 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
2908 2871 )
2909 2872 ui.writenoi18n(
2910 2873 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
2911 2874 )
2912 2875 for depth in sorted(numsnapdepth):
2913 2876 ui.write(
2914 2877 (b' lvl-%-3d : ' % depth)
2915 2878 + fmt % pcfmt(numsnapdepth[depth], numrevs)
2916 2879 )
2917 2880 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2918 2881 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
2919 2882 ui.writenoi18n(
2920 2883 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
2921 2884 )
2922 2885 for depth in sorted(numsnapdepth):
2923 2886 ui.write(
2924 2887 (b' lvl-%-3d : ' % depth)
2925 2888 + fmt % pcfmt(snaptotal[depth], totalsize)
2926 2889 )
2927 2890 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2928 2891
2929 2892 def fmtchunktype(chunktype):
2930 2893 if chunktype == b'empty':
2931 2894 return b' %s : ' % chunktype
2932 2895 elif chunktype in pycompat.bytestr(string.ascii_letters):
2933 2896 return b' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2934 2897 else:
2935 2898 return b' 0x%s : ' % hex(chunktype)
2936 2899
2937 2900 ui.write(b'\n')
2938 2901 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
2939 2902 for chunktype in sorted(chunktypecounts):
2940 2903 ui.write(fmtchunktype(chunktype))
2941 2904 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2942 2905 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
2943 2906 for chunktype in sorted(chunktypecounts):
2944 2907 ui.write(fmtchunktype(chunktype))
2945 2908 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2946 2909
2947 2910 ui.write(b'\n')
2948 2911 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
2949 2912 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
2950 2913 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
2951 2914 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
2952 2915 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
2953 2916
2954 2917 if format > 0:
2955 2918 ui.write(b'\n')
2956 2919 ui.writenoi18n(
2957 2920 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
2958 2921 % tuple(datasize)
2959 2922 )
2960 2923 ui.writenoi18n(
2961 2924 b'full revision size (min/max/avg) : %d / %d / %d\n'
2962 2925 % tuple(fullsize)
2963 2926 )
2964 2927 ui.writenoi18n(
2965 2928 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
2966 2929 % tuple(semisize)
2967 2930 )
2968 2931 for depth in sorted(snapsizedepth):
2969 2932 if depth == 0:
2970 2933 continue
2971 2934 ui.writenoi18n(
2972 2935 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
2973 2936 % ((depth,) + tuple(snapsizedepth[depth]))
2974 2937 )
2975 2938 ui.writenoi18n(
2976 2939 b'delta size (min/max/avg) : %d / %d / %d\n'
2977 2940 % tuple(deltasize)
2978 2941 )
2979 2942
2980 2943 if numdeltas > 0:
2981 2944 ui.write(b'\n')
2982 2945 fmt = pcfmtstr(numdeltas)
2983 2946 fmt2 = pcfmtstr(numdeltas, 4)
2984 2947 ui.writenoi18n(
2985 2948 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
2986 2949 )
2987 2950 if numprev > 0:
2988 2951 ui.writenoi18n(
2989 2952 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
2990 2953 )
2991 2954 ui.writenoi18n(
2992 2955 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
2993 2956 )
2994 2957 ui.writenoi18n(
2995 2958 b' other : ' + fmt2 % pcfmt(numoprev, numprev)
2996 2959 )
2997 2960 if gdelta:
2998 2961 ui.writenoi18n(
2999 2962 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
3000 2963 )
3001 2964 ui.writenoi18n(
3002 2965 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
3003 2966 )
3004 2967 ui.writenoi18n(
3005 2968 b'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
3006 2969 )
3007 2970
3008 2971
3009 2972 @command(
3010 2973 b'debugrevlogindex',
3011 2974 cmdutil.debugrevlogopts
3012 2975 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3013 2976 _(b'[-f FORMAT] -c|-m|FILE'),
3014 2977 optionalrepo=True,
3015 2978 )
3016 2979 def debugrevlogindex(ui, repo, file_=None, **opts):
3017 2980 """dump the contents of a revlog index"""
3018 2981 opts = pycompat.byteskwargs(opts)
3019 2982 r = cmdutil.openrevlog(repo, b'debugrevlogindex', file_, opts)
3020 2983 format = opts.get(b'format', 0)
3021 2984 if format not in (0, 1):
3022 2985 raise error.Abort(_(b"unknown format %d") % format)
3023 2986
3024 2987 if ui.debugflag:
3025 2988 shortfn = hex
3026 2989 else:
3027 2990 shortfn = short
3028 2991
3029 2992 # There might not be anything in r, so have a sane default
3030 2993 idlen = 12
3031 2994 for i in r:
3032 2995 idlen = len(shortfn(r.node(i)))
3033 2996 break
3034 2997
3035 2998 if format == 0:
3036 2999 if ui.verbose:
3037 3000 ui.writenoi18n(
3038 3001 b" rev offset length linkrev %s %s p2\n"
3039 3002 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3040 3003 )
3041 3004 else:
3042 3005 ui.writenoi18n(
3043 3006 b" rev linkrev %s %s p2\n"
3044 3007 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3045 3008 )
3046 3009 elif format == 1:
3047 3010 if ui.verbose:
3048 3011 ui.writenoi18n(
3049 3012 (
3050 3013 b" rev flag offset length size link p1"
3051 3014 b" p2 %s\n"
3052 3015 )
3053 3016 % b"nodeid".rjust(idlen)
3054 3017 )
3055 3018 else:
3056 3019 ui.writenoi18n(
3057 3020 b" rev flag size link p1 p2 %s\n"
3058 3021 % b"nodeid".rjust(idlen)
3059 3022 )
3060 3023
3061 3024 for i in r:
3062 3025 node = r.node(i)
3063 3026 if format == 0:
3064 3027 try:
3065 3028 pp = r.parents(node)
3066 3029 except Exception:
3067 3030 pp = [nullid, nullid]
3068 3031 if ui.verbose:
3069 3032 ui.write(
3070 3033 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3071 3034 % (
3072 3035 i,
3073 3036 r.start(i),
3074 3037 r.length(i),
3075 3038 r.linkrev(i),
3076 3039 shortfn(node),
3077 3040 shortfn(pp[0]),
3078 3041 shortfn(pp[1]),
3079 3042 )
3080 3043 )
3081 3044 else:
3082 3045 ui.write(
3083 3046 b"% 6d % 7d %s %s %s\n"
3084 3047 % (
3085 3048 i,
3086 3049 r.linkrev(i),
3087 3050 shortfn(node),
3088 3051 shortfn(pp[0]),
3089 3052 shortfn(pp[1]),
3090 3053 )
3091 3054 )
3092 3055 elif format == 1:
3093 3056 pr = r.parentrevs(i)
3094 3057 if ui.verbose:
3095 3058 ui.write(
3096 3059 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3097 3060 % (
3098 3061 i,
3099 3062 r.flags(i),
3100 3063 r.start(i),
3101 3064 r.length(i),
3102 3065 r.rawsize(i),
3103 3066 r.linkrev(i),
3104 3067 pr[0],
3105 3068 pr[1],
3106 3069 shortfn(node),
3107 3070 )
3108 3071 )
3109 3072 else:
3110 3073 ui.write(
3111 3074 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3112 3075 % (
3113 3076 i,
3114 3077 r.flags(i),
3115 3078 r.rawsize(i),
3116 3079 r.linkrev(i),
3117 3080 pr[0],
3118 3081 pr[1],
3119 3082 shortfn(node),
3120 3083 )
3121 3084 )
3122 3085
3123 3086
3124 3087 @command(
3125 3088 b'debugrevspec',
3126 3089 [
3127 3090 (
3128 3091 b'',
3129 3092 b'optimize',
3130 3093 None,
3131 3094 _(b'print parsed tree after optimizing (DEPRECATED)'),
3132 3095 ),
3133 3096 (
3134 3097 b'',
3135 3098 b'show-revs',
3136 3099 True,
3137 3100 _(b'print list of result revisions (default)'),
3138 3101 ),
3139 3102 (
3140 3103 b's',
3141 3104 b'show-set',
3142 3105 None,
3143 3106 _(b'print internal representation of result set'),
3144 3107 ),
3145 3108 (
3146 3109 b'p',
3147 3110 b'show-stage',
3148 3111 [],
3149 3112 _(b'print parsed tree at the given stage'),
3150 3113 _(b'NAME'),
3151 3114 ),
3152 3115 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3153 3116 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3154 3117 ],
3155 3118 b'REVSPEC',
3156 3119 )
3157 3120 def debugrevspec(ui, repo, expr, **opts):
3158 3121 """parse and apply a revision specification
3159 3122
3160 3123 Use -p/--show-stage option to print the parsed tree at the given stages.
3161 3124 Use -p all to print tree at every stage.
3162 3125
3163 3126 Use --no-show-revs option with -s or -p to print only the set
3164 3127 representation or the parsed tree respectively.
3165 3128
3166 3129 Use --verify-optimized to compare the optimized result with the unoptimized
3167 3130 one. Returns 1 if the optimized result differs.
3168 3131 """
3169 3132 opts = pycompat.byteskwargs(opts)
3170 3133 aliases = ui.configitems(b'revsetalias')
3171 3134 stages = [
3172 3135 (b'parsed', lambda tree: tree),
3173 3136 (
3174 3137 b'expanded',
3175 3138 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3176 3139 ),
3177 3140 (b'concatenated', revsetlang.foldconcat),
3178 3141 (b'analyzed', revsetlang.analyze),
3179 3142 (b'optimized', revsetlang.optimize),
3180 3143 ]
3181 3144 if opts[b'no_optimized']:
3182 3145 stages = stages[:-1]
3183 3146 if opts[b'verify_optimized'] and opts[b'no_optimized']:
3184 3147 raise error.Abort(
3185 3148 _(b'cannot use --verify-optimized with --no-optimized')
3186 3149 )
3187 3150 stagenames = set(n for n, f in stages)
3188 3151
3189 3152 showalways = set()
3190 3153 showchanged = set()
3191 3154 if ui.verbose and not opts[b'show_stage']:
3192 3155 # show parsed tree by --verbose (deprecated)
3193 3156 showalways.add(b'parsed')
3194 3157 showchanged.update([b'expanded', b'concatenated'])
3195 3158 if opts[b'optimize']:
3196 3159 showalways.add(b'optimized')
3197 3160 if opts[b'show_stage'] and opts[b'optimize']:
3198 3161 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3199 3162 if opts[b'show_stage'] == [b'all']:
3200 3163 showalways.update(stagenames)
3201 3164 else:
3202 3165 for n in opts[b'show_stage']:
3203 3166 if n not in stagenames:
3204 3167 raise error.Abort(_(b'invalid stage name: %s') % n)
3205 3168 showalways.update(opts[b'show_stage'])
3206 3169
3207 3170 treebystage = {}
3208 3171 printedtree = None
3209 3172 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3210 3173 for n, f in stages:
3211 3174 treebystage[n] = tree = f(tree)
3212 3175 if n in showalways or (n in showchanged and tree != printedtree):
3213 3176 if opts[b'show_stage'] or n != b'parsed':
3214 3177 ui.write(b"* %s:\n" % n)
3215 3178 ui.write(revsetlang.prettyformat(tree), b"\n")
3216 3179 printedtree = tree
3217 3180
3218 3181 if opts[b'verify_optimized']:
3219 3182 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3220 3183 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3221 3184 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3222 3185 ui.writenoi18n(
3223 3186 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3224 3187 )
3225 3188 ui.writenoi18n(
3226 3189 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3227 3190 )
3228 3191 arevs = list(arevs)
3229 3192 brevs = list(brevs)
3230 3193 if arevs == brevs:
3231 3194 return 0
3232 3195 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3233 3196 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3234 3197 sm = difflib.SequenceMatcher(None, arevs, brevs)
3235 3198 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3236 3199 if tag in ('delete', 'replace'):
3237 3200 for c in arevs[alo:ahi]:
3238 3201 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3239 3202 if tag in ('insert', 'replace'):
3240 3203 for c in brevs[blo:bhi]:
3241 3204 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3242 3205 if tag == 'equal':
3243 3206 for c in arevs[alo:ahi]:
3244 3207 ui.write(b' %d\n' % c)
3245 3208 return 1
3246 3209
3247 3210 func = revset.makematcher(tree)
3248 3211 revs = func(repo)
3249 3212 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3250 3213 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3251 3214 if not opts[b'show_revs']:
3252 3215 return
3253 3216 for c in revs:
3254 3217 ui.write(b"%d\n" % c)
3255 3218
3256 3219
3257 3220 @command(
3258 3221 b'debugserve',
3259 3222 [
3260 3223 (
3261 3224 b'',
3262 3225 b'sshstdio',
3263 3226 False,
3264 3227 _(b'run an SSH server bound to process handles'),
3265 3228 ),
3266 3229 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3267 3230 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3268 3231 ],
3269 3232 b'',
3270 3233 )
3271 3234 def debugserve(ui, repo, **opts):
3272 3235 """run a server with advanced settings
3273 3236
3274 3237 This command is similar to :hg:`serve`. It exists partially as a
3275 3238 workaround to the fact that ``hg serve --stdio`` must have specific
3276 3239 arguments for security reasons.
3277 3240 """
3278 3241 opts = pycompat.byteskwargs(opts)
3279 3242
3280 3243 if not opts[b'sshstdio']:
3281 3244 raise error.Abort(_(b'only --sshstdio is currently supported'))
3282 3245
3283 3246 logfh = None
3284 3247
3285 3248 if opts[b'logiofd'] and opts[b'logiofile']:
3286 3249 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3287 3250
3288 3251 if opts[b'logiofd']:
3289 3252 # Ideally we would be line buffered. But line buffering in binary
3290 3253 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3291 3254 # buffering could have performance impacts. But since this isn't
3292 3255 # performance critical code, it should be fine.
3293 3256 try:
3294 3257 logfh = os.fdopen(int(opts[b'logiofd']), 'ab', 0)
3295 3258 except OSError as e:
3296 3259 if e.errno != errno.ESPIPE:
3297 3260 raise
3298 3261 # can't seek a pipe, so `ab` mode fails on py3
3299 3262 logfh = os.fdopen(int(opts[b'logiofd']), 'wb', 0)
3300 3263 elif opts[b'logiofile']:
3301 3264 logfh = open(opts[b'logiofile'], b'ab', 0)
3302 3265
3303 3266 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3304 3267 s.serve_forever()
3305 3268
3306 3269
3307 3270 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3308 3271 def debugsetparents(ui, repo, rev1, rev2=None):
3309 3272 """manually set the parents of the current working directory
3310 3273
3311 3274 This is useful for writing repository conversion tools, but should
3312 3275 be used with care. For example, neither the working directory nor the
3313 3276 dirstate is updated, so file status may be incorrect after running this
3314 3277 command.
3315 3278
3316 3279 Returns 0 on success.
3317 3280 """
3318 3281
3319 3282 node1 = scmutil.revsingle(repo, rev1).node()
3320 3283 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3321 3284
3322 3285 with repo.wlock():
3323 3286 repo.setparents(node1, node2)
3324 3287
3325 3288
3326 3289 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3327 3290 def debugsidedata(ui, repo, file_, rev=None, **opts):
3328 3291 """dump the side data for a cl/manifest/file revision
3329 3292
3330 3293 Use --verbose to dump the sidedata content."""
3331 3294 opts = pycompat.byteskwargs(opts)
3332 3295 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
3333 3296 if rev is not None:
3334 3297 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3335 3298 file_, rev = None, file_
3336 3299 elif rev is None:
3337 3300 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3338 3301 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
3339 3302 r = getattr(r, '_revlog', r)
3340 3303 try:
3341 3304 sidedata = r.sidedata(r.lookup(rev))
3342 3305 except KeyError:
3343 3306 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3344 3307 if sidedata:
3345 3308 sidedata = list(sidedata.items())
3346 3309 sidedata.sort()
3347 3310 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3348 3311 for key, value in sidedata:
3349 3312 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3350 3313 if ui.verbose:
3351 3314 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3352 3315
3353 3316
3354 3317 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3355 3318 def debugssl(ui, repo, source=None, **opts):
3356 3319 '''test a secure connection to a server
3357 3320
3358 3321 This builds the certificate chain for the server on Windows, installing the
3359 3322 missing intermediates and trusted root via Windows Update if necessary. It
3360 3323 does nothing on other platforms.
3361 3324
3362 3325 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3363 3326 that server is used. See :hg:`help urls` for more information.
3364 3327
3365 3328 If the update succeeds, retry the original operation. Otherwise, the cause
3366 3329 of the SSL error is likely another issue.
3367 3330 '''
3368 3331 if not pycompat.iswindows:
3369 3332 raise error.Abort(
3370 3333 _(b'certificate chain building is only possible on Windows')
3371 3334 )
3372 3335
3373 3336 if not source:
3374 3337 if not repo:
3375 3338 raise error.Abort(
3376 3339 _(
3377 3340 b"there is no Mercurial repository here, and no "
3378 3341 b"server specified"
3379 3342 )
3380 3343 )
3381 3344 source = b"default"
3382 3345
3383 3346 source, branches = hg.parseurl(ui.expandpath(source))
3384 3347 url = util.url(source)
3385 3348
3386 3349 defaultport = {b'https': 443, b'ssh': 22}
3387 3350 if url.scheme in defaultport:
3388 3351 try:
3389 3352 addr = (url.host, int(url.port or defaultport[url.scheme]))
3390 3353 except ValueError:
3391 3354 raise error.Abort(_(b"malformed port number in URL"))
3392 3355 else:
3393 3356 raise error.Abort(_(b"only https and ssh connections are supported"))
3394 3357
3395 3358 from . import win32
3396 3359
3397 3360 s = ssl.wrap_socket(
3398 3361 socket.socket(),
3399 3362 ssl_version=ssl.PROTOCOL_TLS,
3400 3363 cert_reqs=ssl.CERT_NONE,
3401 3364 ca_certs=None,
3402 3365 )
3403 3366
3404 3367 try:
3405 3368 s.connect(addr)
3406 3369 cert = s.getpeercert(True)
3407 3370
3408 3371 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3409 3372
3410 3373 complete = win32.checkcertificatechain(cert, build=False)
3411 3374
3412 3375 if not complete:
3413 3376 ui.status(_(b'certificate chain is incomplete, updating... '))
3414 3377
3415 3378 if not win32.checkcertificatechain(cert):
3416 3379 ui.status(_(b'failed.\n'))
3417 3380 else:
3418 3381 ui.status(_(b'done.\n'))
3419 3382 else:
3420 3383 ui.status(_(b'full certificate chain is available\n'))
3421 3384 finally:
3422 3385 s.close()
3423 3386
3424 3387
3425 3388 @command(
3426 3389 b'debugsub',
3427 3390 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3428 3391 _(b'[-r REV] [REV]'),
3429 3392 )
3430 3393 def debugsub(ui, repo, rev=None):
3431 3394 ctx = scmutil.revsingle(repo, rev, None)
3432 3395 for k, v in sorted(ctx.substate.items()):
3433 3396 ui.writenoi18n(b'path %s\n' % k)
3434 3397 ui.writenoi18n(b' source %s\n' % v[0])
3435 3398 ui.writenoi18n(b' revision %s\n' % v[1])
3436 3399
3437 3400
3438 3401 @command(
3439 3402 b'debugsuccessorssets',
3440 3403 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3441 3404 _(b'[REV]'),
3442 3405 )
3443 3406 def debugsuccessorssets(ui, repo, *revs, **opts):
3444 3407 """show set of successors for revision
3445 3408
3446 3409 A successors set of changeset A is a consistent group of revisions that
3447 3410 succeed A. It contains non-obsolete changesets only unless closests
3448 3411 successors set is set.
3449 3412
3450 3413 In most cases a changeset A has a single successors set containing a single
3451 3414 successor (changeset A replaced by A').
3452 3415
3453 3416 A changeset that is made obsolete with no successors are called "pruned".
3454 3417 Such changesets have no successors sets at all.
3455 3418
3456 3419 A changeset that has been "split" will have a successors set containing
3457 3420 more than one successor.
3458 3421
3459 3422 A changeset that has been rewritten in multiple different ways is called
3460 3423 "divergent". Such changesets have multiple successor sets (each of which
3461 3424 may also be split, i.e. have multiple successors).
3462 3425
3463 3426 Results are displayed as follows::
3464 3427
3465 3428 <rev1>
3466 3429 <successors-1A>
3467 3430 <rev2>
3468 3431 <successors-2A>
3469 3432 <successors-2B1> <successors-2B2> <successors-2B3>
3470 3433
3471 3434 Here rev2 has two possible (i.e. divergent) successors sets. The first
3472 3435 holds one element, whereas the second holds three (i.e. the changeset has
3473 3436 been split).
3474 3437 """
3475 3438 # passed to successorssets caching computation from one call to another
3476 3439 cache = {}
3477 3440 ctx2str = bytes
3478 3441 node2str = short
3479 3442 for rev in scmutil.revrange(repo, revs):
3480 3443 ctx = repo[rev]
3481 3444 ui.write(b'%s\n' % ctx2str(ctx))
3482 3445 for succsset in obsutil.successorssets(
3483 3446 repo, ctx.node(), closest=opts['closest'], cache=cache
3484 3447 ):
3485 3448 if succsset:
3486 3449 ui.write(b' ')
3487 3450 ui.write(node2str(succsset[0]))
3488 3451 for node in succsset[1:]:
3489 3452 ui.write(b' ')
3490 3453 ui.write(node2str(node))
3491 3454 ui.write(b'\n')
3492 3455
3493 3456
3494 3457 @command(b'debugtagscache', [])
3495 3458 def debugtagscache(ui, repo):
3496 3459 """display the contents of .hg/cache/hgtagsfnodes1"""
3497 3460 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
3498 3461 for r in repo:
3499 3462 node = repo[r].node()
3500 3463 tagsnode = cache.getfnode(node, computemissing=False)
3501 3464 tagsnodedisplay = hex(tagsnode) if tagsnode else b'missing/invalid'
3502 3465 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
3503 3466
3504 3467
3505 3468 @command(
3506 3469 b'debugtemplate',
3507 3470 [
3508 3471 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
3509 3472 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
3510 3473 ],
3511 3474 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3512 3475 optionalrepo=True,
3513 3476 )
3514 3477 def debugtemplate(ui, repo, tmpl, **opts):
3515 3478 """parse and apply a template
3516 3479
3517 3480 If -r/--rev is given, the template is processed as a log template and
3518 3481 applied to the given changesets. Otherwise, it is processed as a generic
3519 3482 template.
3520 3483
3521 3484 Use --verbose to print the parsed tree.
3522 3485 """
3523 3486 revs = None
3524 3487 if opts['rev']:
3525 3488 if repo is None:
3526 3489 raise error.RepoError(
3527 3490 _(b'there is no Mercurial repository here (.hg not found)')
3528 3491 )
3529 3492 revs = scmutil.revrange(repo, opts['rev'])
3530 3493
3531 3494 props = {}
3532 3495 for d in opts['define']:
3533 3496 try:
3534 3497 k, v = (e.strip() for e in d.split(b'=', 1))
3535 3498 if not k or k == b'ui':
3536 3499 raise ValueError
3537 3500 props[k] = v
3538 3501 except ValueError:
3539 3502 raise error.Abort(_(b'malformed keyword definition: %s') % d)
3540 3503
3541 3504 if ui.verbose:
3542 3505 aliases = ui.configitems(b'templatealias')
3543 3506 tree = templater.parse(tmpl)
3544 3507 ui.note(templater.prettyformat(tree), b'\n')
3545 3508 newtree = templater.expandaliases(tree, aliases)
3546 3509 if newtree != tree:
3547 3510 ui.notenoi18n(
3548 3511 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
3549 3512 )
3550 3513
3551 3514 if revs is None:
3552 3515 tres = formatter.templateresources(ui, repo)
3553 3516 t = formatter.maketemplater(ui, tmpl, resources=tres)
3554 3517 if ui.verbose:
3555 3518 kwds, funcs = t.symbolsuseddefault()
3556 3519 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3557 3520 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3558 3521 ui.write(t.renderdefault(props))
3559 3522 else:
3560 3523 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
3561 3524 if ui.verbose:
3562 3525 kwds, funcs = displayer.t.symbolsuseddefault()
3563 3526 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3564 3527 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3565 3528 for r in revs:
3566 3529 displayer.show(repo[r], **pycompat.strkwargs(props))
3567 3530 displayer.close()
3568 3531
3569 3532
3570 3533 @command(
3571 3534 b'debuguigetpass',
3572 3535 [(b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),],
3573 3536 _(b'[-p TEXT]'),
3574 3537 norepo=True,
3575 3538 )
3576 3539 def debuguigetpass(ui, prompt=b''):
3577 3540 """show prompt to type password"""
3578 3541 r = ui.getpass(prompt)
3579 3542 ui.writenoi18n(b'respose: %s\n' % r)
3580 3543
3581 3544
3582 3545 @command(
3583 3546 b'debuguiprompt',
3584 3547 [(b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),],
3585 3548 _(b'[-p TEXT]'),
3586 3549 norepo=True,
3587 3550 )
3588 3551 def debuguiprompt(ui, prompt=b''):
3589 3552 """show plain prompt"""
3590 3553 r = ui.prompt(prompt)
3591 3554 ui.writenoi18n(b'response: %s\n' % r)
3592 3555
3593 3556
3594 3557 @command(b'debugupdatecaches', [])
3595 3558 def debugupdatecaches(ui, repo, *pats, **opts):
3596 3559 """warm all known caches in the repository"""
3597 3560 with repo.wlock(), repo.lock():
3598 3561 repo.updatecaches(full=True)
3599 3562
3600 3563
3601 3564 @command(
3602 3565 b'debugupgraderepo',
3603 3566 [
3604 3567 (
3605 3568 b'o',
3606 3569 b'optimize',
3607 3570 [],
3608 3571 _(b'extra optimization to perform'),
3609 3572 _(b'NAME'),
3610 3573 ),
3611 3574 (b'', b'run', False, _(b'performs an upgrade')),
3612 3575 (b'', b'backup', True, _(b'keep the old repository content around')),
3613 3576 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
3614 3577 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
3615 3578 ],
3616 3579 )
3617 3580 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
3618 3581 """upgrade a repository to use different features
3619 3582
3620 3583 If no arguments are specified, the repository is evaluated for upgrade
3621 3584 and a list of problems and potential optimizations is printed.
3622 3585
3623 3586 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
3624 3587 can be influenced via additional arguments. More details will be provided
3625 3588 by the command output when run without ``--run``.
3626 3589
3627 3590 During the upgrade, the repository will be locked and no writes will be
3628 3591 allowed.
3629 3592
3630 3593 At the end of the upgrade, the repository may not be readable while new
3631 3594 repository data is swapped in. This window will be as long as it takes to
3632 3595 rename some directories inside the ``.hg`` directory. On most machines, this
3633 3596 should complete almost instantaneously and the chances of a consumer being
3634 3597 unable to access the repository should be low.
3635 3598
3636 3599 By default, all revlog will be upgraded. You can restrict this using flag
3637 3600 such as `--manifest`:
3638 3601
3639 3602 * `--manifest`: only optimize the manifest
3640 3603 * `--no-manifest`: optimize all revlog but the manifest
3641 3604 * `--changelog`: optimize the changelog only
3642 3605 * `--no-changelog --no-manifest`: optimize filelogs only
3643 3606 """
3644 3607 return upgrade.upgraderepo(
3645 3608 ui, repo, run=run, optimize=optimize, backup=backup, **opts
3646 3609 )
3647 3610
3648 3611
3649 3612 @command(
3650 3613 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
3651 3614 )
3652 3615 def debugwalk(ui, repo, *pats, **opts):
3653 3616 """show how files match on given patterns"""
3654 3617 opts = pycompat.byteskwargs(opts)
3655 3618 m = scmutil.match(repo[None], pats, opts)
3656 3619 if ui.verbose:
3657 3620 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
3658 3621 items = list(repo[None].walk(m))
3659 3622 if not items:
3660 3623 return
3661 3624 f = lambda fn: fn
3662 3625 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
3663 3626 f = lambda fn: util.normpath(fn)
3664 3627 fmt = b'f %%-%ds %%-%ds %%s' % (
3665 3628 max([len(abs) for abs in items]),
3666 3629 max([len(repo.pathto(abs)) for abs in items]),
3667 3630 )
3668 3631 for abs in items:
3669 3632 line = fmt % (
3670 3633 abs,
3671 3634 f(repo.pathto(abs)),
3672 3635 m.exact(abs) and b'exact' or b'',
3673 3636 )
3674 3637 ui.write(b"%s\n" % line.rstrip())
3675 3638
3676 3639
3677 3640 @command(b'debugwhyunstable', [], _(b'REV'))
3678 3641 def debugwhyunstable(ui, repo, rev):
3679 3642 """explain instabilities of a changeset"""
3680 3643 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
3681 3644 dnodes = b''
3682 3645 if entry.get(b'divergentnodes'):
3683 3646 dnodes = (
3684 3647 b' '.join(
3685 3648 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
3686 3649 for ctx in entry[b'divergentnodes']
3687 3650 )
3688 3651 + b' '
3689 3652 )
3690 3653 ui.write(
3691 3654 b'%s: %s%s %s\n'
3692 3655 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
3693 3656 )
3694 3657
3695 3658
3696 3659 @command(
3697 3660 b'debugwireargs',
3698 3661 [
3699 3662 (b'', b'three', b'', b'three'),
3700 3663 (b'', b'four', b'', b'four'),
3701 3664 (b'', b'five', b'', b'five'),
3702 3665 ]
3703 3666 + cmdutil.remoteopts,
3704 3667 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
3705 3668 norepo=True,
3706 3669 )
3707 3670 def debugwireargs(ui, repopath, *vals, **opts):
3708 3671 opts = pycompat.byteskwargs(opts)
3709 3672 repo = hg.peer(ui, opts, repopath)
3710 3673 for opt in cmdutil.remoteopts:
3711 3674 del opts[opt[1]]
3712 3675 args = {}
3713 3676 for k, v in pycompat.iteritems(opts):
3714 3677 if v:
3715 3678 args[k] = v
3716 3679 args = pycompat.strkwargs(args)
3717 3680 # run twice to check that we don't mess up the stream for the next command
3718 3681 res1 = repo.debugwireargs(*vals, **args)
3719 3682 res2 = repo.debugwireargs(*vals, **args)
3720 3683 ui.write(b"%s\n" % res1)
3721 3684 if res1 != res2:
3722 3685 ui.warn(b"%s\n" % res2)
3723 3686
3724 3687
3725 3688 def _parsewirelangblocks(fh):
3726 3689 activeaction = None
3727 3690 blocklines = []
3728 3691 lastindent = 0
3729 3692
3730 3693 for line in fh:
3731 3694 line = line.rstrip()
3732 3695 if not line:
3733 3696 continue
3734 3697
3735 3698 if line.startswith(b'#'):
3736 3699 continue
3737 3700
3738 3701 if not line.startswith(b' '):
3739 3702 # New block. Flush previous one.
3740 3703 if activeaction:
3741 3704 yield activeaction, blocklines
3742 3705
3743 3706 activeaction = line
3744 3707 blocklines = []
3745 3708 lastindent = 0
3746 3709 continue
3747 3710
3748 3711 # Else we start with an indent.
3749 3712
3750 3713 if not activeaction:
3751 3714 raise error.Abort(_(b'indented line outside of block'))
3752 3715
3753 3716 indent = len(line) - len(line.lstrip())
3754 3717
3755 3718 # If this line is indented more than the last line, concatenate it.
3756 3719 if indent > lastindent and blocklines:
3757 3720 blocklines[-1] += line.lstrip()
3758 3721 else:
3759 3722 blocklines.append(line)
3760 3723 lastindent = indent
3761 3724
3762 3725 # Flush last block.
3763 3726 if activeaction:
3764 3727 yield activeaction, blocklines
3765 3728
3766 3729
3767 3730 @command(
3768 3731 b'debugwireproto',
3769 3732 [
3770 3733 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
3771 3734 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
3772 3735 (
3773 3736 b'',
3774 3737 b'noreadstderr',
3775 3738 False,
3776 3739 _(b'do not read from stderr of the remote'),
3777 3740 ),
3778 3741 (
3779 3742 b'',
3780 3743 b'nologhandshake',
3781 3744 False,
3782 3745 _(b'do not log I/O related to the peer handshake'),
3783 3746 ),
3784 3747 ]
3785 3748 + cmdutil.remoteopts,
3786 3749 _(b'[PATH]'),
3787 3750 optionalrepo=True,
3788 3751 )
3789 3752 def debugwireproto(ui, repo, path=None, **opts):
3790 3753 """send wire protocol commands to a server
3791 3754
3792 3755 This command can be used to issue wire protocol commands to remote
3793 3756 peers and to debug the raw data being exchanged.
3794 3757
3795 3758 ``--localssh`` will start an SSH server against the current repository
3796 3759 and connect to that. By default, the connection will perform a handshake
3797 3760 and establish an appropriate peer instance.
3798 3761
3799 3762 ``--peer`` can be used to bypass the handshake protocol and construct a
3800 3763 peer instance using the specified class type. Valid values are ``raw``,
3801 3764 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
3802 3765 raw data payloads and don't support higher-level command actions.
3803 3766
3804 3767 ``--noreadstderr`` can be used to disable automatic reading from stderr
3805 3768 of the peer (for SSH connections only). Disabling automatic reading of
3806 3769 stderr is useful for making output more deterministic.
3807 3770
3808 3771 Commands are issued via a mini language which is specified via stdin.
3809 3772 The language consists of individual actions to perform. An action is
3810 3773 defined by a block. A block is defined as a line with no leading
3811 3774 space followed by 0 or more lines with leading space. Blocks are
3812 3775 effectively a high-level command with additional metadata.
3813 3776
3814 3777 Lines beginning with ``#`` are ignored.
3815 3778
3816 3779 The following sections denote available actions.
3817 3780
3818 3781 raw
3819 3782 ---
3820 3783
3821 3784 Send raw data to the server.
3822 3785
3823 3786 The block payload contains the raw data to send as one atomic send
3824 3787 operation. The data may not actually be delivered in a single system
3825 3788 call: it depends on the abilities of the transport being used.
3826 3789
3827 3790 Each line in the block is de-indented and concatenated. Then, that
3828 3791 value is evaluated as a Python b'' literal. This allows the use of
3829 3792 backslash escaping, etc.
3830 3793
3831 3794 raw+
3832 3795 ----
3833 3796
3834 3797 Behaves like ``raw`` except flushes output afterwards.
3835 3798
3836 3799 command <X>
3837 3800 -----------
3838 3801
3839 3802 Send a request to run a named command, whose name follows the ``command``
3840 3803 string.
3841 3804
3842 3805 Arguments to the command are defined as lines in this block. The format of
3843 3806 each line is ``<key> <value>``. e.g.::
3844 3807
3845 3808 command listkeys
3846 3809 namespace bookmarks
3847 3810
3848 3811 If the value begins with ``eval:``, it will be interpreted as a Python
3849 3812 literal expression. Otherwise values are interpreted as Python b'' literals.
3850 3813 This allows sending complex types and encoding special byte sequences via
3851 3814 backslash escaping.
3852 3815
3853 3816 The following arguments have special meaning:
3854 3817
3855 3818 ``PUSHFILE``
3856 3819 When defined, the *push* mechanism of the peer will be used instead
3857 3820 of the static request-response mechanism and the content of the
3858 3821 file specified in the value of this argument will be sent as the
3859 3822 command payload.
3860 3823
3861 3824 This can be used to submit a local bundle file to the remote.
3862 3825
3863 3826 batchbegin
3864 3827 ----------
3865 3828
3866 3829 Instruct the peer to begin a batched send.
3867 3830
3868 3831 All ``command`` blocks are queued for execution until the next
3869 3832 ``batchsubmit`` block.
3870 3833
3871 3834 batchsubmit
3872 3835 -----------
3873 3836
3874 3837 Submit previously queued ``command`` blocks as a batch request.
3875 3838
3876 3839 This action MUST be paired with a ``batchbegin`` action.
3877 3840
3878 3841 httprequest <method> <path>
3879 3842 ---------------------------
3880 3843
3881 3844 (HTTP peer only)
3882 3845
3883 3846 Send an HTTP request to the peer.
3884 3847
3885 3848 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
3886 3849
3887 3850 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
3888 3851 headers to add to the request. e.g. ``Accept: foo``.
3889 3852
3890 3853 The following arguments are special:
3891 3854
3892 3855 ``BODYFILE``
3893 3856 The content of the file defined as the value to this argument will be
3894 3857 transferred verbatim as the HTTP request body.
3895 3858
3896 3859 ``frame <type> <flags> <payload>``
3897 3860 Send a unified protocol frame as part of the request body.
3898 3861
3899 3862 All frames will be collected and sent as the body to the HTTP
3900 3863 request.
3901 3864
3902 3865 close
3903 3866 -----
3904 3867
3905 3868 Close the connection to the server.
3906 3869
3907 3870 flush
3908 3871 -----
3909 3872
3910 3873 Flush data written to the server.
3911 3874
3912 3875 readavailable
3913 3876 -------------
3914 3877
3915 3878 Close the write end of the connection and read all available data from
3916 3879 the server.
3917 3880
3918 3881 If the connection to the server encompasses multiple pipes, we poll both
3919 3882 pipes and read available data.
3920 3883
3921 3884 readline
3922 3885 --------
3923 3886
3924 3887 Read a line of output from the server. If there are multiple output
3925 3888 pipes, reads only the main pipe.
3926 3889
3927 3890 ereadline
3928 3891 ---------
3929 3892
3930 3893 Like ``readline``, but read from the stderr pipe, if available.
3931 3894
3932 3895 read <X>
3933 3896 --------
3934 3897
3935 3898 ``read()`` N bytes from the server's main output pipe.
3936 3899
3937 3900 eread <X>
3938 3901 ---------
3939 3902
3940 3903 ``read()`` N bytes from the server's stderr pipe, if available.
3941 3904
3942 3905 Specifying Unified Frame-Based Protocol Frames
3943 3906 ----------------------------------------------
3944 3907
3945 3908 It is possible to emit a *Unified Frame-Based Protocol* by using special
3946 3909 syntax.
3947 3910
3948 3911 A frame is composed as a type, flags, and payload. These can be parsed
3949 3912 from a string of the form:
3950 3913
3951 3914 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
3952 3915
3953 3916 ``request-id`` and ``stream-id`` are integers defining the request and
3954 3917 stream identifiers.
3955 3918
3956 3919 ``type`` can be an integer value for the frame type or the string name
3957 3920 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
3958 3921 ``command-name``.
3959 3922
3960 3923 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
3961 3924 components. Each component (and there can be just one) can be an integer
3962 3925 or a flag name for stream flags or frame flags, respectively. Values are
3963 3926 resolved to integers and then bitwise OR'd together.
3964 3927
3965 3928 ``payload`` represents the raw frame payload. If it begins with
3966 3929 ``cbor:``, the following string is evaluated as Python code and the
3967 3930 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
3968 3931 as a Python byte string literal.
3969 3932 """
3970 3933 opts = pycompat.byteskwargs(opts)
3971 3934
3972 3935 if opts[b'localssh'] and not repo:
3973 3936 raise error.Abort(_(b'--localssh requires a repository'))
3974 3937
3975 3938 if opts[b'peer'] and opts[b'peer'] not in (
3976 3939 b'raw',
3977 3940 b'http2',
3978 3941 b'ssh1',
3979 3942 b'ssh2',
3980 3943 ):
3981 3944 raise error.Abort(
3982 3945 _(b'invalid value for --peer'),
3983 3946 hint=_(b'valid values are "raw", "ssh1", and "ssh2"'),
3984 3947 )
3985 3948
3986 3949 if path and opts[b'localssh']:
3987 3950 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
3988 3951
3989 3952 if ui.interactive():
3990 3953 ui.write(_(b'(waiting for commands on stdin)\n'))
3991 3954
3992 3955 blocks = list(_parsewirelangblocks(ui.fin))
3993 3956
3994 3957 proc = None
3995 3958 stdin = None
3996 3959 stdout = None
3997 3960 stderr = None
3998 3961 opener = None
3999 3962
4000 3963 if opts[b'localssh']:
4001 3964 # We start the SSH server in its own process so there is process
4002 3965 # separation. This prevents a whole class of potential bugs around
4003 3966 # shared state from interfering with server operation.
4004 3967 args = procutil.hgcmd() + [
4005 3968 b'-R',
4006 3969 repo.root,
4007 3970 b'debugserve',
4008 3971 b'--sshstdio',
4009 3972 ]
4010 3973 proc = subprocess.Popen(
4011 3974 pycompat.rapply(procutil.tonativestr, args),
4012 3975 stdin=subprocess.PIPE,
4013 3976 stdout=subprocess.PIPE,
4014 3977 stderr=subprocess.PIPE,
4015 3978 bufsize=0,
4016 3979 )
4017 3980
4018 3981 stdin = proc.stdin
4019 3982 stdout = proc.stdout
4020 3983 stderr = proc.stderr
4021 3984
4022 3985 # We turn the pipes into observers so we can log I/O.
4023 3986 if ui.verbose or opts[b'peer'] == b'raw':
4024 3987 stdin = util.makeloggingfileobject(
4025 3988 ui, proc.stdin, b'i', logdata=True
4026 3989 )
4027 3990 stdout = util.makeloggingfileobject(
4028 3991 ui, proc.stdout, b'o', logdata=True
4029 3992 )
4030 3993 stderr = util.makeloggingfileobject(
4031 3994 ui, proc.stderr, b'e', logdata=True
4032 3995 )
4033 3996
4034 3997 # --localssh also implies the peer connection settings.
4035 3998
4036 3999 url = b'ssh://localserver'
4037 4000 autoreadstderr = not opts[b'noreadstderr']
4038 4001
4039 4002 if opts[b'peer'] == b'ssh1':
4040 4003 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4041 4004 peer = sshpeer.sshv1peer(
4042 4005 ui,
4043 4006 url,
4044 4007 proc,
4045 4008 stdin,
4046 4009 stdout,
4047 4010 stderr,
4048 4011 None,
4049 4012 autoreadstderr=autoreadstderr,
4050 4013 )
4051 4014 elif opts[b'peer'] == b'ssh2':
4052 4015 ui.write(_(b'creating ssh peer for wire protocol version 2\n'))
4053 4016 peer = sshpeer.sshv2peer(
4054 4017 ui,
4055 4018 url,
4056 4019 proc,
4057 4020 stdin,
4058 4021 stdout,
4059 4022 stderr,
4060 4023 None,
4061 4024 autoreadstderr=autoreadstderr,
4062 4025 )
4063 4026 elif opts[b'peer'] == b'raw':
4064 4027 ui.write(_(b'using raw connection to peer\n'))
4065 4028 peer = None
4066 4029 else:
4067 4030 ui.write(_(b'creating ssh peer from handshake results\n'))
4068 4031 peer = sshpeer.makepeer(
4069 4032 ui,
4070 4033 url,
4071 4034 proc,
4072 4035 stdin,
4073 4036 stdout,
4074 4037 stderr,
4075 4038 autoreadstderr=autoreadstderr,
4076 4039 )
4077 4040
4078 4041 elif path:
4079 4042 # We bypass hg.peer() so we can proxy the sockets.
4080 4043 # TODO consider not doing this because we skip
4081 4044 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4082 4045 u = util.url(path)
4083 4046 if u.scheme != b'http':
4084 4047 raise error.Abort(_(b'only http:// paths are currently supported'))
4085 4048
4086 4049 url, authinfo = u.authinfo()
4087 4050 openerargs = {
4088 4051 'useragent': b'Mercurial debugwireproto',
4089 4052 }
4090 4053
4091 4054 # Turn pipes/sockets into observers so we can log I/O.
4092 4055 if ui.verbose:
4093 4056 openerargs.update(
4094 4057 {
4095 4058 'loggingfh': ui,
4096 4059 'loggingname': b's',
4097 4060 'loggingopts': {'logdata': True, 'logdataapis': False,},
4098 4061 }
4099 4062 )
4100 4063
4101 4064 if ui.debugflag:
4102 4065 openerargs['loggingopts']['logdataapis'] = True
4103 4066
4104 4067 # Don't send default headers when in raw mode. This allows us to
4105 4068 # bypass most of the behavior of our URL handling code so we can
4106 4069 # have near complete control over what's sent on the wire.
4107 4070 if opts[b'peer'] == b'raw':
4108 4071 openerargs['sendaccept'] = False
4109 4072
4110 4073 opener = urlmod.opener(ui, authinfo, **openerargs)
4111 4074
4112 4075 if opts[b'peer'] == b'http2':
4113 4076 ui.write(_(b'creating http peer for wire protocol version 2\n'))
4114 4077 # We go through makepeer() because we need an API descriptor for
4115 4078 # the peer instance to be useful.
4116 4079 with ui.configoverride(
4117 4080 {(b'experimental', b'httppeer.advertise-v2'): True}
4118 4081 ):
4119 4082 if opts[b'nologhandshake']:
4120 4083 ui.pushbuffer()
4121 4084
4122 4085 peer = httppeer.makepeer(ui, path, opener=opener)
4123 4086
4124 4087 if opts[b'nologhandshake']:
4125 4088 ui.popbuffer()
4126 4089
4127 4090 if not isinstance(peer, httppeer.httpv2peer):
4128 4091 raise error.Abort(
4129 4092 _(
4130 4093 b'could not instantiate HTTP peer for '
4131 4094 b'wire protocol version 2'
4132 4095 ),
4133 4096 hint=_(
4134 4097 b'the server may not have the feature '
4135 4098 b'enabled or is not allowing this '
4136 4099 b'client version'
4137 4100 ),
4138 4101 )
4139 4102
4140 4103 elif opts[b'peer'] == b'raw':
4141 4104 ui.write(_(b'using raw connection to peer\n'))
4142 4105 peer = None
4143 4106 elif opts[b'peer']:
4144 4107 raise error.Abort(
4145 4108 _(b'--peer %s not supported with HTTP peers') % opts[b'peer']
4146 4109 )
4147 4110 else:
4148 4111 peer = httppeer.makepeer(ui, path, opener=opener)
4149 4112
4150 4113 # We /could/ populate stdin/stdout with sock.makefile()...
4151 4114 else:
4152 4115 raise error.Abort(_(b'unsupported connection configuration'))
4153 4116
4154 4117 batchedcommands = None
4155 4118
4156 4119 # Now perform actions based on the parsed wire language instructions.
4157 4120 for action, lines in blocks:
4158 4121 if action in (b'raw', b'raw+'):
4159 4122 if not stdin:
4160 4123 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4161 4124
4162 4125 # Concatenate the data together.
4163 4126 data = b''.join(l.lstrip() for l in lines)
4164 4127 data = stringutil.unescapestr(data)
4165 4128 stdin.write(data)
4166 4129
4167 4130 if action == b'raw+':
4168 4131 stdin.flush()
4169 4132 elif action == b'flush':
4170 4133 if not stdin:
4171 4134 raise error.Abort(_(b'cannot call flush on this peer'))
4172 4135 stdin.flush()
4173 4136 elif action.startswith(b'command'):
4174 4137 if not peer:
4175 4138 raise error.Abort(
4176 4139 _(
4177 4140 b'cannot send commands unless peer instance '
4178 4141 b'is available'
4179 4142 )
4180 4143 )
4181 4144
4182 4145 command = action.split(b' ', 1)[1]
4183 4146
4184 4147 args = {}
4185 4148 for line in lines:
4186 4149 # We need to allow empty values.
4187 4150 fields = line.lstrip().split(b' ', 1)
4188 4151 if len(fields) == 1:
4189 4152 key = fields[0]
4190 4153 value = b''
4191 4154 else:
4192 4155 key, value = fields
4193 4156
4194 4157 if value.startswith(b'eval:'):
4195 4158 value = stringutil.evalpythonliteral(value[5:])
4196 4159 else:
4197 4160 value = stringutil.unescapestr(value)
4198 4161
4199 4162 args[key] = value
4200 4163
4201 4164 if batchedcommands is not None:
4202 4165 batchedcommands.append((command, args))
4203 4166 continue
4204 4167
4205 4168 ui.status(_(b'sending %s command\n') % command)
4206 4169
4207 4170 if b'PUSHFILE' in args:
4208 4171 with open(args[b'PUSHFILE'], 'rb') as fh:
4209 4172 del args[b'PUSHFILE']
4210 4173 res, output = peer._callpush(
4211 4174 command, fh, **pycompat.strkwargs(args)
4212 4175 )
4213 4176 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4214 4177 ui.status(
4215 4178 _(b'remote output: %s\n') % stringutil.escapestr(output)
4216 4179 )
4217 4180 else:
4218 4181 with peer.commandexecutor() as e:
4219 4182 res = e.callcommand(command, args).result()
4220 4183
4221 4184 if isinstance(res, wireprotov2peer.commandresponse):
4222 4185 val = res.objects()
4223 4186 ui.status(
4224 4187 _(b'response: %s\n')
4225 4188 % stringutil.pprint(val, bprefix=True, indent=2)
4226 4189 )
4227 4190 else:
4228 4191 ui.status(
4229 4192 _(b'response: %s\n')
4230 4193 % stringutil.pprint(res, bprefix=True, indent=2)
4231 4194 )
4232 4195
4233 4196 elif action == b'batchbegin':
4234 4197 if batchedcommands is not None:
4235 4198 raise error.Abort(_(b'nested batchbegin not allowed'))
4236 4199
4237 4200 batchedcommands = []
4238 4201 elif action == b'batchsubmit':
4239 4202 # There is a batching API we could go through. But it would be
4240 4203 # difficult to normalize requests into function calls. It is easier
4241 4204 # to bypass this layer and normalize to commands + args.
4242 4205 ui.status(
4243 4206 _(b'sending batch with %d sub-commands\n')
4244 4207 % len(batchedcommands)
4245 4208 )
4246 4209 assert peer is not None
4247 4210 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4248 4211 ui.status(
4249 4212 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4250 4213 )
4251 4214
4252 4215 batchedcommands = None
4253 4216
4254 4217 elif action.startswith(b'httprequest '):
4255 4218 if not opener:
4256 4219 raise error.Abort(
4257 4220 _(b'cannot use httprequest without an HTTP peer')
4258 4221 )
4259 4222
4260 4223 request = action.split(b' ', 2)
4261 4224 if len(request) != 3:
4262 4225 raise error.Abort(
4263 4226 _(
4264 4227 b'invalid httprequest: expected format is '
4265 4228 b'"httprequest <method> <path>'
4266 4229 )
4267 4230 )
4268 4231
4269 4232 method, httppath = request[1:]
4270 4233 headers = {}
4271 4234 body = None
4272 4235 frames = []
4273 4236 for line in lines:
4274 4237 line = line.lstrip()
4275 4238 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4276 4239 if m:
4277 4240 # Headers need to use native strings.
4278 4241 key = pycompat.strurl(m.group(1))
4279 4242 value = pycompat.strurl(m.group(2))
4280 4243 headers[key] = value
4281 4244 continue
4282 4245
4283 4246 if line.startswith(b'BODYFILE '):
4284 4247 with open(line.split(b' ', 1), b'rb') as fh:
4285 4248 body = fh.read()
4286 4249 elif line.startswith(b'frame '):
4287 4250 frame = wireprotoframing.makeframefromhumanstring(
4288 4251 line[len(b'frame ') :]
4289 4252 )
4290 4253
4291 4254 frames.append(frame)
4292 4255 else:
4293 4256 raise error.Abort(
4294 4257 _(b'unknown argument to httprequest: %s') % line
4295 4258 )
4296 4259
4297 4260 url = path + httppath
4298 4261
4299 4262 if frames:
4300 4263 body = b''.join(bytes(f) for f in frames)
4301 4264
4302 4265 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4303 4266
4304 4267 # urllib.Request insists on using has_data() as a proxy for
4305 4268 # determining the request method. Override that to use our
4306 4269 # explicitly requested method.
4307 4270 req.get_method = lambda: pycompat.sysstr(method)
4308 4271
4309 4272 try:
4310 4273 res = opener.open(req)
4311 4274 body = res.read()
4312 4275 except util.urlerr.urlerror as e:
4313 4276 # read() method must be called, but only exists in Python 2
4314 4277 getattr(e, 'read', lambda: None)()
4315 4278 continue
4316 4279
4317 4280 ct = res.headers.get('Content-Type')
4318 4281 if ct == 'application/mercurial-cbor':
4319 4282 ui.write(
4320 4283 _(b'cbor> %s\n')
4321 4284 % stringutil.pprint(
4322 4285 cborutil.decodeall(body), bprefix=True, indent=2
4323 4286 )
4324 4287 )
4325 4288
4326 4289 elif action == b'close':
4327 4290 assert peer is not None
4328 4291 peer.close()
4329 4292 elif action == b'readavailable':
4330 4293 if not stdout or not stderr:
4331 4294 raise error.Abort(
4332 4295 _(b'readavailable not available on this peer')
4333 4296 )
4334 4297
4335 4298 stdin.close()
4336 4299 stdout.read()
4337 4300 stderr.read()
4338 4301
4339 4302 elif action == b'readline':
4340 4303 if not stdout:
4341 4304 raise error.Abort(_(b'readline not available on this peer'))
4342 4305 stdout.readline()
4343 4306 elif action == b'ereadline':
4344 4307 if not stderr:
4345 4308 raise error.Abort(_(b'ereadline not available on this peer'))
4346 4309 stderr.readline()
4347 4310 elif action.startswith(b'read '):
4348 4311 count = int(action.split(b' ', 1)[1])
4349 4312 if not stdout:
4350 4313 raise error.Abort(_(b'read not available on this peer'))
4351 4314 stdout.read(count)
4352 4315 elif action.startswith(b'eread '):
4353 4316 count = int(action.split(b' ', 1)[1])
4354 4317 if not stderr:
4355 4318 raise error.Abort(_(b'eread not available on this peer'))
4356 4319 stderr.read(count)
4357 4320 else:
4358 4321 raise error.Abort(_(b'unknown action: %s') % action)
4359 4322
4360 4323 if batchedcommands is not None:
4361 4324 raise error.Abort(_(b'unclosed "batchbegin" request'))
4362 4325
4363 4326 if peer:
4364 4327 peer.close()
4365 4328
4366 4329 if proc:
4367 4330 proc.kill()
@@ -1,39 +1,45 b''
1 1 == New Features ==
2 2
3 3 * `hg purge`/`hg clean` can now delete ignored files instead of
4 4 untracked files, with the new -i flag.
5 5
6 6 * `hg log` now defaults to using an '%' symbol for commits involved
7 7 in unresolved merge conflicts. That includes unresolved conflicts
8 8 caused by e.g. `hg update --merge` and `hg graft`. '@' still takes
9 9 precedence, so what used to be marked '@' still is.
10 10
11 11 * New `conflictlocal()` and `conflictother()` revsets return the
12 12 commits that are being merged, when there are conflicts. Also works
13 13 for conflicts caused by e.g. `hg graft`.
14 14
15 * `hg debugmergestate` output is now templated, which may be useful
16 e.g. for IDEs that want to help the user resolve merge conflicts.
17
15 18
16 19 == New Experimental Features ==
17 20
18 21
19 22 == Bug Fixes ==
20 23
21 24
22 25 == Backwards Compatibility Changes ==
23 26
24 27 * When `hg rebase` pauses for merge conflict resolution, the working
25 28 copy will no longer have the rebased node as a second parent. You
26 29 can use the new `conflictparents()` revset for finding the other
27 30 parent during a conflict.
28 31
32 * `hg debugmergestate` output format changed. Let us know if that is
33 causing you problems and we'll roll it back.
34
29 35
30 36 == Internal API Changes ==
31 37
32 38 * The deprecated `ui.progress()` has now been deleted. Please use
33 39 `ui.makeprogress()` instead.
34 40
35 41 * `hg.merge()` has lost its `abort` argument. Please call
36 42 `hg.abortmerge()` directly instead.
37 43
38 44 * The `*others` argument of `cmdutil.check_incompatible_arguments()`
39 45 changed from being varargs argument to being a single collection.
@@ -1,807 +1,806 b''
1 1 $ hg init basic
2 2 $ cd basic
3 3
4 4 should complain
5 5
6 6 $ hg backout
7 7 abort: please specify a revision to backout
8 8 [255]
9 9 $ hg backout -r 0 0
10 10 abort: please specify just one revision
11 11 [255]
12 12
13 13 basic operation
14 14 (this also tests that editor is invoked if the commit message is not
15 15 specified explicitly)
16 16
17 17 $ echo a > a
18 18 $ hg commit -d '0 0' -A -m a
19 19 adding a
20 20 $ echo b >> a
21 21 $ hg commit -d '1 0' -m b
22 22
23 23 $ hg status --rev tip --rev "tip^1"
24 24 M a
25 25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
26 26 reverting a
27 27 Backed out changeset a820f4f40a57
28 28
29 29
30 30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
31 31 HG: Leave message empty to abort commit.
32 32 HG: --
33 33 HG: user: test
34 34 HG: branch 'default'
35 35 HG: changed a
36 36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
37 37 $ cat a
38 38 a
39 39 $ hg summary
40 40 parent: 2:2929462c3dff tip
41 41 Backed out changeset a820f4f40a57
42 42 branch: default
43 43 commit: (clean)
44 44 update: (current)
45 45 phases: 3 draft
46 46
47 47 commit option
48 48
49 49 $ cd ..
50 50 $ hg init commit
51 51 $ cd commit
52 52
53 53 $ echo tomatoes > a
54 54 $ hg add a
55 55 $ hg commit -d '0 0' -m tomatoes
56 56
57 57 $ echo chair > b
58 58 $ hg add b
59 59 $ hg commit -d '1 0' -m chair
60 60
61 61 $ echo grapes >> a
62 62 $ hg commit -d '2 0' -m grapes
63 63
64 64 $ hg backout -d '4 0' 1 --tool=:fail
65 65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
67 67 $ hg summary
68 68 parent: 3:1c2161e97c0a tip
69 69 Backed out changeset 22cb4f70d813
70 70 branch: default
71 71 commit: (clean)
72 72 update: (current)
73 73 phases: 4 draft
74 74
75 75 $ echo ypples > a
76 76 $ hg commit -d '5 0' -m ypples
77 77
78 78 $ hg backout -d '6 0' 2 --tool=:fail
79 79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 80 use 'hg resolve' to retry unresolved file merges
81 81 [1]
82 82 $ hg summary
83 83 parent: 4:ed99997b793d tip
84 84 ypples
85 85 branch: default
86 86 commit: 1 unresolved (clean)
87 87 update: (current)
88 88 phases: 5 draft
89 89 $ hg log -G
90 90 @ changeset: 4:ed99997b793d
91 91 | tag: tip
92 92 | user: test
93 93 | date: Thu Jan 01 00:00:05 1970 +0000
94 94 | summary: ypples
95 95 |
96 96 o changeset: 3:1c2161e97c0a
97 97 | user: test
98 98 | date: Thu Jan 01 00:00:04 1970 +0000
99 99 | summary: Backed out changeset 22cb4f70d813
100 100 |
101 101 o changeset: 2:a8c6e511cfee
102 102 | user: test
103 103 | date: Thu Jan 01 00:00:02 1970 +0000
104 104 | summary: grapes
105 105 |
106 106 % changeset: 1:22cb4f70d813
107 107 | user: test
108 108 | date: Thu Jan 01 00:00:01 1970 +0000
109 109 | summary: chair
110 110 |
111 111 o changeset: 0:a5cb2dde5805
112 112 user: test
113 113 date: Thu Jan 01 00:00:00 1970 +0000
114 114 summary: tomatoes
115 115
116 116
117 117 file that was removed is recreated
118 118 (this also tests that editor is not invoked if the commit message is
119 119 specified explicitly)
120 120
121 121 $ cd ..
122 122 $ hg init remove
123 123 $ cd remove
124 124
125 125 $ echo content > a
126 126 $ hg commit -d '0 0' -A -m a
127 127 adding a
128 128
129 129 $ hg rm a
130 130 $ hg commit -d '1 0' -m b
131 131
132 132 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
133 133 adding a
134 134 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
135 135 $ cat a
136 136 content
137 137 $ hg summary
138 138 parent: 2:de31bdc76c0d tip
139 139 Backed out changeset 76862dcce372
140 140 branch: default
141 141 commit: (clean)
142 142 update: (current)
143 143 phases: 3 draft
144 144
145 145 backout of backout is as if nothing happened
146 146
147 147 $ hg backout -d '3 0' --merge tip --tool=true
148 148 removing a
149 149 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
150 150 $ test -f a
151 151 [1]
152 152 $ hg summary
153 153 parent: 3:7f6d0f120113 tip
154 154 Backed out changeset de31bdc76c0d
155 155 branch: default
156 156 commit: (clean)
157 157 update: (current)
158 158 phases: 4 draft
159 159
160 160 Test that 'hg rollback' restores dirstate just before opening
161 161 transaction: in-memory dirstate changes should be written into
162 162 '.hg/journal.dirstate' as expected.
163 163
164 164 $ echo 'removed soon' > b
165 165 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
166 166 adding b
167 167 $ echo 'newly added' > c
168 168 $ hg add c
169 169 $ hg remove b
170 170 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
171 171 $ touch -t 200001010000 c
172 172 $ hg status -A
173 173 C c
174 174 $ hg debugstate --no-dates
175 175 n 644 12 set c
176 176 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
177 177 removing c
178 178 adding b
179 179 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
180 180 $ hg rollback -q
181 181 $ hg status -A
182 182 A b
183 183 R c
184 184 $ hg debugstate --no-dates
185 185 a 0 -1 unset b
186 186 r 0 0 set c
187 187
188 188 across branch
189 189
190 190 $ cd ..
191 191 $ hg init branch
192 192 $ cd branch
193 193 $ echo a > a
194 194 $ hg ci -Am0
195 195 adding a
196 196 $ echo b > b
197 197 $ hg ci -Am1
198 198 adding b
199 199 $ hg co -C 0
200 200 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
201 201 $ hg summary
202 202 parent: 0:f7b1eb17ad24
203 203 0
204 204 branch: default
205 205 commit: (clean)
206 206 update: 1 new changesets (update)
207 207 phases: 2 draft
208 208
209 209 should fail
210 210
211 211 $ hg backout 1
212 212 abort: cannot backout change that is not an ancestor
213 213 [255]
214 214 $ echo c > c
215 215 $ hg ci -Am2
216 216 adding c
217 217 created new head
218 218 $ hg summary
219 219 parent: 2:db815d6d32e6 tip
220 220 2
221 221 branch: default
222 222 commit: (clean)
223 223 update: 1 new changesets, 2 branch heads (merge)
224 224 phases: 3 draft
225 225
226 226 should fail
227 227
228 228 $ hg backout 1
229 229 abort: cannot backout change that is not an ancestor
230 230 [255]
231 231 $ hg summary
232 232 parent: 2:db815d6d32e6 tip
233 233 2
234 234 branch: default
235 235 commit: (clean)
236 236 update: 1 new changesets, 2 branch heads (merge)
237 237 phases: 3 draft
238 238
239 239 backout with merge
240 240
241 241 $ cd ..
242 242 $ hg init merge
243 243 $ cd merge
244 244
245 245 $ echo line 1 > a
246 246 $ echo line 2 >> a
247 247 $ hg commit -d '0 0' -A -m a
248 248 adding a
249 249 $ hg summary
250 250 parent: 0:59395513a13a tip
251 251 a
252 252 branch: default
253 253 commit: (clean)
254 254 update: (current)
255 255 phases: 1 draft
256 256
257 257 remove line 1
258 258
259 259 $ echo line 2 > a
260 260 $ hg commit -d '1 0' -m b
261 261
262 262 $ echo line 3 >> a
263 263 $ hg commit -d '2 0' -m c
264 264
265 265 $ hg backout --merge -d '3 0' 1 --tool=true
266 266 reverting a
267 267 created new head
268 268 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
269 269 merging with changeset 3:26b8ccb9ad91
270 270 merging a
271 271 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
272 272 (branch merge, don't forget to commit)
273 273 $ hg commit -d '4 0' -m d
274 274 $ hg summary
275 275 parent: 4:c7df5e0b9c09 tip
276 276 d
277 277 branch: default
278 278 commit: (clean)
279 279 update: (current)
280 280 phases: 5 draft
281 281
282 282 check line 1 is back
283 283
284 284 $ cat a
285 285 line 1
286 286 line 2
287 287 line 3
288 288
289 289 Test visibility of in-memory dirstate changes outside transaction to
290 290 external hook process
291 291
292 292 $ cat > $TESTTMP/checkvisibility.sh <<EOF
293 293 > echo "==== \$1:"
294 294 > hg parents --template "{rev}:{node|short}\n"
295 295 > echo "===="
296 296 > EOF
297 297
298 298 "hg backout --merge REV1" at REV2 below implies steps below:
299 299
300 300 (1) update to REV1 (REV2 => REV1)
301 301 (2) revert by REV1^1
302 302 (3) commit backing out revision (REV3)
303 303 (4) update to REV2 (REV3 => REV2)
304 304 (5) merge with REV3 (REV2 => REV2, REV3)
305 305
306 306 == test visibility to external preupdate hook
307 307
308 308 $ hg update -q -C 2
309 309 $ hg --config extensions.strip= strip 3
310 310 saved backup bundle to * (glob)
311 311
312 312 $ cat >> .hg/hgrc <<EOF
313 313 > [hooks]
314 314 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
315 315 > EOF
316 316
317 317 ("-m" is needed to avoid writing dirstate changes out at other than
318 318 invocation of the hook to be examined)
319 319
320 320 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
321 321 ==== preupdate:
322 322 2:6ea3f2a197a2
323 323 ====
324 324 reverting a
325 325 created new head
326 326 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
327 327 ==== preupdate:
328 328 3:d92a3f57f067
329 329 ====
330 330 merging with changeset 3:d92a3f57f067
331 331 ==== preupdate:
332 332 2:6ea3f2a197a2
333 333 ====
334 334 merging a
335 335 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
336 336 (branch merge, don't forget to commit)
337 337
338 338 $ cat >> .hg/hgrc <<EOF
339 339 > [hooks]
340 340 > preupdate.visibility =
341 341 > EOF
342 342
343 343 == test visibility to external update hook
344 344
345 345 $ hg update -q -C 2
346 346 $ hg --config extensions.strip= strip 3
347 347 saved backup bundle to * (glob)
348 348
349 349 $ cat >> .hg/hgrc <<EOF
350 350 > [hooks]
351 351 > update.visibility = sh $TESTTMP/checkvisibility.sh update
352 352 > EOF
353 353
354 354 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
355 355 ==== update:
356 356 1:5a50a024c182
357 357 ====
358 358 reverting a
359 359 created new head
360 360 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
361 361 ==== update:
362 362 2:6ea3f2a197a2
363 363 ====
364 364 merging with changeset 3:d92a3f57f067
365 365 merging a
366 366 ==== update:
367 367 2:6ea3f2a197a2
368 368 3:d92a3f57f067
369 369 ====
370 370 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
371 371 (branch merge, don't forget to commit)
372 372
373 373 $ cat >> .hg/hgrc <<EOF
374 374 > [hooks]
375 375 > update.visibility =
376 376 > EOF
377 377
378 378 $ cd ..
379 379
380 380 backout should not back out subsequent changesets
381 381
382 382 $ hg init onecs
383 383 $ cd onecs
384 384 $ echo 1 > a
385 385 $ hg commit -d '0 0' -A -m a
386 386 adding a
387 387 $ echo 2 >> a
388 388 $ hg commit -d '1 0' -m b
389 389 $ echo 1 > b
390 390 $ hg commit -d '2 0' -A -m c
391 391 adding b
392 392 $ hg summary
393 393 parent: 2:882396649954 tip
394 394 c
395 395 branch: default
396 396 commit: (clean)
397 397 update: (current)
398 398 phases: 3 draft
399 399
400 400 without --merge
401 401 $ hg backout --no-commit -d '3 0' 1 --tool=true
402 402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 403 changeset 22bca4c721e5 backed out, don't forget to commit.
404 404 $ hg locate b
405 405 b
406 406 $ hg update -C tip
407 407 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
408 408 $ hg locate b
409 409 b
410 410 $ hg summary
411 411 parent: 2:882396649954 tip
412 412 c
413 413 branch: default
414 414 commit: (clean)
415 415 update: (current)
416 416 phases: 3 draft
417 417
418 418 with --merge
419 419 $ hg backout --merge -d '3 0' 1 --tool=true
420 420 reverting a
421 421 created new head
422 422 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
423 423 merging with changeset 3:3202beb76721
424 424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 425 (branch merge, don't forget to commit)
426 426 $ hg locate b
427 427 b
428 428 $ hg update -C tip
429 429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
430 430 $ hg locate b
431 431 [1]
432 432
433 433 $ cd ..
434 434 $ hg init m
435 435 $ cd m
436 436 $ echo a > a
437 437 $ hg commit -d '0 0' -A -m a
438 438 adding a
439 439 $ echo b > b
440 440 $ hg commit -d '1 0' -A -m b
441 441 adding b
442 442 $ echo c > c
443 443 $ hg commit -d '2 0' -A -m b
444 444 adding c
445 445 $ hg update 1
446 446 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
447 447 $ echo d > d
448 448 $ hg commit -d '3 0' -A -m c
449 449 adding d
450 450 created new head
451 451 $ hg merge 2
452 452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 453 (branch merge, don't forget to commit)
454 454 $ hg commit -d '4 0' -A -m d
455 455 $ hg summary
456 456 parent: 4:b2f3bb92043e tip
457 457 d
458 458 branch: default
459 459 commit: (clean)
460 460 update: (current)
461 461 phases: 5 draft
462 462
463 463 backout of merge should fail
464 464
465 465 $ hg backout 4
466 466 abort: cannot backout a merge changeset
467 467 [255]
468 468
469 469 backout of merge with bad parent should fail
470 470
471 471 $ hg backout --parent 0 4
472 472 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
473 473 [255]
474 474
475 475 backout of non-merge with parent should fail
476 476
477 477 $ hg backout --parent 0 3
478 478 abort: cannot use --parent on non-merge changeset
479 479 [255]
480 480
481 481 backout with valid parent should be ok
482 482
483 483 $ hg backout -d '5 0' --parent 2 4 --tool=true
484 484 removing d
485 485 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
486 486 $ hg summary
487 487 parent: 5:10e5328c8435 tip
488 488 Backed out changeset b2f3bb92043e
489 489 branch: default
490 490 commit: (clean)
491 491 update: (current)
492 492 phases: 6 draft
493 493
494 494 $ hg rollback
495 495 repository tip rolled back to revision 4 (undo commit)
496 496 working directory now based on revision 4
497 497 $ hg update -C
498 498 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 499 $ hg summary
500 500 parent: 4:b2f3bb92043e tip
501 501 d
502 502 branch: default
503 503 commit: (clean)
504 504 update: (current)
505 505 phases: 5 draft
506 506
507 507 $ hg backout -d '6 0' --parent 3 4 --tool=true
508 508 removing c
509 509 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
510 510 $ hg summary
511 511 parent: 5:033590168430 tip
512 512 Backed out changeset b2f3bb92043e
513 513 branch: default
514 514 commit: (clean)
515 515 update: (current)
516 516 phases: 6 draft
517 517
518 518 $ cd ..
519 519
520 520 named branches
521 521
522 522 $ hg init named_branches
523 523 $ cd named_branches
524 524
525 525 $ echo default > default
526 526 $ hg ci -d '0 0' -Am default
527 527 adding default
528 528 $ hg branch branch1
529 529 marked working directory as branch branch1
530 530 (branches are permanent and global, did you want a bookmark?)
531 531 $ echo branch1 > file1
532 532 $ hg ci -d '1 0' -Am file1
533 533 adding file1
534 534 $ hg branch branch2
535 535 marked working directory as branch branch2
536 536 $ echo branch2 > file2
537 537 $ hg ci -d '2 0' -Am file2
538 538 adding file2
539 539
540 540 without --merge
541 541 $ hg backout --no-commit -r 1 --tool=true
542 542 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
543 543 changeset bf1602f437f3 backed out, don't forget to commit.
544 544 $ hg branch
545 545 branch2
546 546 $ hg status -A
547 547 R file1
548 548 C default
549 549 C file2
550 550 $ hg summary
551 551 parent: 2:45bbcd363bf0 tip
552 552 file2
553 553 branch: branch2
554 554 commit: 1 removed
555 555 update: (current)
556 556 phases: 3 draft
557 557
558 558 with --merge
559 559 (this also tests that editor is invoked if '--edit' is specified
560 560 explicitly regardless of '--message')
561 561
562 562 $ hg update -qC
563 563 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
564 564 removing file1
565 565 backout on branch1
566 566
567 567
568 568 HG: Enter commit message. Lines beginning with 'HG:' are removed.
569 569 HG: Leave message empty to abort commit.
570 570 HG: --
571 571 HG: user: test
572 572 HG: branch 'branch2'
573 573 HG: removed file1
574 574 created new head
575 575 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
576 576 merging with changeset 3:d4e8f6db59fb
577 577 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
578 578 (branch merge, don't forget to commit)
579 579 $ hg summary
580 580 parent: 2:45bbcd363bf0
581 581 file2
582 582 parent: 3:d4e8f6db59fb tip
583 583 backout on branch1
584 584 branch: branch2
585 585 commit: 1 removed (merge)
586 586 update: (current)
587 587 phases: 4 draft
588 588 $ hg update -q -C 2
589 589
590 590 on branch2 with branch1 not merged, so file1 should still exist:
591 591
592 592 $ hg id
593 593 45bbcd363bf0 (branch2)
594 594 $ hg st -A
595 595 C default
596 596 C file1
597 597 C file2
598 598 $ hg summary
599 599 parent: 2:45bbcd363bf0
600 600 file2
601 601 branch: branch2
602 602 commit: (clean)
603 603 update: 1 new changesets, 2 branch heads (merge)
604 604 phases: 4 draft
605 605
606 606 on branch2 with branch1 merged, so file1 should be gone:
607 607
608 608 $ hg merge
609 609 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
610 610 (branch merge, don't forget to commit)
611 611 $ hg ci -d '4 0' -m 'merge backout of branch1'
612 612 $ hg id
613 613 d97a8500a969 (branch2) tip
614 614 $ hg st -A
615 615 C default
616 616 C file2
617 617 $ hg summary
618 618 parent: 4:d97a8500a969 tip
619 619 merge backout of branch1
620 620 branch: branch2
621 621 commit: (clean)
622 622 update: (current)
623 623 phases: 5 draft
624 624
625 625 on branch1, so no file1 and file2:
626 626
627 627 $ hg co -C branch1
628 628 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
629 629 $ hg id
630 630 bf1602f437f3 (branch1)
631 631 $ hg st -A
632 632 C default
633 633 C file1
634 634 $ hg summary
635 635 parent: 1:bf1602f437f3
636 636 file1
637 637 branch: branch1
638 638 commit: (clean)
639 639 update: (current)
640 640 phases: 5 draft
641 641
642 642 $ cd ..
643 643
644 644 backout of empty changeset (issue4190)
645 645
646 646 $ hg init emptycommit
647 647 $ cd emptycommit
648 648
649 649 $ touch file1
650 650 $ hg ci -Aqm file1
651 651 $ hg branch -q branch1
652 652 $ hg ci -qm branch1
653 653 $ hg backout -v 1
654 654 resolving manifests
655 655 nothing changed
656 656 [1]
657 657
658 658 $ cd ..
659 659
660 660
661 661 Test usage of `hg resolve` in case of conflict
662 662 (issue4163)
663 663
664 664 $ hg init issue4163
665 665 $ cd issue4163
666 666 $ touch foo
667 667 $ hg add foo
668 668 $ cat > foo << EOF
669 669 > one
670 670 > two
671 671 > three
672 672 > four
673 673 > five
674 674 > six
675 675 > seven
676 676 > height
677 677 > nine
678 678 > ten
679 679 > EOF
680 680 $ hg ci -m 'initial'
681 681 $ cat > foo << EOF
682 682 > one
683 683 > two
684 684 > THREE
685 685 > four
686 686 > five
687 687 > six
688 688 > seven
689 689 > height
690 690 > nine
691 691 > ten
692 692 > EOF
693 693 $ hg ci -m 'capital three'
694 694 $ cat > foo << EOF
695 695 > one
696 696 > two
697 697 > THREE
698 698 > four
699 699 > five
700 700 > six
701 701 > seven
702 702 > height
703 703 > nine
704 704 > TEN
705 705 > EOF
706 706 $ hg ci -m 'capital ten'
707 707 $ hg backout -r 'desc("capital three")' --tool internal:fail
708 708 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
709 709 use 'hg resolve' to retry unresolved file merges
710 710 [1]
711 711 $ hg status
712 712 $ hg debugmergestate
713 * version 2 records
714 713 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
715 714 other: a30dd8addae3ce71b8667868478542bc417439e6
716 file extras: foo (ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553)
717 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
715 file: foo (state "u")
718 716 local path: foo (flags "")
719 717 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
720 718 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
719 extra: ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553
721 720 $ mv .hg/merge/state2 .hg/merge/state2-moved
722 721 $ hg debugmergestate
723 * version 1 records
724 722 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
725 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
723 other: b71750c4b0fdf719734971e3ef90dbeab5919a2d
724 file: foo (state "u")
726 725 local path: foo (flags "")
727 726 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
728 other path: foo (node not stored in v1 format)
727 other path: (node foo)
729 728 $ mv .hg/merge/state2-moved .hg/merge/state2
730 729 $ hg resolve -l # still unresolved
731 730 U foo
732 731 $ hg summary
733 732 parent: 2:b71750c4b0fd tip
734 733 capital ten
735 734 branch: default
736 735 commit: 1 unresolved (clean)
737 736 update: (current)
738 737 phases: 3 draft
739 738 $ hg log -G
740 739 @ changeset: 2:b71750c4b0fd
741 740 | tag: tip
742 741 | user: test
743 742 | date: Thu Jan 01 00:00:00 1970 +0000
744 743 | summary: capital ten
745 744 |
746 745 o changeset: 1:913609522437
747 746 | user: test
748 747 | date: Thu Jan 01 00:00:00 1970 +0000
749 748 | summary: capital three
750 749 |
751 750 % changeset: 0:a30dd8addae3
752 751 user: test
753 752 date: Thu Jan 01 00:00:00 1970 +0000
754 753 summary: initial
755 754
756 755 $ hg resolve --all --debug
757 756 picked tool ':merge' for foo (binary False symlink False changedelete False)
758 757 merging foo
759 758 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
760 759 premerge successful
761 760 (no more unresolved files)
762 761 continue: hg commit
763 762 $ hg status
764 763 M foo
765 764 ? foo.orig
766 765 $ hg resolve -l
767 766 R foo
768 767 $ hg summary
769 768 parent: 2:b71750c4b0fd tip
770 769 capital ten
771 770 branch: default
772 771 commit: 1 modified, 1 unknown
773 772 update: (current)
774 773 phases: 3 draft
775 774 $ cat foo
776 775 one
777 776 two
778 777 three
779 778 four
780 779 five
781 780 six
782 781 seven
783 782 height
784 783 nine
785 784 TEN
786 785
787 786 --no-commit shouldn't commit
788 787
789 788 $ hg init a
790 789 $ cd a
791 790 $ for i in 1 2 3; do
792 791 > touch $i
793 792 > hg ci -Am $i
794 793 > done
795 794 adding 1
796 795 adding 2
797 796 adding 3
798 797 $ hg backout --no-commit .
799 798 removing 3
800 799 changeset cccc23d9d68f backed out, don't forget to commit.
801 800 $ hg revert -aq
802 801
803 802 --no-commit can't be used with --merge
804 803
805 804 $ hg backout --merge --no-commit 2
806 805 abort: cannot use --merge with --no-commit
807 806 [255]
@@ -1,429 +1,429 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 abort
4 4 add
5 5 addremove
6 6 annotate
7 7 archive
8 8 backout
9 9 bisect
10 10 bookmarks
11 11 branch
12 12 branches
13 13 bundle
14 14 cat
15 15 clone
16 16 commit
17 17 config
18 18 continue
19 19 copy
20 20 diff
21 21 export
22 22 files
23 23 forget
24 24 graft
25 25 grep
26 26 heads
27 27 help
28 28 identify
29 29 import
30 30 incoming
31 31 init
32 32 locate
33 33 log
34 34 manifest
35 35 merge
36 36 outgoing
37 37 parents
38 38 paths
39 39 phase
40 40 pull
41 41 push
42 42 recover
43 43 remove
44 44 rename
45 45 resolve
46 46 revert
47 47 rollback
48 48 root
49 49 serve
50 50 shelve
51 51 status
52 52 summary
53 53 tag
54 54 tags
55 55 tip
56 56 unbundle
57 57 unshelve
58 58 update
59 59 verify
60 60 version
61 61
62 62 Show all commands that start with "a"
63 63 $ hg debugcomplete a
64 64 abort
65 65 add
66 66 addremove
67 67 annotate
68 68 archive
69 69
70 70 Do not show debug commands if there are other candidates
71 71 $ hg debugcomplete d
72 72 diff
73 73
74 74 Show debug commands if there are no other candidates
75 75 $ hg debugcomplete debug
76 76 debugancestor
77 77 debugapplystreamclonebundle
78 78 debugbuilddag
79 79 debugbundle
80 80 debugcapabilities
81 81 debugcheckstate
82 82 debugcolor
83 83 debugcommands
84 84 debugcomplete
85 85 debugconfig
86 86 debugcreatestreamclonebundle
87 87 debugdag
88 88 debugdata
89 89 debugdate
90 90 debugdeltachain
91 91 debugdirstate
92 92 debugdiscovery
93 93 debugdownload
94 94 debugextensions
95 95 debugfileset
96 96 debugformat
97 97 debugfsinfo
98 98 debuggetbundle
99 99 debugignore
100 100 debugindex
101 101 debugindexdot
102 102 debugindexstats
103 103 debuginstall
104 104 debugknown
105 105 debuglabelcomplete
106 106 debuglocks
107 107 debugmanifestfulltextcache
108 108 debugmergestate
109 109 debugnamecomplete
110 110 debugnodemap
111 111 debugobsolete
112 112 debugp1copies
113 113 debugp2copies
114 114 debugpathcomplete
115 115 debugpathcopies
116 116 debugpeer
117 117 debugpickmergetool
118 118 debugpushkey
119 119 debugpvec
120 120 debugrebuilddirstate
121 121 debugrebuildfncache
122 122 debugrename
123 123 debugrevlog
124 124 debugrevlogindex
125 125 debugrevspec
126 126 debugserve
127 127 debugsetparents
128 128 debugsidedata
129 129 debugssl
130 130 debugsub
131 131 debugsuccessorssets
132 132 debugtagscache
133 133 debugtemplate
134 134 debuguigetpass
135 135 debuguiprompt
136 136 debugupdatecaches
137 137 debugupgraderepo
138 138 debugwalk
139 139 debugwhyunstable
140 140 debugwireargs
141 141 debugwireproto
142 142
143 143 Do not show the alias of a debug command if there are other candidates
144 144 (this should hide rawcommit)
145 145 $ hg debugcomplete r
146 146 recover
147 147 remove
148 148 rename
149 149 resolve
150 150 revert
151 151 rollback
152 152 root
153 153 Show the alias of a debug command if there are no other candidates
154 154 $ hg debugcomplete rawc
155 155
156 156
157 157 Show the global options
158 158 $ hg debugcomplete --options | sort
159 159 --color
160 160 --config
161 161 --cwd
162 162 --debug
163 163 --debugger
164 164 --encoding
165 165 --encodingmode
166 166 --help
167 167 --hidden
168 168 --noninteractive
169 169 --pager
170 170 --profile
171 171 --quiet
172 172 --repository
173 173 --time
174 174 --traceback
175 175 --verbose
176 176 --version
177 177 -R
178 178 -h
179 179 -q
180 180 -v
181 181 -y
182 182
183 183 Show the options for the "serve" command
184 184 $ hg debugcomplete --options serve | sort
185 185 --accesslog
186 186 --address
187 187 --certificate
188 188 --cmdserver
189 189 --color
190 190 --config
191 191 --cwd
192 192 --daemon
193 193 --daemon-postexec
194 194 --debug
195 195 --debugger
196 196 --encoding
197 197 --encodingmode
198 198 --errorlog
199 199 --help
200 200 --hidden
201 201 --ipv6
202 202 --name
203 203 --noninteractive
204 204 --pager
205 205 --pid-file
206 206 --port
207 207 --prefix
208 208 --print-url
209 209 --profile
210 210 --quiet
211 211 --repository
212 212 --stdio
213 213 --style
214 214 --subrepos
215 215 --templates
216 216 --time
217 217 --traceback
218 218 --verbose
219 219 --version
220 220 --web-conf
221 221 -6
222 222 -A
223 223 -E
224 224 -R
225 225 -S
226 226 -a
227 227 -d
228 228 -h
229 229 -n
230 230 -p
231 231 -q
232 232 -t
233 233 -v
234 234 -y
235 235
236 236 Show an error if we use --options with an ambiguous abbreviation
237 237 $ hg debugcomplete --options s
238 238 hg: command 's' is ambiguous:
239 239 serve shelve showconfig status summary
240 240 [255]
241 241
242 242 Show all commands + options
243 243 $ hg debugcommands
244 244 abort: dry-run
245 245 add: include, exclude, subrepos, dry-run
246 246 addremove: similarity, subrepos, include, exclude, dry-run
247 247 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
248 248 archive: no-decode, prefix, rev, type, subrepos, include, exclude
249 249 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
250 250 bisect: reset, good, bad, skip, extend, command, noupdate
251 251 bookmarks: force, rev, delete, rename, inactive, list, template
252 252 branch: force, clean, rev
253 253 branches: active, closed, rev, template
254 254 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
255 255 cat: output, rev, decode, include, exclude, template
256 256 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
257 257 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
258 258 config: untrusted, edit, local, global, template
259 259 continue: dry-run
260 260 copy: after, force, include, exclude, dry-run
261 261 debugancestor:
262 262 debugapplystreamclonebundle:
263 263 debugbuilddag: mergeable-file, overwritten-file, new-file
264 264 debugbundle: all, part-type, spec
265 265 debugcapabilities:
266 266 debugcheckstate:
267 267 debugcolor: style
268 268 debugcommands:
269 269 debugcomplete: options
270 270 debugcreatestreamclonebundle:
271 271 debugdag: tags, branches, dots, spaces
272 272 debugdata: changelog, manifest, dir
273 273 debugdate: extended
274 274 debugdeltachain: changelog, manifest, dir, template
275 275 debugdirstate: nodates, dates, datesort
276 276 debugdiscovery: old, nonheads, rev, seed, ssh, remotecmd, insecure
277 277 debugdownload: output
278 278 debugextensions: template
279 279 debugfileset: rev, all-files, show-matcher, show-stage
280 280 debugformat: template
281 281 debugfsinfo:
282 282 debuggetbundle: head, common, type
283 283 debugignore:
284 284 debugindex: changelog, manifest, dir, template
285 285 debugindexdot: changelog, manifest, dir
286 286 debugindexstats:
287 287 debuginstall: template
288 288 debugknown:
289 289 debuglabelcomplete:
290 290 debuglocks: force-lock, force-wlock, set-lock, set-wlock
291 291 debugmanifestfulltextcache: clear, add
292 debugmergestate:
292 debugmergestate: style, template
293 293 debugnamecomplete:
294 294 debugnodemap: dump-new, dump-disk, check, metadata
295 295 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
296 296 debugp1copies: rev
297 297 debugp2copies: rev
298 298 debugpathcomplete: full, normal, added, removed
299 299 debugpathcopies: include, exclude
300 300 debugpeer:
301 301 debugpickmergetool: rev, changedelete, include, exclude, tool
302 302 debugpushkey:
303 303 debugpvec:
304 304 debugrebuilddirstate: rev, minimal
305 305 debugrebuildfncache:
306 306 debugrename: rev
307 307 debugrevlog: changelog, manifest, dir, dump
308 308 debugrevlogindex: changelog, manifest, dir, format
309 309 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
310 310 debugserve: sshstdio, logiofd, logiofile
311 311 debugsetparents:
312 312 debugsidedata: changelog, manifest, dir
313 313 debugssl:
314 314 debugsub: rev
315 315 debugsuccessorssets: closest
316 316 debugtagscache:
317 317 debugtemplate: rev, define
318 318 debuguigetpass: prompt
319 319 debuguiprompt: prompt
320 320 debugupdatecaches:
321 321 debugupgraderepo: optimize, run, backup, changelog, manifest
322 322 debugwalk: include, exclude
323 323 debugwhyunstable:
324 324 debugwireargs: three, four, five, ssh, remotecmd, insecure
325 325 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
326 326 diff: rev, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
327 327 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
328 328 files: rev, print0, include, exclude, template, subrepos
329 329 forget: interactive, include, exclude, dry-run
330 330 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
331 331 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
332 332 heads: rev, topo, active, closed, style, template
333 333 help: extension, command, keyword, system
334 334 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
335 335 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
336 336 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
337 337 init: ssh, remotecmd, insecure
338 338 locate: rev, print0, fullpath, include, exclude
339 339 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
340 340 manifest: rev, all, template
341 341 merge: force, rev, preview, abort, tool
342 342 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
343 343 parents: rev, style, template
344 344 paths: template
345 345 phase: public, draft, secret, force, rev
346 346 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
347 347 push: force, rev, bookmark, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
348 348 recover: verify
349 349 remove: after, force, subrepos, include, exclude, dry-run
350 350 rename: after, force, include, exclude, dry-run
351 351 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
352 352 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
353 353 rollback: dry-run, force
354 354 root: template
355 355 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
356 356 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
357 357 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
358 358 summary: remote
359 359 tag: force, local, rev, remove, edit, message, date, user
360 360 tags: template
361 361 tip: patch, git, style, template
362 362 unbundle: update
363 363 unshelve: abort, continue, interactive, keep, name, tool, date
364 364 update: clean, check, merge, date, rev, tool
365 365 verify: full
366 366 version: template
367 367
368 368 $ hg init a
369 369 $ cd a
370 370 $ echo fee > fee
371 371 $ hg ci -q -Amfee
372 372 $ hg tag fee
373 373 $ mkdir fie
374 374 $ echo dead > fie/dead
375 375 $ echo live > fie/live
376 376 $ hg bookmark fo
377 377 $ hg branch -q fie
378 378 $ hg ci -q -Amfie
379 379 $ echo fo > fo
380 380 $ hg branch -qf default
381 381 $ hg ci -q -Amfo
382 382 $ echo Fum > Fum
383 383 $ hg ci -q -AmFum
384 384 $ hg bookmark Fum
385 385
386 386 Test debugpathcomplete
387 387
388 388 $ hg debugpathcomplete f
389 389 fee
390 390 fie
391 391 fo
392 392 $ hg debugpathcomplete -f f
393 393 fee
394 394 fie/dead
395 395 fie/live
396 396 fo
397 397
398 398 $ hg rm Fum
399 399 $ hg debugpathcomplete -r F
400 400 Fum
401 401
402 402 Test debugnamecomplete
403 403
404 404 $ hg debugnamecomplete
405 405 Fum
406 406 default
407 407 fee
408 408 fie
409 409 fo
410 410 tip
411 411 $ hg debugnamecomplete f
412 412 fee
413 413 fie
414 414 fo
415 415
416 416 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
417 417 used for completions in some shells.
418 418
419 419 $ hg debuglabelcomplete
420 420 Fum
421 421 default
422 422 fee
423 423 fie
424 424 fo
425 425 tip
426 426 $ hg debuglabelcomplete f
427 427 fee
428 428 fie
429 429 fo
@@ -1,187 +1,173 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ initrepo ()
9 9 > {
10 10 > hg init r
11 11 > cd r
12 12 > for x in a b c d e f ; do
13 13 > echo $x > $x
14 14 > hg add $x
15 15 > hg ci -m $x
16 16 > done
17 17 > echo a >> e
18 18 > hg ci -m 'does not commute with e'
19 19 > cd ..
20 20 > }
21 21
22 22 $ initrepo
23 23 $ cd r
24 24
25 25 log before edit
26 26 $ hg log --graph
27 27 @ changeset: 6:bfa474341cc9
28 28 | tag: tip
29 29 | user: test
30 30 | date: Thu Jan 01 00:00:00 1970 +0000
31 31 | summary: does not commute with e
32 32 |
33 33 o changeset: 5:652413bf663e
34 34 | user: test
35 35 | date: Thu Jan 01 00:00:00 1970 +0000
36 36 | summary: f
37 37 |
38 38 o changeset: 4:e860deea161a
39 39 | user: test
40 40 | date: Thu Jan 01 00:00:00 1970 +0000
41 41 | summary: e
42 42 |
43 43 o changeset: 3:055a42cdd887
44 44 | user: test
45 45 | date: Thu Jan 01 00:00:00 1970 +0000
46 46 | summary: d
47 47 |
48 48 o changeset: 2:177f92b77385
49 49 | user: test
50 50 | date: Thu Jan 01 00:00:00 1970 +0000
51 51 | summary: c
52 52 |
53 53 o changeset: 1:d2ae7f538514
54 54 | user: test
55 55 | date: Thu Jan 01 00:00:00 1970 +0000
56 56 | summary: b
57 57 |
58 58 o changeset: 0:cb9a9f314b8b
59 59 user: test
60 60 date: Thu Jan 01 00:00:00 1970 +0000
61 61 summary: a
62 62
63 63
64 64 edit the history
65 65 $ hg histedit 177f92b77385 --commands - 2>&1 <<EOF | fixbundle
66 66 > pick 177f92b77385 c
67 67 > pick 055a42cdd887 d
68 68 > pick bfa474341cc9 does not commute with e
69 69 > pick e860deea161a e
70 70 > pick 652413bf663e f
71 71 > EOF
72 72 merging e
73 73 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
74 74 Fix up the change (pick e860deea161a)
75 75 (hg histedit --continue to resume)
76 76
77 77 insert unsupported advisory merge record
78 78 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
79 79 $ hg debugmergestate
80 * version 2 records
81 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
82 other: e860deea161a2f77de56603b340ebbb4536308ae
83 labels:
84 local: local
85 other: histedit
86 unrecognized entry: x advisory record
87 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
88 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
80 local (local): 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
81 other (histedit): e860deea161a2f77de56603b340ebbb4536308ae
82 file: e (state "u")
89 83 local path: e (flags "")
90 ancestor path: e (node null)
84 ancestor path: e (node 0000000000000000000000000000000000000000)
91 85 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
86 extra: ancestorlinknode = 0000000000000000000000000000000000000000
92 87 $ hg resolve -l
93 88 U e
94 89
95 90 insert unsupported mandatory merge record
96 91 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
97 92 $ hg debugmergestate
98 * version 2 records
99 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
100 other: e860deea161a2f77de56603b340ebbb4536308ae
101 labels:
102 local: local
103 other: histedit
104 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
105 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
106 local path: e (flags "")
107 ancestor path: e (node null)
108 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
109 unrecognized entry: X mandatory record
93 abort: unsupported merge state records: X
94 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
95 [255]
110 96 $ hg resolve -l
111 97 abort: unsupported merge state records: X
112 98 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
113 99 [255]
114 100 $ hg resolve -ma
115 101 abort: unsupported merge state records: X
116 102 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
117 103 [255]
118 104
119 105 abort the edit (should clear out merge state)
120 106 $ hg histedit --abort 2>&1 | fixbundle
121 107 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 108 $ hg debugmergestate
123 109 no merge state found
124 110
125 111 log after abort
126 112 $ hg resolve -l
127 113 $ hg log --graph
128 114 @ changeset: 6:bfa474341cc9
129 115 | tag: tip
130 116 | user: test
131 117 | date: Thu Jan 01 00:00:00 1970 +0000
132 118 | summary: does not commute with e
133 119 |
134 120 o changeset: 5:652413bf663e
135 121 | user: test
136 122 | date: Thu Jan 01 00:00:00 1970 +0000
137 123 | summary: f
138 124 |
139 125 o changeset: 4:e860deea161a
140 126 | user: test
141 127 | date: Thu Jan 01 00:00:00 1970 +0000
142 128 | summary: e
143 129 |
144 130 o changeset: 3:055a42cdd887
145 131 | user: test
146 132 | date: Thu Jan 01 00:00:00 1970 +0000
147 133 | summary: d
148 134 |
149 135 o changeset: 2:177f92b77385
150 136 | user: test
151 137 | date: Thu Jan 01 00:00:00 1970 +0000
152 138 | summary: c
153 139 |
154 140 o changeset: 1:d2ae7f538514
155 141 | user: test
156 142 | date: Thu Jan 01 00:00:00 1970 +0000
157 143 | summary: b
158 144 |
159 145 o changeset: 0:cb9a9f314b8b
160 146 user: test
161 147 date: Thu Jan 01 00:00:00 1970 +0000
162 148 summary: a
163 149
164 150
165 151 Early tree conflict doesn't leave histedit in a wedged state. Note
166 152 that we don't specify --commands here: we catch the problem before we
167 153 even prompt the user for rules, sidestepping any dataloss issues.
168 154
169 155 $ hg rm c
170 156 $ hg ci -m 'remove c'
171 157 $ echo collision > c
172 158
173 159 $ hg histedit e860deea161a
174 160 c: untracked file differs
175 161 abort: untracked files in working directory conflict with files in 055a42cdd887
176 162 [255]
177 163
178 164 We should have detected the collision early enough we're not in a
179 165 histedit state, and p1 is unchanged.
180 166
181 167 $ hg log -r 'p1()' -T'{node}\n'
182 168 1b0954ff00fccb15a37b679e4a35e9b01dfe685e
183 169 $ hg status --config ui.tweakdefaults=yes
184 170 ? c
185 171 ? e.orig
186 172
187 173 $ cd ..
@@ -1,1140 +1,1076 b''
1 1 Tests for change/delete conflicts, including:
2 2 b5605d88dc27: Make ui.prompt repeat on "unrecognized response" again
3 3 (issue897)
4 4
5 5 840e2b315c1f: Fix misleading error and prompts during update/merge
6 6 (issue556)
7 7
8 8 Make sure HGMERGE doesn't interfere with the test
9 9 $ unset HGMERGE
10 10
11 11 $ status() {
12 12 > echo "--- status ---"
13 13 > hg st -A file1 file2 file3
14 14 > echo "--- resolve --list ---"
15 15 > hg resolve --list file1 file2 file3
16 16 > echo "--- debugmergestate ---"
17 17 > hg debugmergestate
18 18 > for file in file1 file2 file3; do
19 19 > if [ -f $file ]; then
20 20 > echo "--- $file ---"
21 21 > cat $file
22 22 > else
23 23 > echo "*** $file does not exist"
24 24 > fi
25 25 > done
26 26 > }
27 27
28 28 $ hg init repo
29 29 $ cd repo
30 30
31 31 $ echo 1 > file1
32 32 $ echo 2 > file2
33 33 $ echo 3 > file3
34 34 $ hg ci -Am 'added files'
35 35 adding file1
36 36 adding file2
37 37 adding file3
38 38
39 39 $ hg rm file1
40 40 $ echo changed >> file2
41 41 $ echo changed1 >> file3
42 42 $ hg ci -m 'removed file1, changed file2, changed file3'
43 43
44 44 $ hg co 0
45 45 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 46
47 47 $ echo changed >> file1
48 48 $ hg rm file2
49 49 $ echo changed2 >> file3
50 50 $ hg ci -m 'changed file1, removed file2, changed file3'
51 51 created new head
52 52
53 53
54 54 Non-interactive merge:
55 55
56 56 $ hg merge -y
57 57 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
58 58 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
59 59 What do you want to do? u
60 60 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
61 61 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
62 62 What do you want to do? u
63 63 merging file3
64 64 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
65 65 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
66 66 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
67 67 [1]
68 68
69 69 $ status
70 70 --- status ---
71 71 M file2
72 72 M file3
73 73 C file1
74 74 --- resolve --list ---
75 75 U file1
76 76 U file2
77 77 U file3
78 78 --- debugmergestate ---
79 * version 2 records
80 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
81 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
82 labels:
83 local: working copy
84 other: merge rev
85 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
86 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
79 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
80 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
81 file: file1 (state "u")
87 82 local path: file1 (flags "")
88 83 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
89 other path: file1 (node null)
90 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
91 file: file2 (record type "C", state "u", hash null)
84 other path: file1 (node 0000000000000000000000000000000000000000)
85 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
86 file: file2 (state "u")
92 87 local path: file2 (flags "")
93 88 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
94 89 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
95 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
96 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
90 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
91 file: file3 (state "u")
97 92 local path: file3 (flags "")
98 93 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
99 94 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
95 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
100 96 --- file1 ---
101 97 1
102 98 changed
103 99 --- file2 ---
104 100 2
105 101 changed
106 102 --- file3 ---
107 103 3
108 104 <<<<<<< working copy: 13910f48cf7b - test: changed file1, removed file2, chan...
109 105 changed2
110 106 =======
111 107 changed1
112 108 >>>>>>> merge rev: 10f9a0a634e8 - test: removed file1, changed file2, chan...
113 109
114 110
115 111 Interactive merge:
116 112
117 113 $ hg co -C
118 114 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
119 115 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
120 116 1 other heads for branch "default"
121 117
122 118 $ hg merge --config ui.interactive=true <<EOF
123 119 > c
124 120 > d
125 121 > EOF
126 122 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
127 123 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
128 124 What do you want to do? c
129 125 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
130 126 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
131 127 What do you want to do? d
132 128 merging file3
133 129 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
134 130 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
135 131 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
136 132 [1]
137 133
138 134 $ status
139 135 --- status ---
140 136 file2: * (glob)
141 137 M file3
142 138 C file1
143 139 --- resolve --list ---
144 140 R file1
145 141 R file2
146 142 U file3
147 143 --- debugmergestate ---
148 * version 2 records
149 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
150 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
151 labels:
152 local: working copy
153 other: merge rev
154 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
155 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
144 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
145 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
146 file: file1 (state "r")
156 147 local path: file1 (flags "")
157 148 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
158 other path: file1 (node null)
159 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
160 file: file2 (record type "C", state "r", hash null)
149 other path: file1 (node 0000000000000000000000000000000000000000)
150 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
151 file: file2 (state "r")
161 152 local path: file2 (flags "")
162 153 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
163 154 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
164 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
165 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
155 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
156 file: file3 (state "u")
166 157 local path: file3 (flags "")
167 158 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
168 159 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
160 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
169 161 --- file1 ---
170 162 1
171 163 changed
172 164 *** file2 does not exist
173 165 --- file3 ---
174 166 3
175 167 <<<<<<< working copy: 13910f48cf7b - test: changed file1, removed file2, chan...
176 168 changed2
177 169 =======
178 170 changed1
179 171 >>>>>>> merge rev: 10f9a0a634e8 - test: removed file1, changed file2, chan...
180 172
181 173
182 174 Interactive merge with bad input:
183 175
184 176 $ hg co -C
185 177 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 178 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
187 179 1 other heads for branch "default"
188 180
189 181 $ hg merge --config ui.interactive=true <<EOF
190 182 > foo
191 183 > bar
192 184 > d
193 185 > baz
194 186 > c
195 187 > EOF
196 188 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
197 189 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
198 190 What do you want to do? foo
199 191 unrecognized response
200 192 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
201 193 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
202 194 What do you want to do? bar
203 195 unrecognized response
204 196 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
205 197 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
206 198 What do you want to do? d
207 199 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
208 200 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
209 201 What do you want to do? baz
210 202 unrecognized response
211 203 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
212 204 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
213 205 What do you want to do? c
214 206 merging file3
215 207 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
216 208 0 files updated, 1 files merged, 1 files removed, 1 files unresolved
217 209 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
218 210 [1]
219 211
220 212 $ status
221 213 --- status ---
222 214 M file2
223 215 M file3
224 216 R file1
225 217 --- resolve --list ---
226 218 R file1
227 219 R file2
228 220 U file3
229 221 --- debugmergestate ---
230 * version 2 records
231 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
232 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
233 labels:
234 local: working copy
235 other: merge rev
236 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
237 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
222 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
223 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
224 file: file1 (state "r")
238 225 local path: file1 (flags "")
239 226 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
240 other path: file1 (node null)
241 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
242 file: file2 (record type "C", state "r", hash null)
227 other path: file1 (node 0000000000000000000000000000000000000000)
228 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
229 file: file2 (state "r")
243 230 local path: file2 (flags "")
244 231 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
245 232 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
246 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
247 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
233 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
234 file: file3 (state "u")
248 235 local path: file3 (flags "")
249 236 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
250 237 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
238 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
251 239 *** file1 does not exist
252 240 --- file2 ---
253 241 2
254 242 changed
255 243 --- file3 ---
256 244 3
257 245 <<<<<<< working copy: 13910f48cf7b - test: changed file1, removed file2, chan...
258 246 changed2
259 247 =======
260 248 changed1
261 249 >>>>>>> merge rev: 10f9a0a634e8 - test: removed file1, changed file2, chan...
262 250
263 251
264 252 Interactive merge with not enough input:
265 253
266 254 $ hg co -C
267 255 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
268 256 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
269 257 1 other heads for branch "default"
270 258
271 259 $ hg merge --config ui.interactive=true <<EOF
272 260 > d
273 261 > EOF
274 262 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
275 263 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
276 264 What do you want to do? d
277 265 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
278 266 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
279 267 What do you want to do?
280 268 merging file3
281 269 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
282 270 0 files updated, 0 files merged, 1 files removed, 2 files unresolved
283 271 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
284 272 [1]
285 273
286 274 $ status
287 275 --- status ---
288 276 M file2
289 277 M file3
290 278 R file1
291 279 --- resolve --list ---
292 280 R file1
293 281 U file2
294 282 U file3
295 283 --- debugmergestate ---
296 * version 2 records
297 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
298 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
299 labels:
300 local: working copy
301 other: merge rev
302 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
303 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
284 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
285 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
286 file: file1 (state "r")
304 287 local path: file1 (flags "")
305 288 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
306 other path: file1 (node null)
307 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
308 file: file2 (record type "C", state "u", hash null)
289 other path: file1 (node 0000000000000000000000000000000000000000)
290 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
291 file: file2 (state "u")
309 292 local path: file2 (flags "")
310 293 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
311 294 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
312 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
313 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
295 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
296 file: file3 (state "u")
314 297 local path: file3 (flags "")
315 298 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
316 299 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
300 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
317 301 *** file1 does not exist
318 302 --- file2 ---
319 303 2
320 304 changed
321 305 --- file3 ---
322 306 3
323 307 <<<<<<< working copy: 13910f48cf7b - test: changed file1, removed file2, chan...
324 308 changed2
325 309 =======
326 310 changed1
327 311 >>>>>>> merge rev: 10f9a0a634e8 - test: removed file1, changed file2, chan...
328 312
329 313 Choose local versions of files
330 314
331 315 $ hg co -C
332 316 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
333 317 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
334 318 1 other heads for branch "default"
335 319
336 320 $ hg merge --tool :local
337 321 0 files updated, 3 files merged, 0 files removed, 0 files unresolved
338 322 (branch merge, don't forget to commit)
339 323 $ status 2>&1 | tee $TESTTMP/local.status
340 324 --- status ---
341 325 file2: * (glob)
342 326 M file3
343 327 C file1
344 328 --- resolve --list ---
345 329 R file1
346 330 R file2
347 331 R file3
348 332 --- debugmergestate ---
349 * version 2 records
350 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
351 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
352 labels:
353 local: working copy
354 other: merge rev
355 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
356 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
333 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
334 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
335 file: file1 (state "r")
357 336 local path: file1 (flags "")
358 337 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
359 other path: file1 (node null)
360 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
361 file: file2 (record type "C", state "r", hash null)
338 other path: file1 (node 0000000000000000000000000000000000000000)
339 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
340 file: file2 (state "r")
362 341 local path: file2 (flags "")
363 342 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
364 343 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
365 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
366 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
344 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
345 file: file3 (state "r")
367 346 local path: file3 (flags "")
368 347 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
369 348 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
349 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
370 350 --- file1 ---
371 351 1
372 352 changed
373 353 *** file2 does not exist
374 354 --- file3 ---
375 355 3
376 356 changed2
377 357
378 358 Choose other versions of files
379 359
380 360 $ hg co -C
381 361 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 362 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
383 363 1 other heads for branch "default"
384 364
385 365 $ hg merge --tool :other
386 366 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
387 367 (branch merge, don't forget to commit)
388 368 $ status 2>&1 | tee $TESTTMP/other.status
389 369 --- status ---
390 370 M file2
391 371 M file3
392 372 R file1
393 373 --- resolve --list ---
394 374 R file1
395 375 R file2
396 376 R file3
397 377 --- debugmergestate ---
398 * version 2 records
399 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
400 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
401 labels:
402 local: working copy
403 other: merge rev
404 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
405 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
378 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
379 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
380 file: file1 (state "r")
406 381 local path: file1 (flags "")
407 382 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
408 other path: file1 (node null)
409 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
410 file: file2 (record type "C", state "r", hash null)
383 other path: file1 (node 0000000000000000000000000000000000000000)
384 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
385 file: file2 (state "r")
411 386 local path: file2 (flags "")
412 387 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
413 388 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
414 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
415 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
389 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
390 file: file3 (state "r")
416 391 local path: file3 (flags "")
417 392 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
418 393 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
394 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
419 395 *** file1 does not exist
420 396 --- file2 ---
421 397 2
422 398 changed
423 399 --- file3 ---
424 400 3
425 401 changed1
426 402
427 403 Fail
428 404
429 405 $ hg co -C
430 406 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
431 407 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
432 408 1 other heads for branch "default"
433 409
434 410 $ hg merge --tool :fail
435 411 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
436 412 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
437 413 [1]
438 414 $ status 2>&1 | tee $TESTTMP/fail.status
439 415 --- status ---
440 416 M file2
441 417 M file3
442 418 C file1
443 419 --- resolve --list ---
444 420 U file1
445 421 U file2
446 422 U file3
447 423 --- debugmergestate ---
448 * version 2 records
449 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
450 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
451 labels:
452 local: working copy
453 other: merge rev
454 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
455 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
424 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
425 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
426 file: file1 (state "u")
456 427 local path: file1 (flags "")
457 428 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
458 other path: file1 (node null)
459 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
460 file: file2 (record type "C", state "u", hash null)
429 other path: file1 (node 0000000000000000000000000000000000000000)
430 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
431 file: file2 (state "u")
461 432 local path: file2 (flags "")
462 433 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
463 434 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
464 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
465 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
435 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
436 file: file3 (state "u")
466 437 local path: file3 (flags "")
467 438 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
468 439 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
440 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
469 441 --- file1 ---
470 442 1
471 443 changed
472 444 --- file2 ---
473 445 2
474 446 changed
475 447 --- file3 ---
476 448 3
477 449 changed2
478 450
479 451 Force prompts with no input (should be similar to :fail)
480 452
481 453 $ hg co -C
482 454 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
483 455 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
484 456 1 other heads for branch "default"
485 457
486 458 $ hg merge --config ui.interactive=True --tool :prompt
487 459 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
488 460 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
489 461 What do you want to do?
490 462 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
491 463 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
492 464 What do you want to do?
493 465 file 'file3' needs to be resolved.
494 466 You can keep (l)ocal [working copy], take (o)ther [merge rev], or leave (u)nresolved.
495 467 What do you want to do?
496 468 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
497 469 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
498 470 [1]
499 471 $ status 2>&1 | tee $TESTTMP/prompt.status
500 472 --- status ---
501 473 M file2
502 474 M file3
503 475 C file1
504 476 --- resolve --list ---
505 477 U file1
506 478 U file2
507 479 U file3
508 480 --- debugmergestate ---
509 * version 2 records
510 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
511 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
512 labels:
513 local: working copy
514 other: merge rev
515 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
516 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
481 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
482 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
483 file: file1 (state "u")
517 484 local path: file1 (flags "")
518 485 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
519 other path: file1 (node null)
520 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
521 file: file2 (record type "C", state "u", hash null)
486 other path: file1 (node 0000000000000000000000000000000000000000)
487 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
488 file: file2 (state "u")
522 489 local path: file2 (flags "")
523 490 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
524 491 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
525 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
526 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
492 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
493 file: file3 (state "u")
527 494 local path: file3 (flags "")
528 495 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
529 496 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
497 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
530 498 --- file1 ---
531 499 1
532 500 changed
533 501 --- file2 ---
534 502 2
535 503 changed
536 504 --- file3 ---
537 505 3
538 506 changed2
539 507 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
540 508
541 509
542 510 Force prompts
543 511
544 512 $ hg co -C
545 513 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
546 514 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
547 515 1 other heads for branch "default"
548 516
549 517 $ hg merge --tool :prompt
550 518 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
551 519 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
552 520 What do you want to do? u
553 521 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
554 522 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
555 523 What do you want to do? u
556 524 file 'file3' needs to be resolved.
557 525 You can keep (l)ocal [working copy], take (o)ther [merge rev], or leave (u)nresolved.
558 526 What do you want to do? u
559 527 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
560 528 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
561 529 [1]
562 530 $ status
563 531 --- status ---
564 532 M file2
565 533 M file3
566 534 C file1
567 535 --- resolve --list ---
568 536 U file1
569 537 U file2
570 538 U file3
571 539 --- debugmergestate ---
572 * version 2 records
573 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
574 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
575 labels:
576 local: working copy
577 other: merge rev
578 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
579 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
540 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
541 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
542 file: file1 (state "u")
580 543 local path: file1 (flags "")
581 544 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
582 other path: file1 (node null)
583 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
584 file: file2 (record type "C", state "u", hash null)
545 other path: file1 (node 0000000000000000000000000000000000000000)
546 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
547 file: file2 (state "u")
585 548 local path: file2 (flags "")
586 549 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
587 550 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
588 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
589 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
551 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
552 file: file3 (state "u")
590 553 local path: file3 (flags "")
591 554 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
592 555 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
556 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
593 557 --- file1 ---
594 558 1
595 559 changed
596 560 --- file2 ---
597 561 2
598 562 changed
599 563 --- file3 ---
600 564 3
601 565 changed2
602 566
603 567 Choose to merge all files
604 568
605 569 $ hg co -C
606 570 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
607 571 updated to "13910f48cf7b: changed file1, removed file2, changed file3"
608 572 1 other heads for branch "default"
609 573
610 574 $ hg merge --tool :merge3
611 575 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
612 576 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
613 577 What do you want to do? u
614 578 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
615 579 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
616 580 What do you want to do? u
617 581 merging file3
618 582 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
619 583 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
620 584 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
621 585 [1]
622 586 $ status
623 587 --- status ---
624 588 M file2
625 589 M file3
626 590 C file1
627 591 --- resolve --list ---
628 592 U file1
629 593 U file2
630 594 U file3
631 595 --- debugmergestate ---
632 * version 2 records
633 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
634 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
635 labels:
636 local: working copy
637 other: merge rev
638 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
639 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
596 local (working copy): 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
597 other (merge rev): 10f9a0a634e82080907e62f075ab119cbc565ea6
598 file: file1 (state "u")
640 599 local path: file1 (flags "")
641 600 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
642 other path: file1 (node null)
643 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
644 file: file2 (record type "C", state "u", hash null)
601 other path: file1 (node 0000000000000000000000000000000000000000)
602 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
603 file: file2 (state "u")
645 604 local path: file2 (flags "")
646 605 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
647 606 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
648 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
649 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
607 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
608 file: file3 (state "u")
650 609 local path: file3 (flags "")
651 610 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
652 611 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
612 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
653 613 --- file1 ---
654 614 1
655 615 changed
656 616 --- file2 ---
657 617 2
658 618 changed
659 619 --- file3 ---
660 620 3
661 621 <<<<<<< working copy: 13910f48cf7b - test: changed file1, removed file2, chan...
662 622 changed2
663 623 ||||||| base
664 624 =======
665 625 changed1
666 626 >>>>>>> merge rev: 10f9a0a634e8 - test: removed file1, changed file2, chan...
667 627
668 628 Exercise transitions between local, other, fail and prompt, and make sure the
669 629 dirstate stays consistent. (Compare with each other and to the above
670 630 invocations.)
671 631
672 632 $ testtransitions() {
673 633 > # this traversal order covers every transition
674 634 > tools="local other prompt local fail other local prompt other fail prompt fail local"
675 635 > lasttool="merge3"
676 636 > for tool in $tools; do
677 637 > echo "=== :$lasttool -> :$tool ==="
678 638 > ref="$TESTTMP/$tool.status"
679 639 > hg resolve --unmark --all
680 640 > hg resolve --tool ":$tool" --all --config ui.interactive=True
681 641 > status > "$TESTTMP/compare.status" 2>&1
682 642 > echo '--- diff of status ---'
683 643 > if cmp "$TESTTMP/$tool.status" "$TESTTMP/compare.status" || diff -U8 "$TESTTMP/$tool.status" "$TESTTMP/compare.status"; then
684 644 > echo '(status identical)'
685 645 > fi
686 646 > lasttool="$tool"
687 647 > echo
688 648 > done
689 649 > }
690 650
691 651 $ testtransitions
692 652 === :merge3 -> :local ===
693 653 (no more unresolved files)
694 654 --- diff of status ---
695 655 (status identical)
696 656
697 657 === :local -> :other ===
698 658 (no more unresolved files)
699 659 --- diff of status ---
700 660 (status identical)
701 661
702 662 === :other -> :prompt ===
703 663 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
704 664 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
705 665 What do you want to do?
706 666 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
707 667 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
708 668 What do you want to do?
709 669 file 'file3' needs to be resolved.
710 670 You can keep (l)ocal [working copy], take (o)ther [merge rev], or leave (u)nresolved.
711 671 What do you want to do?
712 672 --- diff of status ---
713 673 (status identical)
714 674
715 675 === :prompt -> :local ===
716 676 (no more unresolved files)
717 677 --- diff of status ---
718 678 (status identical)
719 679
720 680 === :local -> :fail ===
721 681 --- diff of status ---
722 682 (status identical)
723 683
724 684 === :fail -> :other ===
725 685 (no more unresolved files)
726 686 --- diff of status ---
727 687 (status identical)
728 688
729 689 === :other -> :local ===
730 690 (no more unresolved files)
731 691 --- diff of status ---
732 692 (status identical)
733 693
734 694 === :local -> :prompt ===
735 695 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
736 696 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
737 697 What do you want to do?
738 698 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
739 699 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
740 700 What do you want to do?
741 701 file 'file3' needs to be resolved.
742 702 You can keep (l)ocal [working copy], take (o)ther [merge rev], or leave (u)nresolved.
743 703 What do you want to do?
744 704 --- diff of status ---
745 705 (status identical)
746 706
747 707 === :prompt -> :other ===
748 708 (no more unresolved files)
749 709 --- diff of status ---
750 710 (status identical)
751 711
752 712 === :other -> :fail ===
753 713 --- diff of status ---
754 714 (status identical)
755 715
756 716 === :fail -> :prompt ===
757 717 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
758 718 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
759 719 What do you want to do?
760 720 file 'file2' was deleted in local [working copy] but was modified in other [merge rev].
761 721 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
762 722 What do you want to do?
763 723 file 'file3' needs to be resolved.
764 724 You can keep (l)ocal [working copy], take (o)ther [merge rev], or leave (u)nresolved.
765 725 What do you want to do?
766 726 --- diff of status ---
767 727 (status identical)
768 728
769 729 === :prompt -> :fail ===
770 730 --- diff of status ---
771 731 (status identical)
772 732
773 733 === :fail -> :local ===
774 734 (no more unresolved files)
775 735 --- diff of status ---
776 736 (status identical)
777 737
778 738
779 739
780 740 Non-interactive linear update
781 741
782 742 $ hg co -C 0
783 743 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
784 744 $ echo changed >> file1
785 745 $ hg rm file2
786 746 $ hg update 1 -y
787 747 file 'file1' was deleted in other [destination] but was modified in local [working copy].
788 748 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
789 749 What do you want to do? u
790 750 file 'file2' was deleted in local [working copy] but was modified in other [destination].
791 751 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
792 752 What do you want to do? u
793 753 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
794 754 use 'hg resolve' to retry unresolved file merges
795 755 [1]
796 756 $ status
797 757 --- status ---
798 758 A file1
799 759 C file2
800 760 C file3
801 761 --- resolve --list ---
802 762 U file1
803 763 U file2
804 764 --- debugmergestate ---
805 * version 2 records
806 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
807 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
808 labels:
809 local: working copy
810 other: destination
811 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
812 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
765 local (working copy): ab57bf49aa276a22d35a473592d4c34b5abc3eff
766 other (destination): 10f9a0a634e82080907e62f075ab119cbc565ea6
767 file: file1 (state "u")
813 768 local path: file1 (flags "")
814 769 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
815 other path: file1 (node null)
816 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
817 file: file2 (record type "C", state "u", hash null)
770 other path: file1 (node 0000000000000000000000000000000000000000)
771 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
772 file: file2 (state "u")
818 773 local path: file2 (flags "")
819 774 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
820 775 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
776 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
821 777 --- file1 ---
822 778 1
823 779 changed
824 780 --- file2 ---
825 781 2
826 782 changed
827 783 --- file3 ---
828 784 3
829 785 changed1
830 786
831 787 Choose local versions of files
832 788
833 789 $ hg co -C 0
834 790 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
835 791 $ echo changed >> file1
836 792 $ hg rm file2
837 793 $ hg update 1 --tool :local
838 794 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
839 795 $ status 2>&1 | tee $TESTTMP/local.status
840 796 --- status ---
841 797 file2: * (glob)
842 798 A file1
843 799 C file3
844 800 --- resolve --list ---
845 801 R file1
846 802 R file2
847 803 --- debugmergestate ---
848 * version 2 records
849 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
850 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
851 labels:
852 local: working copy
853 other: destination
854 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
855 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
804 local (working copy): ab57bf49aa276a22d35a473592d4c34b5abc3eff
805 other (destination): 10f9a0a634e82080907e62f075ab119cbc565ea6
806 file: file1 (state "r")
856 807 local path: file1 (flags "")
857 808 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
858 other path: file1 (node null)
859 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
860 file: file2 (record type "C", state "r", hash null)
809 other path: file1 (node 0000000000000000000000000000000000000000)
810 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
811 file: file2 (state "r")
861 812 local path: file2 (flags "")
862 813 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
863 814 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
815 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
864 816 --- file1 ---
865 817 1
866 818 changed
867 819 *** file2 does not exist
868 820 --- file3 ---
869 821 3
870 822 changed1
871 823
872 824 Choose other versions of files
873 825
874 826 $ hg co -C 0
875 827 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
876 828 $ echo changed >> file1
877 829 $ hg rm file2
878 830 $ hg update 1 --tool :other
879 831 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
880 832 $ status 2>&1 | tee $TESTTMP/other.status
881 833 --- status ---
882 834 file1: * (glob)
883 835 C file2
884 836 C file3
885 837 --- resolve --list ---
886 838 R file1
887 839 R file2
888 840 --- debugmergestate ---
889 * version 2 records
890 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
891 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
892 labels:
893 local: working copy
894 other: destination
895 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
896 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
841 local (working copy): ab57bf49aa276a22d35a473592d4c34b5abc3eff
842 other (destination): 10f9a0a634e82080907e62f075ab119cbc565ea6
843 file: file1 (state "r")
897 844 local path: file1 (flags "")
898 845 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
899 other path: file1 (node null)
900 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
901 file: file2 (record type "C", state "r", hash null)
846 other path: file1 (node 0000000000000000000000000000000000000000)
847 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
848 file: file2 (state "r")
902 849 local path: file2 (flags "")
903 850 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
904 851 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
852 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
905 853 *** file1 does not exist
906 854 --- file2 ---
907 855 2
908 856 changed
909 857 --- file3 ---
910 858 3
911 859 changed1
912 860
913 861 Fail
914 862
915 863 $ hg co -C 0
916 864 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
917 865 $ echo changed >> file1
918 866 $ hg rm file2
919 867 $ hg update 1 --tool :fail
920 868 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
921 869 use 'hg resolve' to retry unresolved file merges
922 870 [1]
923 871 $ status 2>&1 | tee $TESTTMP/fail.status
924 872 --- status ---
925 873 A file1
926 874 C file2
927 875 C file3
928 876 --- resolve --list ---
929 877 U file1
930 878 U file2
931 879 --- debugmergestate ---
932 * version 2 records
933 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
934 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
935 labels:
936 local: working copy
937 other: destination
938 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
939 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
880 local (working copy): ab57bf49aa276a22d35a473592d4c34b5abc3eff
881 other (destination): 10f9a0a634e82080907e62f075ab119cbc565ea6
882 file: file1 (state "u")
940 883 local path: file1 (flags "")
941 884 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
942 other path: file1 (node null)
943 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
944 file: file2 (record type "C", state "u", hash null)
885 other path: file1 (node 0000000000000000000000000000000000000000)
886 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
887 file: file2 (state "u")
945 888 local path: file2 (flags "")
946 889 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
947 890 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
891 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
948 892 --- file1 ---
949 893 1
950 894 changed
951 895 --- file2 ---
952 896 2
953 897 changed
954 898 --- file3 ---
955 899 3
956 900 changed1
957 901
958 902 Force prompts with no input
959 903
960 904 $ hg co -C 0
961 905 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
962 906 $ echo changed >> file1
963 907 $ hg rm file2
964 908 $ hg update 1 --config ui.interactive=True --tool :prompt
965 909 file 'file1' was deleted in other [destination] but was modified in local [working copy].
966 910 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
967 911 What do you want to do?
968 912 file 'file2' was deleted in local [working copy] but was modified in other [destination].
969 913 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
970 914 What do you want to do?
971 915 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
972 916 use 'hg resolve' to retry unresolved file merges
973 917 [1]
974 918 $ status 2>&1 | tee $TESTTMP/prompt.status
975 919 --- status ---
976 920 A file1
977 921 C file2
978 922 C file3
979 923 --- resolve --list ---
980 924 U file1
981 925 U file2
982 926 --- debugmergestate ---
983 * version 2 records
984 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
985 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
986 labels:
987 local: working copy
988 other: destination
989 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
990 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
927 local (working copy): ab57bf49aa276a22d35a473592d4c34b5abc3eff
928 other (destination): 10f9a0a634e82080907e62f075ab119cbc565ea6
929 file: file1 (state "u")
991 930 local path: file1 (flags "")
992 931 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
993 other path: file1 (node null)
994 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
995 file: file2 (record type "C", state "u", hash null)
932 other path: file1 (node 0000000000000000000000000000000000000000)
933 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
934 file: file2 (state "u")
996 935 local path: file2 (flags "")
997 936 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
998 937 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
938 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
999 939 --- file1 ---
1000 940 1
1001 941 changed
1002 942 --- file2 ---
1003 943 2
1004 944 changed
1005 945 --- file3 ---
1006 946 3
1007 947 changed1
1008 948 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
1009 949
1010 950 Choose to merge all files
1011 951
1012 952 $ hg co -C 0
1013 953 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1014 954 $ echo changed >> file1
1015 955 $ hg rm file2
1016 956 $ hg update 1 --tool :merge3
1017 957 file 'file1' was deleted in other [destination] but was modified in local [working copy].
1018 958 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
1019 959 What do you want to do? u
1020 960 file 'file2' was deleted in local [working copy] but was modified in other [destination].
1021 961 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
1022 962 What do you want to do? u
1023 963 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
1024 964 use 'hg resolve' to retry unresolved file merges
1025 965 [1]
1026 966 $ status
1027 967 --- status ---
1028 968 A file1
1029 969 C file2
1030 970 C file3
1031 971 --- resolve --list ---
1032 972 U file1
1033 973 U file2
1034 974 --- debugmergestate ---
1035 * version 2 records
1036 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
1037 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
1038 labels:
1039 local: working copy
1040 other: destination
1041 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
1042 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
975 local (working copy): ab57bf49aa276a22d35a473592d4c34b5abc3eff
976 other (destination): 10f9a0a634e82080907e62f075ab119cbc565ea6
977 file: file1 (state "u")
1043 978 local path: file1 (flags "")
1044 979 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
1045 other path: file1 (node null)
1046 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
1047 file: file2 (record type "C", state "u", hash null)
980 other path: file1 (node 0000000000000000000000000000000000000000)
981 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
982 file: file2 (state "u")
1048 983 local path: file2 (flags "")
1049 984 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
1050 985 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
986 extra: ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff
1051 987 --- file1 ---
1052 988 1
1053 989 changed
1054 990 --- file2 ---
1055 991 2
1056 992 changed
1057 993 --- file3 ---
1058 994 3
1059 995 changed1
1060 996
1061 997 Test transitions between different merge tools
1062 998
1063 999 $ testtransitions
1064 1000 === :merge3 -> :local ===
1065 1001 (no more unresolved files)
1066 1002 --- diff of status ---
1067 1003 (status identical)
1068 1004
1069 1005 === :local -> :other ===
1070 1006 (no more unresolved files)
1071 1007 --- diff of status ---
1072 1008 (status identical)
1073 1009
1074 1010 === :other -> :prompt ===
1075 1011 file 'file1' was deleted in other [destination] but was modified in local [working copy].
1076 1012 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
1077 1013 What do you want to do?
1078 1014 file 'file2' was deleted in local [working copy] but was modified in other [destination].
1079 1015 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
1080 1016 What do you want to do?
1081 1017 --- diff of status ---
1082 1018 (status identical)
1083 1019
1084 1020 === :prompt -> :local ===
1085 1021 (no more unresolved files)
1086 1022 --- diff of status ---
1087 1023 (status identical)
1088 1024
1089 1025 === :local -> :fail ===
1090 1026 --- diff of status ---
1091 1027 (status identical)
1092 1028
1093 1029 === :fail -> :other ===
1094 1030 (no more unresolved files)
1095 1031 --- diff of status ---
1096 1032 (status identical)
1097 1033
1098 1034 === :other -> :local ===
1099 1035 (no more unresolved files)
1100 1036 --- diff of status ---
1101 1037 (status identical)
1102 1038
1103 1039 === :local -> :prompt ===
1104 1040 file 'file1' was deleted in other [destination] but was modified in local [working copy].
1105 1041 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
1106 1042 What do you want to do?
1107 1043 file 'file2' was deleted in local [working copy] but was modified in other [destination].
1108 1044 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
1109 1045 What do you want to do?
1110 1046 --- diff of status ---
1111 1047 (status identical)
1112 1048
1113 1049 === :prompt -> :other ===
1114 1050 (no more unresolved files)
1115 1051 --- diff of status ---
1116 1052 (status identical)
1117 1053
1118 1054 === :other -> :fail ===
1119 1055 --- diff of status ---
1120 1056 (status identical)
1121 1057
1122 1058 === :fail -> :prompt ===
1123 1059 file 'file1' was deleted in other [destination] but was modified in local [working copy].
1124 1060 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
1125 1061 What do you want to do?
1126 1062 file 'file2' was deleted in local [working copy] but was modified in other [destination].
1127 1063 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
1128 1064 What do you want to do?
1129 1065 --- diff of status ---
1130 1066 (status identical)
1131 1067
1132 1068 === :prompt -> :fail ===
1133 1069 --- diff of status ---
1134 1070 (status identical)
1135 1071
1136 1072 === :fail -> :local ===
1137 1073 (no more unresolved files)
1138 1074 --- diff of status ---
1139 1075 (status identical)
1140 1076
@@ -1,525 +1,511 b''
1 1 #testcases abortcommand abortflag
2 2 #testcases continuecommand continueflag
3 3
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [extensions]
6 6 > rebase=
7 7 >
8 8 > [phases]
9 9 > publish=False
10 10 >
11 11 > [alias]
12 12 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
13 13 > EOF
14 14
15 15 #if abortflag
16 16 $ cat >> $HGRCPATH <<EOF
17 17 > [alias]
18 18 > abort = rebase --abort
19 19 > EOF
20 20 #endif
21 21
22 22 #if continueflag
23 23 $ cat >> $HGRCPATH <<EOF
24 24 > [alias]
25 25 > continue = rebase --continue
26 26 > EOF
27 27 #endif
28 28
29 29 $ hg init a
30 30 $ cd a
31 31
32 32 $ touch .hg/rebasestate
33 33 $ hg sum
34 34 parent: -1:000000000000 tip (empty repository)
35 35 branch: default
36 36 commit: (clean)
37 37 update: (current)
38 38 abort: .hg/rebasestate is incomplete
39 39 [255]
40 40 $ rm .hg/rebasestate
41 41
42 42 $ echo c1 > common
43 43 $ hg add common
44 44 $ hg ci -m C1
45 45
46 46 $ echo c2 >> common
47 47 $ hg ci -m C2
48 48
49 49 $ echo c3 >> common
50 50 $ hg ci -m C3
51 51
52 52 $ hg up -q -C 1
53 53
54 54 $ echo l1 >> extra
55 55 $ hg add extra
56 56 $ hg ci -m L1
57 57 created new head
58 58
59 59 $ sed -e 's/c2/l2/' common > common.new
60 60 $ mv common.new common
61 61 $ hg ci -m L2
62 62
63 63 $ hg phase --force --secret 2
64 64
65 65 $ hg tglog
66 66 @ 4:draft 'L2'
67 67 |
68 68 o 3:draft 'L1'
69 69 |
70 70 | o 2:secret 'C3'
71 71 |/
72 72 o 1:draft 'C2'
73 73 |
74 74 o 0:draft 'C1'
75 75
76 76
77 77 Conflicting rebase:
78 78
79 79 $ hg rebase -s 3 -d 2
80 80 rebasing 3:3163e20567cc "L1"
81 81 rebasing 4:46f0b057b5c0 "L2" (tip)
82 82 merging common
83 83 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
84 84 unresolved conflicts (see hg resolve, then hg rebase --continue)
85 85 [1]
86 86
87 87 Insert unsupported advisory merge record:
88 88
89 89 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
90 90 $ hg debugmergestate
91 * version 2 records
92 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
93 other: 46f0b057b5c061d276b91491c22151f78698abd2
94 labels:
95 local: dest
96 other: source
97 unrecognized entry: x advisory record
98 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
99 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
91 local (dest): 3e046f2ecedb793b97ed32108086edd1a162f8bc
92 other (source): 46f0b057b5c061d276b91491c22151f78698abd2
93 file: common (state "u")
100 94 local path: common (flags "")
101 95 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
102 96 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
97 extra: ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c
103 98 $ hg resolve -l
104 99 U common
105 100
106 101 Insert unsupported mandatory merge record:
107 102
108 103 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
109 104 $ hg debugmergestate
110 * version 2 records
111 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
112 other: 46f0b057b5c061d276b91491c22151f78698abd2
113 labels:
114 local: dest
115 other: source
116 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
117 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
118 local path: common (flags "")
119 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
120 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
121 unrecognized entry: X mandatory record
105 abort: unsupported merge state records: X
106 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
107 [255]
122 108 $ hg resolve -l
123 109 abort: unsupported merge state records: X
124 110 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
125 111 [255]
126 112 $ hg resolve -ma
127 113 abort: unsupported merge state records: X
128 114 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
129 115 [255]
130 116
131 117 Abort (should clear out unsupported merge state):
132 118
133 119 #if abortcommand
134 120 when in dry-run mode
135 121 $ hg abort --dry-run
136 122 rebase in progress, will be aborted
137 123 #endif
138 124
139 125 $ hg abort
140 126 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3e046f2ecedb-6beef7d5-backup.hg
141 127 rebase aborted
142 128 $ hg debugmergestate
143 129 no merge state found
144 130
145 131 $ hg tglog
146 132 @ 4:draft 'L2'
147 133 |
148 134 o 3:draft 'L1'
149 135 |
150 136 | o 2:secret 'C3'
151 137 |/
152 138 o 1:draft 'C2'
153 139 |
154 140 o 0:draft 'C1'
155 141
156 142 Test safety for inconsistent rebase state, which may be created (and
157 143 forgotten) by Mercurial earlier than 2.7. This emulates Mercurial
158 144 earlier than 2.7 by renaming ".hg/rebasestate" temporarily.
159 145
160 146 $ hg rebase -s 3 -d 2
161 147 rebasing 3:3163e20567cc "L1"
162 148 rebasing 4:46f0b057b5c0 "L2" (tip)
163 149 merging common
164 150 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
165 151 unresolved conflicts (see hg resolve, then hg rebase --continue)
166 152 [1]
167 153
168 154 $ mv .hg/rebasestate .hg/rebasestate.back
169 155 $ hg update --quiet --clean 2
170 156 $ hg --config extensions.mq= strip --quiet "destination()"
171 157 $ mv .hg/rebasestate.back .hg/rebasestate
172 158
173 159 $ hg continue
174 160 abort: cannot continue inconsistent rebase
175 161 (use "hg rebase --abort" to clear broken state)
176 162 [255]
177 163 $ hg summary | grep '^rebase: '
178 164 rebase: (use "hg rebase --abort" to clear broken state)
179 165 $ hg abort
180 166 rebase aborted (no revision is removed, only broken state is cleared)
181 167
182 168 $ cd ..
183 169
184 170
185 171 Construct new repo:
186 172
187 173 $ hg init b
188 174 $ cd b
189 175
190 176 $ echo a > a
191 177 $ hg ci -Am A
192 178 adding a
193 179
194 180 $ echo b > b
195 181 $ hg ci -Am B
196 182 adding b
197 183
198 184 $ echo c > c
199 185 $ hg ci -Am C
200 186 adding c
201 187
202 188 $ hg up -q 0
203 189
204 190 $ echo b > b
205 191 $ hg ci -Am 'B bis'
206 192 adding b
207 193 created new head
208 194
209 195 $ echo c1 > c
210 196 $ hg ci -Am C1
211 197 adding c
212 198
213 199 $ hg phase --force --secret 1
214 200 $ hg phase --public 1
215 201
216 202 Rebase and abort without generating new changesets:
217 203
218 204 $ hg tglog
219 205 @ 4:draft 'C1'
220 206 |
221 207 o 3:draft 'B bis'
222 208 |
223 209 | o 2:secret 'C'
224 210 | |
225 211 | o 1:public 'B'
226 212 |/
227 213 o 0:public 'A'
228 214
229 215 $ hg rebase -b 4 -d 2
230 216 rebasing 3:a6484957d6b9 "B bis"
231 217 note: not rebasing 3:a6484957d6b9 "B bis", its destination already has all its changes
232 218 rebasing 4:145842775fec "C1" (tip)
233 219 merging c
234 220 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
235 221 unresolved conflicts (see hg resolve, then hg rebase --continue)
236 222 [1]
237 223
238 224 $ hg tglog
239 225 % 4:draft 'C1'
240 226 |
241 227 o 3:draft 'B bis'
242 228 |
243 229 | @ 2:secret 'C'
244 230 | |
245 231 | o 1:public 'B'
246 232 |/
247 233 o 0:public 'A'
248 234
249 235 $ hg rebase -a
250 236 rebase aborted
251 237
252 238 $ hg tglog
253 239 @ 4:draft 'C1'
254 240 |
255 241 o 3:draft 'B bis'
256 242 |
257 243 | o 2:secret 'C'
258 244 | |
259 245 | o 1:public 'B'
260 246 |/
261 247 o 0:public 'A'
262 248
263 249
264 250 $ cd ..
265 251
266 252 rebase abort should not leave working copy in a merge state if tip-1 is public
267 253 (issue4082)
268 254
269 255 $ hg init abortpublic
270 256 $ cd abortpublic
271 257 $ echo a > a && hg ci -Aqm a
272 258 $ hg book master
273 259 $ hg book foo
274 260 $ echo b > b && hg ci -Aqm b
275 261 $ hg up -q master
276 262 $ echo c > c && hg ci -Aqm c
277 263 $ hg phase -p -r .
278 264 $ hg up -q foo
279 265 $ echo C > c && hg ci -Aqm C
280 266 $ hg log -G --template "{rev} {desc} {bookmarks}"
281 267 @ 3 C foo
282 268 |
283 269 | o 2 c master
284 270 | |
285 271 o | 1 b
286 272 |/
287 273 o 0 a
288 274
289 275
290 276 $ hg rebase -d master -r foo
291 277 rebasing 3:6c0f977a22d8 "C" (foo tip)
292 278 merging c
293 279 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
294 280 unresolved conflicts (see hg resolve, then hg rebase --continue)
295 281 [1]
296 282 $ hg abort
297 283 rebase aborted
298 284 $ hg log -G --template "{rev} {desc} {bookmarks}"
299 285 @ 3 C foo
300 286 |
301 287 | o 2 c master
302 288 | |
303 289 o | 1 b
304 290 |/
305 291 o 0 a
306 292
307 293 $ cd ..
308 294
309 295 Make sure we don't clobber changes in the working directory when the
310 296 user has somehow managed to update to a different revision (issue4009)
311 297
312 298 $ hg init noupdate
313 299 $ cd noupdate
314 300 $ hg book @
315 301 $ echo original > a
316 302 $ hg add a
317 303 $ hg commit -m a
318 304 $ echo x > b
319 305 $ hg add b
320 306 $ hg commit -m b1
321 307 $ hg up 0
322 308 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
323 309 (leaving bookmark @)
324 310 $ hg book foo
325 311 $ echo y > b
326 312 $ hg add b
327 313 $ hg commit -m b2
328 314 created new head
329 315
330 316 $ hg rebase -d @ -b foo --tool=internal:fail
331 317 rebasing 2:070cf4580bb5 "b2" (foo tip)
332 318 unresolved conflicts (see hg resolve, then hg rebase --continue)
333 319 [1]
334 320
335 321 $ mv .hg/rebasestate ./ # so we're allowed to hg up like in mercurial <2.6.3
336 322 $ hg up -C 0 # user does other stuff in the repo
337 323 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
338 324
339 325 $ mv rebasestate .hg/ # user upgrades to 2.7
340 326
341 327 $ echo new > a
342 328 $ hg up 1 # user gets an error saying to run hg rebase --abort
343 329 abort: rebase in progress
344 330 (use 'hg rebase --continue' or 'hg rebase --abort')
345 331 [255]
346 332
347 333 $ cat a
348 334 new
349 335 $ hg abort
350 336 rebase aborted
351 337 $ cat a
352 338 new
353 339
354 340 $ cd ..
355 341
356 342 test aborting an interrupted series (issue5084)
357 343 $ hg init interrupted
358 344 $ cd interrupted
359 345 $ touch base
360 346 $ hg add base
361 347 $ hg commit -m base
362 348 $ touch a
363 349 $ hg add a
364 350 $ hg commit -m a
365 351 $ echo 1 > a
366 352 $ hg commit -m 1
367 353 $ touch b
368 354 $ hg add b
369 355 $ hg commit -m b
370 356 $ echo 2 >> a
371 357 $ hg commit -m c
372 358 $ touch d
373 359 $ hg add d
374 360 $ hg commit -m d
375 361 $ hg co -q 1
376 362 $ hg rm a
377 363 $ hg commit -m no-a
378 364 created new head
379 365 $ hg co 0
380 366 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 367 $ hg log -G --template "{rev} {desc} {bookmarks}"
382 368 o 6 no-a
383 369 |
384 370 | o 5 d
385 371 | |
386 372 | o 4 c
387 373 | |
388 374 | o 3 b
389 375 | |
390 376 | o 2 1
391 377 |/
392 378 o 1 a
393 379 |
394 380 @ 0 base
395 381
396 382 $ hg --config extensions.n=$TESTDIR/failfilemerge.py rebase -s 3 -d tip
397 383 rebasing 3:3a71550954f1 "b"
398 384 rebasing 4:e80b69427d80 "c"
399 385 abort: ^C
400 386 [255]
401 387
402 388 New operations are blocked with the correct state message
403 389
404 390 $ find .hg -name '*state' -prune | sort
405 391 .hg/dirstate
406 392 .hg/merge/state
407 393 .hg/rebasestate
408 394 .hg/undo.backup.dirstate
409 395 .hg/undo.dirstate
410 396 .hg/updatestate
411 397
412 398 $ hg rebase -s 3 -d tip
413 399 abort: rebase in progress
414 400 (use 'hg rebase --continue' or 'hg rebase --abort')
415 401 [255]
416 402 $ hg up .
417 403 abort: rebase in progress
418 404 (use 'hg rebase --continue' or 'hg rebase --abort')
419 405 [255]
420 406 $ hg up -C .
421 407 abort: rebase in progress
422 408 (use 'hg rebase --continue' or 'hg rebase --abort')
423 409 [255]
424 410
425 411 $ hg graft 3
426 412 abort: rebase in progress
427 413 (use 'hg rebase --continue' or 'hg rebase --abort')
428 414 [255]
429 415
430 416 $ hg abort
431 417 saved backup bundle to $TESTTMP/interrupted/.hg/strip-backup/3d8812cf300d-93041a90-backup.hg
432 418 rebase aborted
433 419 $ hg log -G --template "{rev} {desc} {bookmarks}"
434 420 o 6 no-a
435 421 |
436 422 | o 5 d
437 423 | |
438 424 | o 4 c
439 425 | |
440 426 | o 3 b
441 427 | |
442 428 | o 2 1
443 429 |/
444 430 o 1 a
445 431 |
446 432 @ 0 base
447 433
448 434 $ hg summary
449 435 parent: 0:df4f53cec30a
450 436 base
451 437 branch: default
452 438 commit: (clean)
453 439 update: 6 new changesets (update)
454 440 phases: 7 draft
455 441
456 442 $ cd ..
457 443 On the other hand, make sure we *do* clobber changes whenever we
458 444 haven't somehow managed to update the repo to a different revision
459 445 during a rebase (issue4661)
460 446
461 447 $ hg ini yesupdate
462 448 $ cd yesupdate
463 449 $ echo "initial data" > foo.txt
464 450 $ hg add
465 451 adding foo.txt
466 452 $ hg ci -m "initial checkin"
467 453 $ echo "change 1" > foo.txt
468 454 $ hg ci -m "change 1"
469 455 $ hg up 0
470 456 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
471 457 $ echo "conflicting change 1" > foo.txt
472 458 $ hg ci -m "conflicting 1"
473 459 created new head
474 460 $ echo "conflicting change 2" > foo.txt
475 461 $ hg ci -m "conflicting 2"
476 462
477 463 $ hg rebase -d 1 --tool 'internal:fail'
478 464 rebasing 2:e4ea5cdc9789 "conflicting 1"
479 465 unresolved conflicts (see hg resolve, then hg rebase --continue)
480 466 [1]
481 467 $ hg abort
482 468 rebase aborted
483 469 $ hg summary
484 470 parent: 3:b16646383533 tip
485 471 conflicting 2
486 472 branch: default
487 473 commit: (clean)
488 474 update: 1 new changesets, 2 branch heads (merge)
489 475 phases: 4 draft
490 476 $ cd ..
491 477
492 478 test aborting a rebase succeeds after rebasing with skipped commits onto a
493 479 public changeset (issue4896)
494 480
495 481 $ hg init succeedonpublic
496 482 $ cd succeedonpublic
497 483 $ echo 'content' > root
498 484 $ hg commit -A -m 'root' -q
499 485
500 486 set up public branch
501 487 $ echo 'content' > disappear
502 488 $ hg commit -A -m 'disappear public' -q
503 489 commit will cause merge conflict on rebase
504 490 $ echo '' > root
505 491 $ hg commit -m 'remove content public' -q
506 492 $ hg phase --public
507 493
508 494 setup the draft branch that will be rebased onto public commit
509 495 $ hg up -r 0 -q
510 496 $ echo 'content' > disappear
511 497 commit will disappear
512 498 $ hg commit -A -m 'disappear draft' -q
513 499 $ echo 'addedcontADDEDentadded' > root
514 500 commit will cause merge conflict on rebase
515 501 $ hg commit -m 'add content draft' -q
516 502
517 503 $ hg rebase -d 'public()' --tool :merge -q
518 504 note: not rebasing 3:0682fd3dabf5 "disappear draft", its destination already has all its changes
519 505 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
520 506 unresolved conflicts (see hg resolve, then hg rebase --continue)
521 507 [1]
522 508 $ hg abort
523 509 rebase aborted
524 510 $ cd ..
525 511
@@ -1,803 +1,795 b''
1 1 test that a commit clears the merge state.
2 2
3 3 $ hg init repo
4 4 $ cd repo
5 5
6 6 $ echo foo > file1
7 7 $ echo foo > file2
8 8 $ hg commit -Am 'add files'
9 9 adding file1
10 10 adding file2
11 11
12 12 $ echo bar >> file1
13 13 $ echo bar >> file2
14 14 $ hg commit -Am 'append bar to files'
15 15
16 16 create a second head with conflicting edits
17 17
18 18 $ hg up -C 0
19 19 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 20 $ echo baz >> file1
21 21 $ echo baz >> file2
22 22 $ hg commit -Am 'append baz to files'
23 23 created new head
24 24
25 25 create a third head with no conflicting edits
26 26 $ hg up -qC 0
27 27 $ echo foo > file3
28 28 $ hg commit -Am 'add non-conflicting file'
29 29 adding file3
30 30 created new head
31 31
32 32 failing merge
33 33
34 34 $ hg up -qC 2
35 35 $ hg merge --tool=internal:fail 1
36 36 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
37 37 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
38 38 [1]
39 39
40 40 resolve -l should contain unresolved entries
41 41
42 42 $ hg resolve -l
43 43 U file1
44 44 U file2
45 45
46 46 $ hg resolve -l --no-status
47 47 file1
48 48 file2
49 49
50 50 resolving an unknown path should emit a warning, but not for -l
51 51
52 52 $ hg resolve -m does-not-exist
53 53 arguments do not match paths that need resolving
54 54 $ hg resolve -l does-not-exist
55 55
56 56 tell users how they could have used resolve
57 57
58 58 $ mkdir nested
59 59 $ cd nested
60 60 $ hg resolve -m file1
61 61 arguments do not match paths that need resolving
62 62 (try: hg resolve -m path:file1)
63 63 $ hg resolve -m file1 filez
64 64 arguments do not match paths that need resolving
65 65 (try: hg resolve -m path:file1 path:filez)
66 66 $ hg resolve -m path:file1 path:filez
67 67 $ hg resolve -l
68 68 R file1
69 69 U file2
70 70 $ hg resolve -l --config ui.relative-paths=yes
71 71 R ../file1
72 72 U ../file2
73 73 $ hg resolve --re-merge filez file2
74 74 arguments do not match paths that need resolving
75 75 (try: hg resolve --re-merge path:filez path:file2)
76 76 $ hg resolve -m filez file2
77 77 arguments do not match paths that need resolving
78 78 (try: hg resolve -m path:filez path:file2)
79 79 $ hg resolve -m path:filez path:file2
80 80 (no more unresolved files)
81 81 $ hg resolve -l
82 82 R file1
83 83 R file2
84 84
85 85 cleanup
86 86 $ hg resolve -u
87 87 $ cd ..
88 88 $ rmdir nested
89 89
90 90 don't allow marking or unmarking driver-resolved files
91 91
92 92 $ cat > $TESTTMP/markdriver.py << EOF
93 93 > '''mark and unmark files as driver-resolved'''
94 94 > from mercurial import (
95 95 > merge,
96 96 > pycompat,
97 97 > registrar,
98 98 > scmutil,
99 99 > )
100 100 > cmdtable = {}
101 101 > command = registrar.command(cmdtable)
102 102 > @command(b'markdriver',
103 103 > [(b'u', b'unmark', None, b'')],
104 104 > b'FILE...')
105 105 > def markdriver(ui, repo, *pats, **opts):
106 106 > wlock = repo.wlock()
107 107 > opts = pycompat.byteskwargs(opts)
108 108 > try:
109 109 > ms = merge.mergestate.read(repo)
110 110 > m = scmutil.match(repo[None], pats, opts)
111 111 > for f in ms:
112 112 > if not m(f):
113 113 > continue
114 114 > if not opts[b'unmark']:
115 115 > ms.mark(f, b'd')
116 116 > else:
117 117 > ms.mark(f, b'u')
118 118 > ms.commit()
119 119 > finally:
120 120 > wlock.release()
121 121 > EOF
122 122 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver file1
123 123 $ hg resolve --list
124 124 D file1
125 125 U file2
126 126 $ hg resolve --mark file1
127 127 not marking file1 as it is driver-resolved
128 128 this should not print out file1
129 129 $ hg resolve --mark --all
130 130 (no more unresolved files -- run "hg resolve --all" to conclude)
131 131 $ hg resolve --mark 'glob:file*'
132 132 (no more unresolved files -- run "hg resolve --all" to conclude)
133 133 $ hg resolve --list
134 134 D file1
135 135 R file2
136 136 $ hg resolve --unmark file1
137 137 not unmarking file1 as it is driver-resolved
138 138 (no more unresolved files -- run "hg resolve --all" to conclude)
139 139 $ hg resolve --unmark --all
140 140 $ hg resolve --list
141 141 D file1
142 142 U file2
143 143 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver --unmark file1
144 144 $ hg resolve --list
145 145 U file1
146 146 U file2
147 147
148 148 resolve the failure
149 149
150 150 $ echo resolved > file1
151 151 $ hg resolve -m file1
152 152
153 153 resolve -l should show resolved file as resolved
154 154
155 155 $ hg resolve -l
156 156 R file1
157 157 U file2
158 158
159 159 $ hg resolve -l -Tjson
160 160 [
161 161 {
162 162 "mergestatus": "R",
163 163 "path": "file1"
164 164 },
165 165 {
166 166 "mergestatus": "U",
167 167 "path": "file2"
168 168 }
169 169 ]
170 170
171 171 $ hg resolve -l -T '{path} {mergestatus} {status} {p1rev} {p2rev}\n'
172 172 file1 R M 2 1
173 173 file2 U M 2 1
174 174
175 175 resolve -m without paths should mark all resolved
176 176
177 177 $ hg resolve -m
178 178 (no more unresolved files)
179 179 $ hg commit -m 'resolved'
180 180
181 181 resolve -l should be empty after commit
182 182
183 183 $ hg resolve -l
184 184
185 185 $ hg resolve -l -Tjson
186 186 [
187 187 ]
188 188
189 189 resolve --all should abort when no merge in progress
190 190
191 191 $ hg resolve --all
192 192 abort: resolve command not applicable when not merging
193 193 [255]
194 194
195 195 resolve -m should abort when no merge in progress
196 196
197 197 $ hg resolve -m
198 198 abort: resolve command not applicable when not merging
199 199 [255]
200 200
201 201 can not update or merge when there are unresolved conflicts
202 202
203 203 $ hg up -qC 0
204 204 $ echo quux >> file1
205 205 $ hg up 1
206 206 merging file1
207 207 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
208 208 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
209 209 use 'hg resolve' to retry unresolved file merges
210 210 [1]
211 211 $ hg up 0
212 212 abort: outstanding merge conflicts
213 213 (use 'hg resolve' to resolve)
214 214 [255]
215 215 $ hg merge 2
216 216 abort: outstanding merge conflicts
217 217 (use 'hg resolve' to resolve)
218 218 [255]
219 219 $ hg merge --force 2
220 220 abort: outstanding merge conflicts
221 221 (use 'hg resolve' to resolve)
222 222 [255]
223 223
224 224 set up conflict-free merge
225 225
226 226 $ hg up -qC 3
227 227 $ hg merge 1
228 228 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 229 (branch merge, don't forget to commit)
230 230
231 231 resolve --all should do nothing in merge without conflicts
232 232 $ hg resolve --all
233 233 (no more unresolved files)
234 234
235 235 resolve -m should do nothing in merge without conflicts
236 236
237 237 $ hg resolve -m
238 238 (no more unresolved files)
239 239
240 240 get back to conflicting state
241 241
242 242 $ hg up -qC 2
243 243 $ hg merge --tool=internal:fail 1
244 244 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
245 245 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
246 246 [1]
247 247
248 248 resolve without arguments should suggest --all
249 249 $ hg resolve
250 250 abort: no files or directories specified
251 251 (use --all to re-merge all unresolved files)
252 252 [255]
253 253
254 254 resolve --all should re-merge all unresolved files
255 255 $ hg resolve --all
256 256 merging file1
257 257 merging file2
258 258 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
259 259 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
260 260 [1]
261 261 $ cat file1.orig
262 262 foo
263 263 baz
264 264 $ cat file2.orig
265 265 foo
266 266 baz
267 267
268 268 .orig files should exists where specified
269 269 $ hg resolve --all --verbose --config 'ui.origbackuppath=.hg/origbackups'
270 270 merging file1
271 271 creating directory: $TESTTMP/repo/.hg/origbackups
272 272 merging file2
273 273 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
274 274 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
275 275 [1]
276 276 $ ls .hg/origbackups
277 277 file1
278 278 file2
279 279 $ grep '<<<' file1 > /dev/null
280 280 $ grep '<<<' file2 > /dev/null
281 281
282 282 resolve <file> should re-merge file
283 283 $ echo resolved > file1
284 284 $ hg resolve -q file1
285 285 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
286 286 [1]
287 287 $ grep '<<<' file1 > /dev/null
288 288
289 289 test .orig behavior with resolve
290 290
291 291 $ hg resolve -q file1 --tool "sh -c 'f --dump \"$TESTTMP/repo/file1.orig\"'"
292 292 $TESTTMP/repo/file1.orig:
293 293 >>>
294 294 foo
295 295 baz
296 296 <<<
297 297
298 298 resolve <file> should do nothing if 'file' was marked resolved
299 299 $ echo resolved > file1
300 300 $ hg resolve -m file1
301 301 $ hg resolve -q file1
302 302 $ cat file1
303 303 resolved
304 304
305 305 insert unsupported advisory merge record
306 306
307 307 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
308 308 $ hg debugmergestate
309 * version 2 records
310 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
311 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
312 labels:
313 local: working copy
314 other: merge rev
315 unrecognized entry: x advisory record
316 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
317 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
309 local (working copy): 57653b9f834a4493f7240b0681efcb9ae7cab745
310 other (merge rev): dc77451844e37f03f5c559e3b8529b2b48d381d1
311 file: file1 (state "r")
318 312 local path: file1 (flags "")
319 313 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
320 314 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
321 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
322 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
315 extra: ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac
316 file: file2 (state "u")
323 317 local path: file2 (flags "")
324 318 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
325 319 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
320 extra: ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac
326 321 $ hg resolve -l
327 322 R file1
328 323 U file2
329 324
325 test json output
326
327 $ hg debugmergestate -T json
328 [
329 {
330 "commits": [{"label": "working copy", "name": "local", "node": "57653b9f834a4493f7240b0681efcb9ae7cab745"}, {"label": "merge rev", "name": "other", "node": "dc77451844e37f03f5c559e3b8529b2b48d381d1"}],
331 "files": [{"ancestor_node": "2ed2a3912a0b24502043eae84ee4b279c18b90dd", "ancestor_path": "file1", "extras": [{"key": "ancestorlinknode", "value": "99726c03216e233810a2564cbc0adfe395007eac"}], "local_flags": "", "local_key": "60b27f004e454aca81b0480209cce5081ec52390", "local_path": "file1", "other_node": "6f4310b00b9a147241b071a60c28a650827fb03d", "other_path": "file1", "path": "file1", "state": "r"}, {"ancestor_node": "2ed2a3912a0b24502043eae84ee4b279c18b90dd", "ancestor_path": "file2", "extras": [{"key": "ancestorlinknode", "value": "99726c03216e233810a2564cbc0adfe395007eac"}], "local_flags": "", "local_key": "cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523", "local_path": "file2", "other_node": "6f4310b00b9a147241b071a60c28a650827fb03d", "other_path": "file2", "path": "file2", "state": "u"}]
332 }
333 ]
334
335
330 336 insert unsupported mandatory merge record
331 337
332 338 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
333 339 $ hg debugmergestate
334 * version 2 records
335 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
336 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
337 labels:
338 local: working copy
339 other: merge rev
340 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
341 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
342 local path: file1 (flags "")
343 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
344 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
345 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
346 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
347 local path: file2 (flags "")
348 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
349 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
350 unrecognized entry: X mandatory record
340 abort: unsupported merge state records: X
341 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
342 [255]
351 343 $ hg resolve -l
352 344 abort: unsupported merge state records: X
353 345 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
354 346 [255]
355 347 $ hg resolve -ma
356 348 abort: unsupported merge state records: X
357 349 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
358 350 [255]
359 351 $ hg summary
360 352 warning: merge state has unsupported record types: X
361 353 parent: 2:57653b9f834a
362 354 append baz to files
363 355 parent: 1:dc77451844e3
364 356 append bar to files
365 357 branch: default
366 358 commit: 2 modified, 2 unknown (merge)
367 359 update: 2 new changesets (update)
368 360 phases: 5 draft
369 361
370 362 update --clean shouldn't abort on unsupported records
371 363
372 364 $ hg up -qC 1
373 365 $ hg debugmergestate
374 366 no merge state found
375 367
376 368 test crashed merge with empty mergestate
377 369
378 370 $ mkdir .hg/merge
379 371 $ touch .hg/merge/state
380 372
381 373 resolve -l should be empty
382 374
383 375 $ hg resolve -l
384 376
385 377 resolve -m can be configured to look for remaining conflict markers
386 378 $ hg up -qC 2
387 379 $ hg merge -q --tool=internal:merge 1
388 380 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
389 381 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
390 382 [1]
391 383 $ hg resolve -l
392 384 U file1
393 385 U file2
394 386 $ echo 'remove markers' > file1
395 387 $ hg --config commands.resolve.mark-check=abort resolve -m
396 388 warning: the following files still have conflict markers:
397 389 file2
398 390 abort: conflict markers detected
399 391 (use --all to mark anyway)
400 392 [255]
401 393 $ hg resolve -l
402 394 U file1
403 395 U file2
404 396 Try with --all from the hint
405 397 $ hg --config commands.resolve.mark-check=abort resolve -m --all
406 398 warning: the following files still have conflict markers:
407 399 file2
408 400 (no more unresolved files)
409 401 $ hg resolve -l
410 402 R file1
411 403 R file2
412 404 Test option value 'warn'
413 405 $ hg resolve --unmark
414 406 $ hg resolve -l
415 407 U file1
416 408 U file2
417 409 $ hg --config commands.resolve.mark-check=warn resolve -m
418 410 warning: the following files still have conflict markers:
419 411 file2
420 412 (no more unresolved files)
421 413 $ hg resolve -l
422 414 R file1
423 415 R file2
424 416 If the file is already marked as resolved, we don't warn about it
425 417 $ hg resolve --unmark file1
426 418 $ hg resolve -l
427 419 U file1
428 420 R file2
429 421 $ hg --config commands.resolve.mark-check=warn resolve -m
430 422 (no more unresolved files)
431 423 $ hg resolve -l
432 424 R file1
433 425 R file2
434 426 If the user passes an invalid value, we treat it as 'none'.
435 427 $ hg resolve --unmark
436 428 $ hg resolve -l
437 429 U file1
438 430 U file2
439 431 $ hg --config commands.resolve.mark-check=nope resolve -m
440 432 (no more unresolved files)
441 433 $ hg resolve -l
442 434 R file1
443 435 R file2
444 436 Test explicitly setting the option to 'none'
445 437 $ hg resolve --unmark
446 438 $ hg resolve -l
447 439 U file1
448 440 U file2
449 441 $ hg --config commands.resolve.mark-check=none resolve -m
450 442 (no more unresolved files)
451 443 $ hg resolve -l
452 444 R file1
453 445 R file2
454 446 Test with marking an explicit file as resolved, this should not abort (since
455 447 there's no --force flag, we have no way of combining --all with a filename)
456 448 $ hg resolve --unmark
457 449 $ hg resolve -l
458 450 U file1
459 451 U file2
460 452 (This downgrades to a warning since an explicit file was specified).
461 453 $ hg --config commands.resolve.mark-check=abort resolve -m file2
462 454 warning: the following files still have conflict markers:
463 455 file2
464 456 $ hg resolve -l
465 457 U file1
466 458 R file2
467 459 Testing the --re-merge flag
468 460 $ hg resolve --unmark file1
469 461 $ hg resolve -l
470 462 U file1
471 463 R file2
472 464 $ hg resolve --mark --re-merge
473 465 abort: too many actions specified
474 466 [255]
475 467 $ hg resolve --re-merge --all
476 468 merging file1
477 469 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
478 470 [1]
479 471 Explicit re-merge
480 472 $ hg resolve --unmark file1
481 473 $ hg resolve --config commands.resolve.explicit-re-merge=1 --all
482 474 abort: no action specified
483 475 (use --mark, --unmark, --list or --re-merge)
484 476 [255]
485 477 $ hg resolve --config commands.resolve.explicit-re-merge=1 --re-merge --all
486 478 merging file1
487 479 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
488 480 [1]
489 481
490 482 $ cd ..
491 483
492 484 ======================================================
493 485 Test 'hg resolve' confirm config option functionality |
494 486 ======================================================
495 487 $ cat >> $HGRCPATH << EOF
496 488 > [extensions]
497 489 > rebase=
498 490 > EOF
499 491
500 492 $ hg init repo2
501 493 $ cd repo2
502 494
503 495 $ echo boss > boss
504 496 $ hg ci -Am "add boss"
505 497 adding boss
506 498
507 499 $ for emp in emp1 emp2 emp3; do echo work > $emp; done;
508 500 $ hg ci -Aqm "added emp1 emp2 emp3"
509 501
510 502 $ hg up 0
511 503 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
512 504
513 505 $ for emp in emp1 emp2 emp3; do echo nowork > $emp; done;
514 506 $ hg ci -Aqm "added lazy emp1 emp2 emp3"
515 507
516 508 $ hg log -GT "{rev} {node|short} {firstline(desc)}\n"
517 509 @ 2 0acfd4a49af0 added lazy emp1 emp2 emp3
518 510 |
519 511 | o 1 f30f98a8181f added emp1 emp2 emp3
520 512 |/
521 513 o 0 88660038d466 add boss
522 514
523 515 $ hg rebase -s 1 -d 2
524 516 rebasing 1:f30f98a8181f "added emp1 emp2 emp3"
525 517 merging emp1
526 518 merging emp2
527 519 merging emp3
528 520 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
529 521 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
530 522 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
531 523 unresolved conflicts (see hg resolve, then hg rebase --continue)
532 524 [1]
533 525
534 526 Test when commands.resolve.confirm config option is not set:
535 527 ===========================================================
536 528 $ hg resolve --all
537 529 merging emp1
538 530 merging emp2
539 531 merging emp3
540 532 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
541 533 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
542 534 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
543 535 [1]
544 536
545 537 Test when config option is set:
546 538 ==============================
547 539 $ cat >> .hg/hgrc << EOF
548 540 > [ui]
549 541 > interactive = True
550 542 > [commands]
551 543 > resolve.confirm = True
552 544 > EOF
553 545
554 546 $ hg resolve
555 547 abort: no files or directories specified
556 548 (use --all to re-merge all unresolved files)
557 549 [255]
558 550 $ hg resolve --all << EOF
559 551 > n
560 552 > EOF
561 553 re-merge all unresolved files (yn)? n
562 554 abort: user quit
563 555 [255]
564 556
565 557 $ hg resolve --all << EOF
566 558 > y
567 559 > EOF
568 560 re-merge all unresolved files (yn)? y
569 561 merging emp1
570 562 merging emp2
571 563 merging emp3
572 564 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
573 565 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
574 566 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
575 567 [1]
576 568
577 569 Test that commands.resolve.confirm respect --mark option (only when no patterns args are given):
578 570 ===============================================================================================
579 571
580 572 $ hg resolve -m emp1
581 573 $ hg resolve -l
582 574 R emp1
583 575 U emp2
584 576 U emp3
585 577
586 578 $ hg resolve -m << EOF
587 579 > n
588 580 > EOF
589 581 mark all unresolved files as resolved (yn)? n
590 582 abort: user quit
591 583 [255]
592 584
593 585 $ hg resolve -m << EOF
594 586 > y
595 587 > EOF
596 588 mark all unresolved files as resolved (yn)? y
597 589 (no more unresolved files)
598 590 continue: hg rebase --continue
599 591 $ hg resolve -l
600 592 R emp1
601 593 R emp2
602 594 R emp3
603 595
604 596 Test that commands.resolve.confirm respect --unmark option (only when no patterns args are given):
605 597 =================================================================================================
606 598
607 599 $ hg resolve -u emp1
608 600
609 601 $ hg resolve -l
610 602 U emp1
611 603 R emp2
612 604 R emp3
613 605
614 606 $ hg resolve -u << EOF
615 607 > n
616 608 > EOF
617 609 mark all resolved files as unresolved (yn)? n
618 610 abort: user quit
619 611 [255]
620 612
621 613 $ hg resolve -m << EOF
622 614 > y
623 615 > EOF
624 616 mark all unresolved files as resolved (yn)? y
625 617 (no more unresolved files)
626 618 continue: hg rebase --continue
627 619
628 620 $ hg resolve -l
629 621 R emp1
630 622 R emp2
631 623 R emp3
632 624
633 625 $ hg rebase --abort
634 626 rebase aborted
635 627
636 628 Done with commands.resolve.confirm tests:
637 629 $ cd ..
638 630
639 631 Test that commands.resolve.mark-check works even if there are deleted files:
640 632 $ hg init resolve-deleted
641 633 $ cd resolve-deleted
642 634 $ echo r0 > file1
643 635 $ hg ci -qAm r0
644 636 $ echo r1 > file1
645 637 $ hg ci -qm r1
646 638 $ hg co -qr 0
647 639 $ hg rm file1
648 640 $ hg ci -qm "r2 (delete file1)"
649 641
650 642 (At this point we have r0 creating file1, and sibling commits r1 and r2, which
651 643 modify and delete file1, respectively)
652 644
653 645 $ hg merge -r 1
654 646 file 'file1' was deleted in local [working copy] but was modified in other [merge rev].
655 647 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
656 648 What do you want to do? u
657 649 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
658 650 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
659 651 [1]
660 652 $ hg resolve --list
661 653 U file1
662 654 Because we left it as 'unresolved' the file should still exist.
663 655 $ [ -f file1 ] || echo "File does not exist?"
664 656 BC behavior: `hg resolve --mark` accepts that the file is still there, and
665 657 doesn't have a problem with this situation.
666 658 $ hg resolve --mark --config commands.resolve.mark-check=abort
667 659 (no more unresolved files)
668 660 $ hg resolve --list
669 661 R file1
670 662 The file is still there:
671 663 $ [ -f file1 ] || echo "File does not exist?"
672 664 Let's check mark-check=warn:
673 665 $ hg resolve --unmark file1
674 666 $ hg resolve --mark --config commands.resolve.mark-check=warn
675 667 (no more unresolved files)
676 668 $ hg resolve --list
677 669 R file1
678 670 The file is still there:
679 671 $ [ -f file1 ] || echo "File does not exist?"
680 672 Let's resolve the issue by deleting the file via `hg resolve`
681 673 $ hg resolve --unmark file1
682 674 $ echo 'd' | hg resolve file1 --config ui.interactive=1
683 675 file 'file1' was deleted in local [working copy] but was modified in other [merge rev].
684 676 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
685 677 What do you want to do? d
686 678 (no more unresolved files)
687 679 $ hg resolve --list
688 680 R file1
689 681 The file is deleted:
690 682 $ [ -f file1 ] && echo "File still exists?" || true
691 683 Doing `hg resolve --mark` doesn't break now that the file is missing:
692 684 $ hg resolve --mark --config commands.resolve.mark-check=abort
693 685 (no more unresolved files)
694 686 $ hg resolve --mark --config commands.resolve.mark-check=warn
695 687 (no more unresolved files)
696 688 Resurrect the file, and delete it outside of hg:
697 689 $ hg resolve --unmark file1
698 690 $ hg resolve file1
699 691 file 'file1' was deleted in local [working copy] but was modified in other [merge rev].
700 692 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
701 693 What do you want to do? u
702 694 [1]
703 695 $ [ -f file1 ] || echo "File does not exist?"
704 696 $ hg resolve --list
705 697 U file1
706 698 $ rm file1
707 699 $ hg resolve --mark --config commands.resolve.mark-check=abort
708 700 (no more unresolved files)
709 701 $ hg resolve --list
710 702 R file1
711 703 $ hg resolve --unmark file1
712 704 $ hg resolve file1
713 705 file 'file1' was deleted in local [working copy] but was modified in other [merge rev].
714 706 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
715 707 What do you want to do? u
716 708 [1]
717 709 $ [ -f file1 ] || echo "File does not exist?"
718 710 $ hg resolve --list
719 711 U file1
720 712 $ rm file1
721 713 $ hg resolve --mark --config commands.resolve.mark-check=warn
722 714 (no more unresolved files)
723 715 $ hg resolve --list
724 716 R file1
725 717
726 718
727 719 For completeness, let's try that in the opposite direction (merging r2 into r1,
728 720 instead of r1 into r2):
729 721 $ hg update -qCr 1
730 722 $ hg merge -r 2
731 723 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
732 724 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
733 725 What do you want to do? u
734 726 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
735 727 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
736 728 [1]
737 729 $ hg resolve --list
738 730 U file1
739 731 Because we left it as 'unresolved' the file should still exist.
740 732 $ [ -f file1 ] || echo "File does not exist?"
741 733 BC behavior: `hg resolve --mark` accepts that the file is still there, and
742 734 doesn't have a problem with this situation.
743 735 $ hg resolve --mark --config commands.resolve.mark-check=abort
744 736 (no more unresolved files)
745 737 $ hg resolve --list
746 738 R file1
747 739 The file is still there:
748 740 $ [ -f file1 ] || echo "File does not exist?"
749 741 Let's check mark-check=warn:
750 742 $ hg resolve --unmark file1
751 743 $ hg resolve --mark --config commands.resolve.mark-check=warn
752 744 (no more unresolved files)
753 745 $ hg resolve --list
754 746 R file1
755 747 The file is still there:
756 748 $ [ -f file1 ] || echo "File does not exist?"
757 749 Let's resolve the issue by deleting the file via `hg resolve`
758 750 $ hg resolve --unmark file1
759 751 $ echo 'd' | hg resolve file1 --config ui.interactive=1
760 752 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
761 753 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
762 754 What do you want to do? d
763 755 (no more unresolved files)
764 756 $ hg resolve --list
765 757 R file1
766 758 The file is deleted:
767 759 $ [ -f file1 ] && echo "File still exists?" || true
768 760 Doing `hg resolve --mark` doesn't break now that the file is missing:
769 761 $ hg resolve --mark --config commands.resolve.mark-check=abort
770 762 (no more unresolved files)
771 763 $ hg resolve --mark --config commands.resolve.mark-check=warn
772 764 (no more unresolved files)
773 765 Resurrect the file, and delete it outside of hg:
774 766 $ hg resolve --unmark file1
775 767 $ hg resolve file1
776 768 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
777 769 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
778 770 What do you want to do? u
779 771 [1]
780 772 $ [ -f file1 ] || echo "File does not exist?"
781 773 $ hg resolve --list
782 774 U file1
783 775 $ rm file1
784 776 $ hg resolve --mark --config commands.resolve.mark-check=abort
785 777 (no more unresolved files)
786 778 $ hg resolve --list
787 779 R file1
788 780 $ hg resolve --unmark file1
789 781 $ hg resolve file1
790 782 file 'file1' was deleted in other [merge rev] but was modified in local [working copy].
791 783 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
792 784 What do you want to do? u
793 785 [1]
794 786 $ [ -f file1 ] || echo "File does not exist?"
795 787 $ hg resolve --list
796 788 U file1
797 789 $ rm file1
798 790 $ hg resolve --mark --config commands.resolve.mark-check=warn
799 791 (no more unresolved files)
800 792 $ hg resolve --list
801 793 R file1
802 794
803 795 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now