##// END OF EJS Templates
formatter: remove experimental marker from -T option...
Yuya Nishihara -
r39967:0d703063 default
parent child Browse files
Show More
@@ -1,3313 +1,3312 b''
1 1 # cmdutil.py - help for command processing in mercurial
2 2 #
3 3 # Copyright 2005-2007 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 errno
11 11 import os
12 12 import re
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 hex,
17 17 nullid,
18 18 nullrev,
19 19 short,
20 20 )
21 21
22 22 from . import (
23 23 bookmarks,
24 24 changelog,
25 25 copies,
26 26 crecord as crecordmod,
27 27 dirstateguard,
28 28 encoding,
29 29 error,
30 30 formatter,
31 31 logcmdutil,
32 32 match as matchmod,
33 33 merge as mergemod,
34 34 mergeutil,
35 35 obsolete,
36 36 patch,
37 37 pathutil,
38 38 phases,
39 39 pycompat,
40 40 revlog,
41 41 rewriteutil,
42 42 scmutil,
43 43 smartset,
44 44 subrepoutil,
45 45 templatekw,
46 46 templater,
47 47 util,
48 48 vfs as vfsmod,
49 49 )
50 50
51 51 from .utils import (
52 52 dateutil,
53 53 stringutil,
54 54 )
55 55
56 56 stringio = util.stringio
57 57
58 58 # templates of common command options
59 59
60 60 dryrunopts = [
61 61 ('n', 'dry-run', None,
62 62 _('do not perform actions, just print output')),
63 63 ]
64 64
65 65 confirmopts = [
66 66 ('', 'confirm', None,
67 67 _('ask before applying actions')),
68 68 ]
69 69
70 70 remoteopts = [
71 71 ('e', 'ssh', '',
72 72 _('specify ssh command to use'), _('CMD')),
73 73 ('', 'remotecmd', '',
74 74 _('specify hg command to run on the remote side'), _('CMD')),
75 75 ('', 'insecure', None,
76 76 _('do not verify server certificate (ignoring web.cacerts config)')),
77 77 ]
78 78
79 79 walkopts = [
80 80 ('I', 'include', [],
81 81 _('include names matching the given patterns'), _('PATTERN')),
82 82 ('X', 'exclude', [],
83 83 _('exclude names matching the given patterns'), _('PATTERN')),
84 84 ]
85 85
86 86 commitopts = [
87 87 ('m', 'message', '',
88 88 _('use text as commit message'), _('TEXT')),
89 89 ('l', 'logfile', '',
90 90 _('read commit message from file'), _('FILE')),
91 91 ]
92 92
93 93 commitopts2 = [
94 94 ('d', 'date', '',
95 95 _('record the specified date as commit date'), _('DATE')),
96 96 ('u', 'user', '',
97 97 _('record the specified user as committer'), _('USER')),
98 98 ]
99 99
100 # hidden for now
101 100 formatteropts = [
102 101 ('T', 'template', '',
103 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
102 _('display with template'), _('TEMPLATE')),
104 103 ]
105 104
106 105 templateopts = [
107 106 ('', 'style', '',
108 107 _('display using template map file (DEPRECATED)'), _('STYLE')),
109 108 ('T', 'template', '',
110 109 _('display with template'), _('TEMPLATE')),
111 110 ]
112 111
113 112 logopts = [
114 113 ('p', 'patch', None, _('show patch')),
115 114 ('g', 'git', None, _('use git extended diff format')),
116 115 ('l', 'limit', '',
117 116 _('limit number of changes displayed'), _('NUM')),
118 117 ('M', 'no-merges', None, _('do not show merges')),
119 118 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 119 ('G', 'graph', None, _("show the revision DAG")),
121 120 ] + templateopts
122 121
123 122 diffopts = [
124 123 ('a', 'text', None, _('treat all files as text')),
125 124 ('g', 'git', None, _('use git extended diff format')),
126 125 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
127 126 ('', 'nodates', None, _('omit dates from diff headers'))
128 127 ]
129 128
130 129 diffwsopts = [
131 130 ('w', 'ignore-all-space', None,
132 131 _('ignore white space when comparing lines')),
133 132 ('b', 'ignore-space-change', None,
134 133 _('ignore changes in the amount of white space')),
135 134 ('B', 'ignore-blank-lines', None,
136 135 _('ignore changes whose lines are all blank')),
137 136 ('Z', 'ignore-space-at-eol', None,
138 137 _('ignore changes in whitespace at EOL')),
139 138 ]
140 139
141 140 diffopts2 = [
142 141 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
143 142 ('p', 'show-function', None, _('show which function each change is in')),
144 143 ('', 'reverse', None, _('produce a diff that undoes the changes')),
145 144 ] + diffwsopts + [
146 145 ('U', 'unified', '',
147 146 _('number of lines of context to show'), _('NUM')),
148 147 ('', 'stat', None, _('output diffstat-style summary of changes')),
149 148 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
150 149 ]
151 150
152 151 mergetoolopts = [
153 152 ('t', 'tool', '', _('specify merge tool')),
154 153 ]
155 154
156 155 similarityopts = [
157 156 ('s', 'similarity', '',
158 157 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
159 158 ]
160 159
161 160 subrepoopts = [
162 161 ('S', 'subrepos', None,
163 162 _('recurse into subrepositories'))
164 163 ]
165 164
166 165 debugrevlogopts = [
167 166 ('c', 'changelog', False, _('open changelog')),
168 167 ('m', 'manifest', False, _('open manifest')),
169 168 ('', 'dir', '', _('open directory manifest')),
170 169 ]
171 170
172 171 # special string such that everything below this line will be ingored in the
173 172 # editor text
174 173 _linebelow = "^HG: ------------------------ >8 ------------------------$"
175 174
176 175 def ishunk(x):
177 176 hunkclasses = (crecordmod.uihunk, patch.recordhunk)
178 177 return isinstance(x, hunkclasses)
179 178
180 179 def newandmodified(chunks, originalchunks):
181 180 newlyaddedandmodifiedfiles = set()
182 181 for chunk in chunks:
183 182 if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
184 183 originalchunks:
185 184 newlyaddedandmodifiedfiles.add(chunk.header.filename())
186 185 return newlyaddedandmodifiedfiles
187 186
188 187 def parsealiases(cmd):
189 188 return cmd.lstrip("^").split("|")
190 189
191 190 def setupwrapcolorwrite(ui):
192 191 # wrap ui.write so diff output can be labeled/colorized
193 192 def wrapwrite(orig, *args, **kw):
194 193 label = kw.pop(r'label', '')
195 194 for chunk, l in patch.difflabel(lambda: args):
196 195 orig(chunk, label=label + l)
197 196
198 197 oldwrite = ui.write
199 198 def wrap(*args, **kwargs):
200 199 return wrapwrite(oldwrite, *args, **kwargs)
201 200 setattr(ui, 'write', wrap)
202 201 return oldwrite
203 202
204 203 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
205 204 try:
206 205 if usecurses:
207 206 if testfile:
208 207 recordfn = crecordmod.testdecorator(
209 208 testfile, crecordmod.testchunkselector)
210 209 else:
211 210 recordfn = crecordmod.chunkselector
212 211
213 212 return crecordmod.filterpatch(ui, originalhunks, recordfn,
214 213 operation)
215 214 except crecordmod.fallbackerror as e:
216 215 ui.warn('%s\n' % e.message)
217 216 ui.warn(_('falling back to text mode\n'))
218 217
219 218 return patch.filterpatch(ui, originalhunks, operation)
220 219
221 220 def recordfilter(ui, originalhunks, operation=None):
222 221 """ Prompts the user to filter the originalhunks and return a list of
223 222 selected hunks.
224 223 *operation* is used for to build ui messages to indicate the user what
225 224 kind of filtering they are doing: reverting, committing, shelving, etc.
226 225 (see patch.filterpatch).
227 226 """
228 227 usecurses = crecordmod.checkcurses(ui)
229 228 testfile = ui.config('experimental', 'crecordtest')
230 229 oldwrite = setupwrapcolorwrite(ui)
231 230 try:
232 231 newchunks, newopts = filterchunks(ui, originalhunks, usecurses,
233 232 testfile, operation)
234 233 finally:
235 234 ui.write = oldwrite
236 235 return newchunks, newopts
237 236
238 237 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
239 238 filterfn, *pats, **opts):
240 239 opts = pycompat.byteskwargs(opts)
241 240 if not ui.interactive():
242 241 if cmdsuggest:
243 242 msg = _('running non-interactively, use %s instead') % cmdsuggest
244 243 else:
245 244 msg = _('running non-interactively')
246 245 raise error.Abort(msg)
247 246
248 247 # make sure username is set before going interactive
249 248 if not opts.get('user'):
250 249 ui.username() # raise exception, username not provided
251 250
252 251 def recordfunc(ui, repo, message, match, opts):
253 252 """This is generic record driver.
254 253
255 254 Its job is to interactively filter local changes, and
256 255 accordingly prepare working directory into a state in which the
257 256 job can be delegated to a non-interactive commit command such as
258 257 'commit' or 'qrefresh'.
259 258
260 259 After the actual job is done by non-interactive command, the
261 260 working directory is restored to its original state.
262 261
263 262 In the end we'll record interesting changes, and everything else
264 263 will be left in place, so the user can continue working.
265 264 """
266 265
267 266 checkunfinished(repo, commit=True)
268 267 wctx = repo[None]
269 268 merge = len(wctx.parents()) > 1
270 269 if merge:
271 270 raise error.Abort(_('cannot partially commit a merge '
272 271 '(use "hg commit" instead)'))
273 272
274 273 def fail(f, msg):
275 274 raise error.Abort('%s: %s' % (f, msg))
276 275
277 276 force = opts.get('force')
278 277 if not force:
279 278 vdirs = []
280 279 match.explicitdir = vdirs.append
281 280 match.bad = fail
282 281
283 282 status = repo.status(match=match)
284 283 if not force:
285 284 repo.checkcommitpatterns(wctx, vdirs, match, status, fail)
286 285 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
287 286 diffopts.nodates = True
288 287 diffopts.git = True
289 288 diffopts.showfunc = True
290 289 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
291 290 originalchunks = patch.parsepatch(originaldiff)
292 291
293 292 # 1. filter patch, since we are intending to apply subset of it
294 293 try:
295 294 chunks, newopts = filterfn(ui, originalchunks)
296 295 except error.PatchError as err:
297 296 raise error.Abort(_('error parsing patch: %s') % err)
298 297 opts.update(newopts)
299 298
300 299 # We need to keep a backup of files that have been newly added and
301 300 # modified during the recording process because there is a previous
302 301 # version without the edit in the workdir
303 302 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
304 303 contenders = set()
305 304 for h in chunks:
306 305 try:
307 306 contenders.update(set(h.files()))
308 307 except AttributeError:
309 308 pass
310 309
311 310 changed = status.modified + status.added + status.removed
312 311 newfiles = [f for f in changed if f in contenders]
313 312 if not newfiles:
314 313 ui.status(_('no changes to record\n'))
315 314 return 0
316 315
317 316 modified = set(status.modified)
318 317
319 318 # 2. backup changed files, so we can restore them in the end
320 319
321 320 if backupall:
322 321 tobackup = changed
323 322 else:
324 323 tobackup = [f for f in newfiles if f in modified or f in \
325 324 newlyaddedandmodifiedfiles]
326 325 backups = {}
327 326 if tobackup:
328 327 backupdir = repo.vfs.join('record-backups')
329 328 try:
330 329 os.mkdir(backupdir)
331 330 except OSError as err:
332 331 if err.errno != errno.EEXIST:
333 332 raise
334 333 try:
335 334 # backup continues
336 335 for f in tobackup:
337 336 fd, tmpname = pycompat.mkstemp(prefix=f.replace('/', '_') + '.',
338 337 dir=backupdir)
339 338 os.close(fd)
340 339 ui.debug('backup %r as %r\n' % (f, tmpname))
341 340 util.copyfile(repo.wjoin(f), tmpname, copystat=True)
342 341 backups[f] = tmpname
343 342
344 343 fp = stringio()
345 344 for c in chunks:
346 345 fname = c.filename()
347 346 if fname in backups:
348 347 c.write(fp)
349 348 dopatch = fp.tell()
350 349 fp.seek(0)
351 350
352 351 # 2.5 optionally review / modify patch in text editor
353 352 if opts.get('review', False):
354 353 patchtext = (crecordmod.diffhelptext
355 354 + crecordmod.patchhelptext
356 355 + fp.read())
357 356 reviewedpatch = ui.edit(patchtext, "",
358 357 action="diff",
359 358 repopath=repo.path)
360 359 fp.truncate(0)
361 360 fp.write(reviewedpatch)
362 361 fp.seek(0)
363 362
364 363 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
365 364 # 3a. apply filtered patch to clean repo (clean)
366 365 if backups:
367 366 # Equivalent to hg.revert
368 367 m = scmutil.matchfiles(repo, backups.keys())
369 368 mergemod.update(repo, repo.dirstate.p1(),
370 369 False, True, matcher=m)
371 370
372 371 # 3b. (apply)
373 372 if dopatch:
374 373 try:
375 374 ui.debug('applying patch\n')
376 375 ui.debug(fp.getvalue())
377 376 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
378 377 except error.PatchError as err:
379 378 raise error.Abort(pycompat.bytestr(err))
380 379 del fp
381 380
382 381 # 4. We prepared working directory according to filtered
383 382 # patch. Now is the time to delegate the job to
384 383 # commit/qrefresh or the like!
385 384
386 385 # Make all of the pathnames absolute.
387 386 newfiles = [repo.wjoin(nf) for nf in newfiles]
388 387 return commitfunc(ui, repo, *newfiles, **pycompat.strkwargs(opts))
389 388 finally:
390 389 # 5. finally restore backed-up files
391 390 try:
392 391 dirstate = repo.dirstate
393 392 for realname, tmpname in backups.iteritems():
394 393 ui.debug('restoring %r to %r\n' % (tmpname, realname))
395 394
396 395 if dirstate[realname] == 'n':
397 396 # without normallookup, restoring timestamp
398 397 # may cause partially committed files
399 398 # to be treated as unmodified
400 399 dirstate.normallookup(realname)
401 400
402 401 # copystat=True here and above are a hack to trick any
403 402 # editors that have f open that we haven't modified them.
404 403 #
405 404 # Also note that this racy as an editor could notice the
406 405 # file's mtime before we've finished writing it.
407 406 util.copyfile(tmpname, repo.wjoin(realname), copystat=True)
408 407 os.unlink(tmpname)
409 408 if tobackup:
410 409 os.rmdir(backupdir)
411 410 except OSError:
412 411 pass
413 412
414 413 def recordinwlock(ui, repo, message, match, opts):
415 414 with repo.wlock():
416 415 return recordfunc(ui, repo, message, match, opts)
417 416
418 417 return commit(ui, repo, recordinwlock, pats, opts)
419 418
420 419 class dirnode(object):
421 420 """
422 421 Represent a directory in user working copy with information required for
423 422 the purpose of tersing its status.
424 423
425 424 path is the path to the directory, without a trailing '/'
426 425
427 426 statuses is a set of statuses of all files in this directory (this includes
428 427 all the files in all the subdirectories too)
429 428
430 429 files is a list of files which are direct child of this directory
431 430
432 431 subdirs is a dictionary of sub-directory name as the key and it's own
433 432 dirnode object as the value
434 433 """
435 434
436 435 def __init__(self, dirpath):
437 436 self.path = dirpath
438 437 self.statuses = set([])
439 438 self.files = []
440 439 self.subdirs = {}
441 440
442 441 def _addfileindir(self, filename, status):
443 442 """Add a file in this directory as a direct child."""
444 443 self.files.append((filename, status))
445 444
446 445 def addfile(self, filename, status):
447 446 """
448 447 Add a file to this directory or to its direct parent directory.
449 448
450 449 If the file is not direct child of this directory, we traverse to the
451 450 directory of which this file is a direct child of and add the file
452 451 there.
453 452 """
454 453
455 454 # the filename contains a path separator, it means it's not the direct
456 455 # child of this directory
457 456 if '/' in filename:
458 457 subdir, filep = filename.split('/', 1)
459 458
460 459 # does the dirnode object for subdir exists
461 460 if subdir not in self.subdirs:
462 461 subdirpath = pathutil.join(self.path, subdir)
463 462 self.subdirs[subdir] = dirnode(subdirpath)
464 463
465 464 # try adding the file in subdir
466 465 self.subdirs[subdir].addfile(filep, status)
467 466
468 467 else:
469 468 self._addfileindir(filename, status)
470 469
471 470 if status not in self.statuses:
472 471 self.statuses.add(status)
473 472
474 473 def iterfilepaths(self):
475 474 """Yield (status, path) for files directly under this directory."""
476 475 for f, st in self.files:
477 476 yield st, pathutil.join(self.path, f)
478 477
479 478 def tersewalk(self, terseargs):
480 479 """
481 480 Yield (status, path) obtained by processing the status of this
482 481 dirnode.
483 482
484 483 terseargs is the string of arguments passed by the user with `--terse`
485 484 flag.
486 485
487 486 Following are the cases which can happen:
488 487
489 488 1) All the files in the directory (including all the files in its
490 489 subdirectories) share the same status and the user has asked us to terse
491 490 that status. -> yield (status, dirpath). dirpath will end in '/'.
492 491
493 492 2) Otherwise, we do following:
494 493
495 494 a) Yield (status, filepath) for all the files which are in this
496 495 directory (only the ones in this directory, not the subdirs)
497 496
498 497 b) Recurse the function on all the subdirectories of this
499 498 directory
500 499 """
501 500
502 501 if len(self.statuses) == 1:
503 502 onlyst = self.statuses.pop()
504 503
505 504 # Making sure we terse only when the status abbreviation is
506 505 # passed as terse argument
507 506 if onlyst in terseargs:
508 507 yield onlyst, self.path + '/'
509 508 return
510 509
511 510 # add the files to status list
512 511 for st, fpath in self.iterfilepaths():
513 512 yield st, fpath
514 513
515 514 #recurse on the subdirs
516 515 for dirobj in self.subdirs.values():
517 516 for st, fpath in dirobj.tersewalk(terseargs):
518 517 yield st, fpath
519 518
520 519 def tersedir(statuslist, terseargs):
521 520 """
522 521 Terse the status if all the files in a directory shares the same status.
523 522
524 523 statuslist is scmutil.status() object which contains a list of files for
525 524 each status.
526 525 terseargs is string which is passed by the user as the argument to `--terse`
527 526 flag.
528 527
529 528 The function makes a tree of objects of dirnode class, and at each node it
530 529 stores the information required to know whether we can terse a certain
531 530 directory or not.
532 531 """
533 532 # the order matters here as that is used to produce final list
534 533 allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c')
535 534
536 535 # checking the argument validity
537 536 for s in pycompat.bytestr(terseargs):
538 537 if s not in allst:
539 538 raise error.Abort(_("'%s' not recognized") % s)
540 539
541 540 # creating a dirnode object for the root of the repo
542 541 rootobj = dirnode('')
543 542 pstatus = ('modified', 'added', 'deleted', 'clean', 'unknown',
544 543 'ignored', 'removed')
545 544
546 545 tersedict = {}
547 546 for attrname in pstatus:
548 547 statuschar = attrname[0:1]
549 548 for f in getattr(statuslist, attrname):
550 549 rootobj.addfile(f, statuschar)
551 550 tersedict[statuschar] = []
552 551
553 552 # we won't be tersing the root dir, so add files in it
554 553 for st, fpath in rootobj.iterfilepaths():
555 554 tersedict[st].append(fpath)
556 555
557 556 # process each sub-directory and build tersedict
558 557 for subdir in rootobj.subdirs.values():
559 558 for st, f in subdir.tersewalk(terseargs):
560 559 tersedict[st].append(f)
561 560
562 561 tersedlist = []
563 562 for st in allst:
564 563 tersedict[st].sort()
565 564 tersedlist.append(tersedict[st])
566 565
567 566 return tersedlist
568 567
569 568 def _commentlines(raw):
570 569 '''Surround lineswith a comment char and a new line'''
571 570 lines = raw.splitlines()
572 571 commentedlines = ['# %s' % line for line in lines]
573 572 return '\n'.join(commentedlines) + '\n'
574 573
575 574 def _conflictsmsg(repo):
576 575 mergestate = mergemod.mergestate.read(repo)
577 576 if not mergestate.active():
578 577 return
579 578
580 579 m = scmutil.match(repo[None])
581 580 unresolvedlist = [f for f in mergestate.unresolved() if m(f)]
582 581 if unresolvedlist:
583 582 mergeliststr = '\n'.join(
584 583 [' %s' % util.pathto(repo.root, encoding.getcwd(), path)
585 584 for path in unresolvedlist])
586 585 msg = _('''Unresolved merge conflicts:
587 586
588 587 %s
589 588
590 589 To mark files as resolved: hg resolve --mark FILE''') % mergeliststr
591 590 else:
592 591 msg = _('No unresolved merge conflicts.')
593 592
594 593 return _commentlines(msg)
595 594
596 595 def _helpmessage(continuecmd, abortcmd):
597 596 msg = _('To continue: %s\n'
598 597 'To abort: %s') % (continuecmd, abortcmd)
599 598 return _commentlines(msg)
600 599
601 600 def _rebasemsg():
602 601 return _helpmessage('hg rebase --continue', 'hg rebase --abort')
603 602
604 603 def _histeditmsg():
605 604 return _helpmessage('hg histedit --continue', 'hg histedit --abort')
606 605
607 606 def _unshelvemsg():
608 607 return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
609 608
610 609 def _graftmsg():
611 610 # tweakdefaults requires `update` to have a rev hence the `.`
612 611 return _helpmessage('hg graft --continue', 'hg graft --abort')
613 612
614 613 def _mergemsg():
615 614 # tweakdefaults requires `update` to have a rev hence the `.`
616 615 return _helpmessage('hg commit', 'hg merge --abort')
617 616
618 617 def _bisectmsg():
619 618 msg = _('To mark the changeset good: hg bisect --good\n'
620 619 'To mark the changeset bad: hg bisect --bad\n'
621 620 'To abort: hg bisect --reset\n')
622 621 return _commentlines(msg)
623 622
624 623 def fileexistspredicate(filename):
625 624 return lambda repo: repo.vfs.exists(filename)
626 625
627 626 def _mergepredicate(repo):
628 627 return len(repo[None].parents()) > 1
629 628
630 629 STATES = (
631 630 # (state, predicate to detect states, helpful message function)
632 631 ('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
633 632 ('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
634 633 ('graft', fileexistspredicate('graftstate'), _graftmsg),
635 634 ('unshelve', fileexistspredicate('shelvedstate'), _unshelvemsg),
636 635 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
637 636 # The merge state is part of a list that will be iterated over.
638 637 # They need to be last because some of the other unfinished states may also
639 638 # be in a merge or update state (eg. rebase, histedit, graft, etc).
640 639 # We want those to have priority.
641 640 ('merge', _mergepredicate, _mergemsg),
642 641 )
643 642
644 643 def _getrepostate(repo):
645 644 # experimental config: commands.status.skipstates
646 645 skip = set(repo.ui.configlist('commands', 'status.skipstates'))
647 646 for state, statedetectionpredicate, msgfn in STATES:
648 647 if state in skip:
649 648 continue
650 649 if statedetectionpredicate(repo):
651 650 return (state, statedetectionpredicate, msgfn)
652 651
653 652 def morestatus(repo, fm):
654 653 statetuple = _getrepostate(repo)
655 654 label = 'status.morestatus'
656 655 if statetuple:
657 656 state, statedetectionpredicate, helpfulmsg = statetuple
658 657 statemsg = _('The repository is in an unfinished *%s* state.') % state
659 658 fm.plain('%s\n' % _commentlines(statemsg), label=label)
660 659 conmsg = _conflictsmsg(repo)
661 660 if conmsg:
662 661 fm.plain('%s\n' % conmsg, label=label)
663 662 if helpfulmsg:
664 663 helpmsg = helpfulmsg()
665 664 fm.plain('%s\n' % helpmsg, label=label)
666 665
667 666 def findpossible(cmd, table, strict=False):
668 667 """
669 668 Return cmd -> (aliases, command table entry)
670 669 for each matching command.
671 670 Return debug commands (or their aliases) only if no normal command matches.
672 671 """
673 672 choice = {}
674 673 debugchoice = {}
675 674
676 675 if cmd in table:
677 676 # short-circuit exact matches, "log" alias beats "^log|history"
678 677 keys = [cmd]
679 678 else:
680 679 keys = table.keys()
681 680
682 681 allcmds = []
683 682 for e in keys:
684 683 aliases = parsealiases(e)
685 684 allcmds.extend(aliases)
686 685 found = None
687 686 if cmd in aliases:
688 687 found = cmd
689 688 elif not strict:
690 689 for a in aliases:
691 690 if a.startswith(cmd):
692 691 found = a
693 692 break
694 693 if found is not None:
695 694 if aliases[0].startswith("debug") or found.startswith("debug"):
696 695 debugchoice[found] = (aliases, table[e])
697 696 else:
698 697 choice[found] = (aliases, table[e])
699 698
700 699 if not choice and debugchoice:
701 700 choice = debugchoice
702 701
703 702 return choice, allcmds
704 703
705 704 def findcmd(cmd, table, strict=True):
706 705 """Return (aliases, command table entry) for command string."""
707 706 choice, allcmds = findpossible(cmd, table, strict)
708 707
709 708 if cmd in choice:
710 709 return choice[cmd]
711 710
712 711 if len(choice) > 1:
713 712 clist = sorted(choice)
714 713 raise error.AmbiguousCommand(cmd, clist)
715 714
716 715 if choice:
717 716 return list(choice.values())[0]
718 717
719 718 raise error.UnknownCommand(cmd, allcmds)
720 719
721 720 def changebranch(ui, repo, revs, label):
722 721 """ Change the branch name of given revs to label """
723 722
724 723 with repo.wlock(), repo.lock(), repo.transaction('branches'):
725 724 # abort in case of uncommitted merge or dirty wdir
726 725 bailifchanged(repo)
727 726 revs = scmutil.revrange(repo, revs)
728 727 if not revs:
729 728 raise error.Abort("empty revision set")
730 729 roots = repo.revs('roots(%ld)', revs)
731 730 if len(roots) > 1:
732 731 raise error.Abort(_("cannot change branch of non-linear revisions"))
733 732 rewriteutil.precheck(repo, revs, 'change branch of')
734 733
735 734 root = repo[roots.first()]
736 735 if not root.p1().branch() == label and label in repo.branchmap():
737 736 raise error.Abort(_("a branch of the same name already exists"))
738 737
739 738 if repo.revs('merge() and %ld', revs):
740 739 raise error.Abort(_("cannot change branch of a merge commit"))
741 740 if repo.revs('obsolete() and %ld', revs):
742 741 raise error.Abort(_("cannot change branch of a obsolete changeset"))
743 742
744 743 # make sure only topological heads
745 744 if repo.revs('heads(%ld) - head()', revs):
746 745 raise error.Abort(_("cannot change branch in middle of a stack"))
747 746
748 747 replacements = {}
749 748 # avoid import cycle mercurial.cmdutil -> mercurial.context ->
750 749 # mercurial.subrepo -> mercurial.cmdutil
751 750 from . import context
752 751 for rev in revs:
753 752 ctx = repo[rev]
754 753 oldbranch = ctx.branch()
755 754 # check if ctx has same branch
756 755 if oldbranch == label:
757 756 continue
758 757
759 758 def filectxfn(repo, newctx, path):
760 759 try:
761 760 return ctx[path]
762 761 except error.ManifestLookupError:
763 762 return None
764 763
765 764 ui.debug("changing branch of '%s' from '%s' to '%s'\n"
766 765 % (hex(ctx.node()), oldbranch, label))
767 766 extra = ctx.extra()
768 767 extra['branch_change'] = hex(ctx.node())
769 768 # While changing branch of set of linear commits, make sure that
770 769 # we base our commits on new parent rather than old parent which
771 770 # was obsoleted while changing the branch
772 771 p1 = ctx.p1().node()
773 772 p2 = ctx.p2().node()
774 773 if p1 in replacements:
775 774 p1 = replacements[p1][0]
776 775 if p2 in replacements:
777 776 p2 = replacements[p2][0]
778 777
779 778 mc = context.memctx(repo, (p1, p2),
780 779 ctx.description(),
781 780 ctx.files(),
782 781 filectxfn,
783 782 user=ctx.user(),
784 783 date=ctx.date(),
785 784 extra=extra,
786 785 branch=label)
787 786
788 787 newnode = repo.commitctx(mc)
789 788 replacements[ctx.node()] = (newnode,)
790 789 ui.debug('new node id is %s\n' % hex(newnode))
791 790
792 791 # create obsmarkers and move bookmarks
793 792 scmutil.cleanupnodes(repo, replacements, 'branch-change', fixphase=True)
794 793
795 794 # move the working copy too
796 795 wctx = repo[None]
797 796 # in-progress merge is a bit too complex for now.
798 797 if len(wctx.parents()) == 1:
799 798 newid = replacements.get(wctx.p1().node())
800 799 if newid is not None:
801 800 # avoid import cycle mercurial.cmdutil -> mercurial.hg ->
802 801 # mercurial.cmdutil
803 802 from . import hg
804 803 hg.update(repo, newid[0], quietempty=True)
805 804
806 805 ui.status(_("changed branch on %d changesets\n") % len(replacements))
807 806
808 807 def findrepo(p):
809 808 while not os.path.isdir(os.path.join(p, ".hg")):
810 809 oldp, p = p, os.path.dirname(p)
811 810 if p == oldp:
812 811 return None
813 812
814 813 return p
815 814
816 815 def bailifchanged(repo, merge=True, hint=None):
817 816 """ enforce the precondition that working directory must be clean.
818 817
819 818 'merge' can be set to false if a pending uncommitted merge should be
820 819 ignored (such as when 'update --check' runs).
821 820
822 821 'hint' is the usual hint given to Abort exception.
823 822 """
824 823
825 824 if merge and repo.dirstate.p2() != nullid:
826 825 raise error.Abort(_('outstanding uncommitted merge'), hint=hint)
827 826 modified, added, removed, deleted = repo.status()[:4]
828 827 if modified or added or removed or deleted:
829 828 raise error.Abort(_('uncommitted changes'), hint=hint)
830 829 ctx = repo[None]
831 830 for s in sorted(ctx.substate):
832 831 ctx.sub(s).bailifchanged(hint=hint)
833 832
834 833 def logmessage(ui, opts):
835 834 """ get the log message according to -m and -l option """
836 835 message = opts.get('message')
837 836 logfile = opts.get('logfile')
838 837
839 838 if message and logfile:
840 839 raise error.Abort(_('options --message and --logfile are mutually '
841 840 'exclusive'))
842 841 if not message and logfile:
843 842 try:
844 843 if isstdiofilename(logfile):
845 844 message = ui.fin.read()
846 845 else:
847 846 message = '\n'.join(util.readfile(logfile).splitlines())
848 847 except IOError as inst:
849 848 raise error.Abort(_("can't read commit message '%s': %s") %
850 849 (logfile, encoding.strtolocal(inst.strerror)))
851 850 return message
852 851
853 852 def mergeeditform(ctxorbool, baseformname):
854 853 """return appropriate editform name (referencing a committemplate)
855 854
856 855 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
857 856 merging is committed.
858 857
859 858 This returns baseformname with '.merge' appended if it is a merge,
860 859 otherwise '.normal' is appended.
861 860 """
862 861 if isinstance(ctxorbool, bool):
863 862 if ctxorbool:
864 863 return baseformname + ".merge"
865 864 elif 1 < len(ctxorbool.parents()):
866 865 return baseformname + ".merge"
867 866
868 867 return baseformname + ".normal"
869 868
870 869 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
871 870 editform='', **opts):
872 871 """get appropriate commit message editor according to '--edit' option
873 872
874 873 'finishdesc' is a function to be called with edited commit message
875 874 (= 'description' of the new changeset) just after editing, but
876 875 before checking empty-ness. It should return actual text to be
877 876 stored into history. This allows to change description before
878 877 storing.
879 878
880 879 'extramsg' is a extra message to be shown in the editor instead of
881 880 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
882 881 is automatically added.
883 882
884 883 'editform' is a dot-separated list of names, to distinguish
885 884 the purpose of commit text editing.
886 885
887 886 'getcommiteditor' returns 'commitforceeditor' regardless of
888 887 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
889 888 they are specific for usage in MQ.
890 889 """
891 890 if edit or finishdesc or extramsg:
892 891 return lambda r, c, s: commitforceeditor(r, c, s,
893 892 finishdesc=finishdesc,
894 893 extramsg=extramsg,
895 894 editform=editform)
896 895 elif editform:
897 896 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
898 897 else:
899 898 return commiteditor
900 899
901 900 def _escapecommandtemplate(tmpl):
902 901 parts = []
903 902 for typ, start, end in templater.scantemplate(tmpl, raw=True):
904 903 if typ == b'string':
905 904 parts.append(stringutil.escapestr(tmpl[start:end]))
906 905 else:
907 906 parts.append(tmpl[start:end])
908 907 return b''.join(parts)
909 908
910 909 def rendercommandtemplate(ui, tmpl, props):
911 910 r"""Expand a literal template 'tmpl' in a way suitable for command line
912 911
913 912 '\' in outermost string is not taken as an escape character because it
914 913 is a directory separator on Windows.
915 914
916 915 >>> from . import ui as uimod
917 916 >>> ui = uimod.ui()
918 917 >>> rendercommandtemplate(ui, b'c:\\{path}', {b'path': b'foo'})
919 918 'c:\\foo'
920 919 >>> rendercommandtemplate(ui, b'{"c:\\{path}"}', {'path': b'foo'})
921 920 'c:{path}'
922 921 """
923 922 if not tmpl:
924 923 return tmpl
925 924 t = formatter.maketemplater(ui, _escapecommandtemplate(tmpl))
926 925 return t.renderdefault(props)
927 926
928 927 def rendertemplate(ctx, tmpl, props=None):
929 928 """Expand a literal template 'tmpl' byte-string against one changeset
930 929
931 930 Each props item must be a stringify-able value or a callable returning
932 931 such value, i.e. no bare list nor dict should be passed.
933 932 """
934 933 repo = ctx.repo()
935 934 tres = formatter.templateresources(repo.ui, repo)
936 935 t = formatter.maketemplater(repo.ui, tmpl, defaults=templatekw.keywords,
937 936 resources=tres)
938 937 mapping = {'ctx': ctx}
939 938 if props:
940 939 mapping.update(props)
941 940 return t.renderdefault(mapping)
942 941
943 942 def _buildfntemplate(pat, total=None, seqno=None, revwidth=None, pathname=None):
944 943 r"""Convert old-style filename format string to template string
945 944
946 945 >>> _buildfntemplate(b'foo-%b-%n.patch', seqno=0)
947 946 'foo-{reporoot|basename}-{seqno}.patch'
948 947 >>> _buildfntemplate(b'%R{tags % "{tag}"}%H')
949 948 '{rev}{tags % "{tag}"}{node}'
950 949
951 950 '\' in outermost strings has to be escaped because it is a directory
952 951 separator on Windows:
953 952
954 953 >>> _buildfntemplate(b'c:\\tmp\\%R\\%n.patch', seqno=0)
955 954 'c:\\\\tmp\\\\{rev}\\\\{seqno}.patch'
956 955 >>> _buildfntemplate(b'\\\\foo\\bar.patch')
957 956 '\\\\\\\\foo\\\\bar.patch'
958 957 >>> _buildfntemplate(b'\\{tags % "{tag}"}')
959 958 '\\\\{tags % "{tag}"}'
960 959
961 960 but inner strings follow the template rules (i.e. '\' is taken as an
962 961 escape character):
963 962
964 963 >>> _buildfntemplate(br'{"c:\tmp"}', seqno=0)
965 964 '{"c:\\tmp"}'
966 965 """
967 966 expander = {
968 967 b'H': b'{node}',
969 968 b'R': b'{rev}',
970 969 b'h': b'{node|short}',
971 970 b'm': br'{sub(r"[^\w]", "_", desc|firstline)}',
972 971 b'r': b'{if(revwidth, pad(rev, revwidth, "0", left=True), rev)}',
973 972 b'%': b'%',
974 973 b'b': b'{reporoot|basename}',
975 974 }
976 975 if total is not None:
977 976 expander[b'N'] = b'{total}'
978 977 if seqno is not None:
979 978 expander[b'n'] = b'{seqno}'
980 979 if total is not None and seqno is not None:
981 980 expander[b'n'] = b'{pad(seqno, total|stringify|count, "0", left=True)}'
982 981 if pathname is not None:
983 982 expander[b's'] = b'{pathname|basename}'
984 983 expander[b'd'] = b'{if(pathname|dirname, pathname|dirname, ".")}'
985 984 expander[b'p'] = b'{pathname}'
986 985
987 986 newname = []
988 987 for typ, start, end in templater.scantemplate(pat, raw=True):
989 988 if typ != b'string':
990 989 newname.append(pat[start:end])
991 990 continue
992 991 i = start
993 992 while i < end:
994 993 n = pat.find(b'%', i, end)
995 994 if n < 0:
996 995 newname.append(stringutil.escapestr(pat[i:end]))
997 996 break
998 997 newname.append(stringutil.escapestr(pat[i:n]))
999 998 if n + 2 > end:
1000 999 raise error.Abort(_("incomplete format spec in output "
1001 1000 "filename"))
1002 1001 c = pat[n + 1:n + 2]
1003 1002 i = n + 2
1004 1003 try:
1005 1004 newname.append(expander[c])
1006 1005 except KeyError:
1007 1006 raise error.Abort(_("invalid format spec '%%%s' in output "
1008 1007 "filename") % c)
1009 1008 return ''.join(newname)
1010 1009
1011 1010 def makefilename(ctx, pat, **props):
1012 1011 if not pat:
1013 1012 return pat
1014 1013 tmpl = _buildfntemplate(pat, **props)
1015 1014 # BUG: alias expansion shouldn't be made against template fragments
1016 1015 # rewritten from %-format strings, but we have no easy way to partially
1017 1016 # disable the expansion.
1018 1017 return rendertemplate(ctx, tmpl, pycompat.byteskwargs(props))
1019 1018
1020 1019 def isstdiofilename(pat):
1021 1020 """True if the given pat looks like a filename denoting stdin/stdout"""
1022 1021 return not pat or pat == '-'
1023 1022
1024 1023 class _unclosablefile(object):
1025 1024 def __init__(self, fp):
1026 1025 self._fp = fp
1027 1026
1028 1027 def close(self):
1029 1028 pass
1030 1029
1031 1030 def __iter__(self):
1032 1031 return iter(self._fp)
1033 1032
1034 1033 def __getattr__(self, attr):
1035 1034 return getattr(self._fp, attr)
1036 1035
1037 1036 def __enter__(self):
1038 1037 return self
1039 1038
1040 1039 def __exit__(self, exc_type, exc_value, exc_tb):
1041 1040 pass
1042 1041
1043 1042 def makefileobj(ctx, pat, mode='wb', **props):
1044 1043 writable = mode not in ('r', 'rb')
1045 1044
1046 1045 if isstdiofilename(pat):
1047 1046 repo = ctx.repo()
1048 1047 if writable:
1049 1048 fp = repo.ui.fout
1050 1049 else:
1051 1050 fp = repo.ui.fin
1052 1051 return _unclosablefile(fp)
1053 1052 fn = makefilename(ctx, pat, **props)
1054 1053 return open(fn, mode)
1055 1054
1056 1055 def openstorage(repo, cmd, file_, opts, returnrevlog=False):
1057 1056 """opens the changelog, manifest, a filelog or a given revlog"""
1058 1057 cl = opts['changelog']
1059 1058 mf = opts['manifest']
1060 1059 dir = opts['dir']
1061 1060 msg = None
1062 1061 if cl and mf:
1063 1062 msg = _('cannot specify --changelog and --manifest at the same time')
1064 1063 elif cl and dir:
1065 1064 msg = _('cannot specify --changelog and --dir at the same time')
1066 1065 elif cl or mf or dir:
1067 1066 if file_:
1068 1067 msg = _('cannot specify filename with --changelog or --manifest')
1069 1068 elif not repo:
1070 1069 msg = _('cannot specify --changelog or --manifest or --dir '
1071 1070 'without a repository')
1072 1071 if msg:
1073 1072 raise error.Abort(msg)
1074 1073
1075 1074 r = None
1076 1075 if repo:
1077 1076 if cl:
1078 1077 r = repo.unfiltered().changelog
1079 1078 elif dir:
1080 1079 if 'treemanifest' not in repo.requirements:
1081 1080 raise error.Abort(_("--dir can only be used on repos with "
1082 1081 "treemanifest enabled"))
1083 1082 if not dir.endswith('/'):
1084 1083 dir = dir + '/'
1085 1084 dirlog = repo.manifestlog.getstorage(dir)
1086 1085 if len(dirlog):
1087 1086 r = dirlog
1088 1087 elif mf:
1089 1088 r = repo.manifestlog.getstorage(b'')
1090 1089 elif file_:
1091 1090 filelog = repo.file(file_)
1092 1091 if len(filelog):
1093 1092 r = filelog
1094 1093
1095 1094 # Not all storage may be revlogs. If requested, try to return an actual
1096 1095 # revlog instance.
1097 1096 if returnrevlog:
1098 1097 if isinstance(r, revlog.revlog):
1099 1098 pass
1100 1099 elif util.safehasattr(r, '_revlog'):
1101 1100 r = r._revlog
1102 1101 elif r is not None:
1103 1102 raise error.Abort(_('%r does not appear to be a revlog') % r)
1104 1103
1105 1104 if not r:
1106 1105 if not returnrevlog:
1107 1106 raise error.Abort(_('cannot give path to non-revlog'))
1108 1107
1109 1108 if not file_:
1110 1109 raise error.CommandError(cmd, _('invalid arguments'))
1111 1110 if not os.path.isfile(file_):
1112 1111 raise error.Abort(_("revlog '%s' not found") % file_)
1113 1112 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False),
1114 1113 file_[:-2] + ".i")
1115 1114 return r
1116 1115
1117 1116 def openrevlog(repo, cmd, file_, opts):
1118 1117 """Obtain a revlog backing storage of an item.
1119 1118
1120 1119 This is similar to ``openstorage()`` except it always returns a revlog.
1121 1120
1122 1121 In most cases, a caller cares about the main storage object - not the
1123 1122 revlog backing it. Therefore, this function should only be used by code
1124 1123 that needs to examine low-level revlog implementation details. e.g. debug
1125 1124 commands.
1126 1125 """
1127 1126 return openstorage(repo, cmd, file_, opts, returnrevlog=True)
1128 1127
1129 1128 def copy(ui, repo, pats, opts, rename=False):
1130 1129 # called with the repo lock held
1131 1130 #
1132 1131 # hgsep => pathname that uses "/" to separate directories
1133 1132 # ossep => pathname that uses os.sep to separate directories
1134 1133 cwd = repo.getcwd()
1135 1134 targets = {}
1136 1135 after = opts.get("after")
1137 1136 dryrun = opts.get("dry_run")
1138 1137 wctx = repo[None]
1139 1138
1140 1139 def walkpat(pat):
1141 1140 srcs = []
1142 1141 if after:
1143 1142 badstates = '?'
1144 1143 else:
1145 1144 badstates = '?r'
1146 1145 m = scmutil.match(wctx, [pat], opts, globbed=True)
1147 1146 for abs in wctx.walk(m):
1148 1147 state = repo.dirstate[abs]
1149 1148 rel = m.rel(abs)
1150 1149 exact = m.exact(abs)
1151 1150 if state in badstates:
1152 1151 if exact and state == '?':
1153 1152 ui.warn(_('%s: not copying - file is not managed\n') % rel)
1154 1153 if exact and state == 'r':
1155 1154 ui.warn(_('%s: not copying - file has been marked for'
1156 1155 ' remove\n') % rel)
1157 1156 continue
1158 1157 # abs: hgsep
1159 1158 # rel: ossep
1160 1159 srcs.append((abs, rel, exact))
1161 1160 return srcs
1162 1161
1163 1162 # abssrc: hgsep
1164 1163 # relsrc: ossep
1165 1164 # otarget: ossep
1166 1165 def copyfile(abssrc, relsrc, otarget, exact):
1167 1166 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
1168 1167 if '/' in abstarget:
1169 1168 # We cannot normalize abstarget itself, this would prevent
1170 1169 # case only renames, like a => A.
1171 1170 abspath, absname = abstarget.rsplit('/', 1)
1172 1171 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
1173 1172 reltarget = repo.pathto(abstarget, cwd)
1174 1173 target = repo.wjoin(abstarget)
1175 1174 src = repo.wjoin(abssrc)
1176 1175 state = repo.dirstate[abstarget]
1177 1176
1178 1177 scmutil.checkportable(ui, abstarget)
1179 1178
1180 1179 # check for collisions
1181 1180 prevsrc = targets.get(abstarget)
1182 1181 if prevsrc is not None:
1183 1182 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1184 1183 (reltarget, repo.pathto(abssrc, cwd),
1185 1184 repo.pathto(prevsrc, cwd)))
1186 1185 return True # report a failure
1187 1186
1188 1187 # check for overwrites
1189 1188 exists = os.path.lexists(target)
1190 1189 samefile = False
1191 1190 if exists and abssrc != abstarget:
1192 1191 if (repo.dirstate.normalize(abssrc) ==
1193 1192 repo.dirstate.normalize(abstarget)):
1194 1193 if not rename:
1195 1194 ui.warn(_("%s: can't copy - same file\n") % reltarget)
1196 1195 return True # report a failure
1197 1196 exists = False
1198 1197 samefile = True
1199 1198
1200 1199 if not after and exists or after and state in 'mn':
1201 1200 if not opts['force']:
1202 1201 if state in 'mn':
1203 1202 msg = _('%s: not overwriting - file already committed\n')
1204 1203 if after:
1205 1204 flags = '--after --force'
1206 1205 else:
1207 1206 flags = '--force'
1208 1207 if rename:
1209 1208 hint = _("('hg rename %s' to replace the file by "
1210 1209 'recording a rename)\n') % flags
1211 1210 else:
1212 1211 hint = _("('hg copy %s' to replace the file by "
1213 1212 'recording a copy)\n') % flags
1214 1213 else:
1215 1214 msg = _('%s: not overwriting - file exists\n')
1216 1215 if rename:
1217 1216 hint = _("('hg rename --after' to record the rename)\n")
1218 1217 else:
1219 1218 hint = _("('hg copy --after' to record the copy)\n")
1220 1219 ui.warn(msg % reltarget)
1221 1220 ui.warn(hint)
1222 1221 return True # report a failure
1223 1222
1224 1223 if after:
1225 1224 if not exists:
1226 1225 if rename:
1227 1226 ui.warn(_('%s: not recording move - %s does not exist\n') %
1228 1227 (relsrc, reltarget))
1229 1228 else:
1230 1229 ui.warn(_('%s: not recording copy - %s does not exist\n') %
1231 1230 (relsrc, reltarget))
1232 1231 return True # report a failure
1233 1232 elif not dryrun:
1234 1233 try:
1235 1234 if exists:
1236 1235 os.unlink(target)
1237 1236 targetdir = os.path.dirname(target) or '.'
1238 1237 if not os.path.isdir(targetdir):
1239 1238 os.makedirs(targetdir)
1240 1239 if samefile:
1241 1240 tmp = target + "~hgrename"
1242 1241 os.rename(src, tmp)
1243 1242 os.rename(tmp, target)
1244 1243 else:
1245 1244 # Preserve stat info on renames, not on copies; this matches
1246 1245 # Linux CLI behavior.
1247 1246 util.copyfile(src, target, copystat=rename)
1248 1247 srcexists = True
1249 1248 except IOError as inst:
1250 1249 if inst.errno == errno.ENOENT:
1251 1250 ui.warn(_('%s: deleted in working directory\n') % relsrc)
1252 1251 srcexists = False
1253 1252 else:
1254 1253 ui.warn(_('%s: cannot copy - %s\n') %
1255 1254 (relsrc, encoding.strtolocal(inst.strerror)))
1256 1255 if rename:
1257 1256 hint = _("('hg rename --after' to record the rename)\n")
1258 1257 else:
1259 1258 hint = _("('hg copy --after' to record the copy)\n")
1260 1259 return True # report a failure
1261 1260
1262 1261 if ui.verbose or not exact:
1263 1262 if rename:
1264 1263 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
1265 1264 else:
1266 1265 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1267 1266
1268 1267 targets[abstarget] = abssrc
1269 1268
1270 1269 # fix up dirstate
1271 1270 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
1272 1271 dryrun=dryrun, cwd=cwd)
1273 1272 if rename and not dryrun:
1274 1273 if not after and srcexists and not samefile:
1275 1274 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
1276 1275 repo.wvfs.unlinkpath(abssrc, rmdir=rmdir)
1277 1276 wctx.forget([abssrc])
1278 1277
1279 1278 # pat: ossep
1280 1279 # dest ossep
1281 1280 # srcs: list of (hgsep, hgsep, ossep, bool)
1282 1281 # return: function that takes hgsep and returns ossep
1283 1282 def targetpathfn(pat, dest, srcs):
1284 1283 if os.path.isdir(pat):
1285 1284 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1286 1285 abspfx = util.localpath(abspfx)
1287 1286 if destdirexists:
1288 1287 striplen = len(os.path.split(abspfx)[0])
1289 1288 else:
1290 1289 striplen = len(abspfx)
1291 1290 if striplen:
1292 1291 striplen += len(pycompat.ossep)
1293 1292 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
1294 1293 elif destdirexists:
1295 1294 res = lambda p: os.path.join(dest,
1296 1295 os.path.basename(util.localpath(p)))
1297 1296 else:
1298 1297 res = lambda p: dest
1299 1298 return res
1300 1299
1301 1300 # pat: ossep
1302 1301 # dest ossep
1303 1302 # srcs: list of (hgsep, hgsep, ossep, bool)
1304 1303 # return: function that takes hgsep and returns ossep
1305 1304 def targetpathafterfn(pat, dest, srcs):
1306 1305 if matchmod.patkind(pat):
1307 1306 # a mercurial pattern
1308 1307 res = lambda p: os.path.join(dest,
1309 1308 os.path.basename(util.localpath(p)))
1310 1309 else:
1311 1310 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1312 1311 if len(abspfx) < len(srcs[0][0]):
1313 1312 # A directory. Either the target path contains the last
1314 1313 # component of the source path or it does not.
1315 1314 def evalpath(striplen):
1316 1315 score = 0
1317 1316 for s in srcs:
1318 1317 t = os.path.join(dest, util.localpath(s[0])[striplen:])
1319 1318 if os.path.lexists(t):
1320 1319 score += 1
1321 1320 return score
1322 1321
1323 1322 abspfx = util.localpath(abspfx)
1324 1323 striplen = len(abspfx)
1325 1324 if striplen:
1326 1325 striplen += len(pycompat.ossep)
1327 1326 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1328 1327 score = evalpath(striplen)
1329 1328 striplen1 = len(os.path.split(abspfx)[0])
1330 1329 if striplen1:
1331 1330 striplen1 += len(pycompat.ossep)
1332 1331 if evalpath(striplen1) > score:
1333 1332 striplen = striplen1
1334 1333 res = lambda p: os.path.join(dest,
1335 1334 util.localpath(p)[striplen:])
1336 1335 else:
1337 1336 # a file
1338 1337 if destdirexists:
1339 1338 res = lambda p: os.path.join(dest,
1340 1339 os.path.basename(util.localpath(p)))
1341 1340 else:
1342 1341 res = lambda p: dest
1343 1342 return res
1344 1343
1345 1344 pats = scmutil.expandpats(pats)
1346 1345 if not pats:
1347 1346 raise error.Abort(_('no source or destination specified'))
1348 1347 if len(pats) == 1:
1349 1348 raise error.Abort(_('no destination specified'))
1350 1349 dest = pats.pop()
1351 1350 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
1352 1351 if not destdirexists:
1353 1352 if len(pats) > 1 or matchmod.patkind(pats[0]):
1354 1353 raise error.Abort(_('with multiple sources, destination must be an '
1355 1354 'existing directory'))
1356 1355 if util.endswithsep(dest):
1357 1356 raise error.Abort(_('destination %s is not a directory') % dest)
1358 1357
1359 1358 tfn = targetpathfn
1360 1359 if after:
1361 1360 tfn = targetpathafterfn
1362 1361 copylist = []
1363 1362 for pat in pats:
1364 1363 srcs = walkpat(pat)
1365 1364 if not srcs:
1366 1365 continue
1367 1366 copylist.append((tfn(pat, dest, srcs), srcs))
1368 1367 if not copylist:
1369 1368 raise error.Abort(_('no files to copy'))
1370 1369
1371 1370 errors = 0
1372 1371 for targetpath, srcs in copylist:
1373 1372 for abssrc, relsrc, exact in srcs:
1374 1373 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
1375 1374 errors += 1
1376 1375
1377 1376 return errors != 0
1378 1377
1379 1378 ## facility to let extension process additional data into an import patch
1380 1379 # list of identifier to be executed in order
1381 1380 extrapreimport = [] # run before commit
1382 1381 extrapostimport = [] # run after commit
1383 1382 # mapping from identifier to actual import function
1384 1383 #
1385 1384 # 'preimport' are run before the commit is made and are provided the following
1386 1385 # arguments:
1387 1386 # - repo: the localrepository instance,
1388 1387 # - patchdata: data extracted from patch header (cf m.patch.patchheadermap),
1389 1388 # - extra: the future extra dictionary of the changeset, please mutate it,
1390 1389 # - opts: the import options.
1391 1390 # XXX ideally, we would just pass an ctx ready to be computed, that would allow
1392 1391 # mutation of in memory commit and more. Feel free to rework the code to get
1393 1392 # there.
1394 1393 extrapreimportmap = {}
1395 1394 # 'postimport' are run after the commit is made and are provided the following
1396 1395 # argument:
1397 1396 # - ctx: the changectx created by import.
1398 1397 extrapostimportmap = {}
1399 1398
1400 1399 def tryimportone(ui, repo, patchdata, parents, opts, msgs, updatefunc):
1401 1400 """Utility function used by commands.import to import a single patch
1402 1401
1403 1402 This function is explicitly defined here to help the evolve extension to
1404 1403 wrap this part of the import logic.
1405 1404
1406 1405 The API is currently a bit ugly because it a simple code translation from
1407 1406 the import command. Feel free to make it better.
1408 1407
1409 1408 :patchdata: a dictionary containing parsed patch data (such as from
1410 1409 ``patch.extract()``)
1411 1410 :parents: nodes that will be parent of the created commit
1412 1411 :opts: the full dict of option passed to the import command
1413 1412 :msgs: list to save commit message to.
1414 1413 (used in case we need to save it when failing)
1415 1414 :updatefunc: a function that update a repo to a given node
1416 1415 updatefunc(<repo>, <node>)
1417 1416 """
1418 1417 # avoid cycle context -> subrepo -> cmdutil
1419 1418 from . import context
1420 1419
1421 1420 tmpname = patchdata.get('filename')
1422 1421 message = patchdata.get('message')
1423 1422 user = opts.get('user') or patchdata.get('user')
1424 1423 date = opts.get('date') or patchdata.get('date')
1425 1424 branch = patchdata.get('branch')
1426 1425 nodeid = patchdata.get('nodeid')
1427 1426 p1 = patchdata.get('p1')
1428 1427 p2 = patchdata.get('p2')
1429 1428
1430 1429 nocommit = opts.get('no_commit')
1431 1430 importbranch = opts.get('import_branch')
1432 1431 update = not opts.get('bypass')
1433 1432 strip = opts["strip"]
1434 1433 prefix = opts["prefix"]
1435 1434 sim = float(opts.get('similarity') or 0)
1436 1435
1437 1436 if not tmpname:
1438 1437 return None, None, False
1439 1438
1440 1439 rejects = False
1441 1440
1442 1441 cmdline_message = logmessage(ui, opts)
1443 1442 if cmdline_message:
1444 1443 # pickup the cmdline msg
1445 1444 message = cmdline_message
1446 1445 elif message:
1447 1446 # pickup the patch msg
1448 1447 message = message.strip()
1449 1448 else:
1450 1449 # launch the editor
1451 1450 message = None
1452 1451 ui.debug('message:\n%s\n' % (message or ''))
1453 1452
1454 1453 if len(parents) == 1:
1455 1454 parents.append(repo[nullid])
1456 1455 if opts.get('exact'):
1457 1456 if not nodeid or not p1:
1458 1457 raise error.Abort(_('not a Mercurial patch'))
1459 1458 p1 = repo[p1]
1460 1459 p2 = repo[p2 or nullid]
1461 1460 elif p2:
1462 1461 try:
1463 1462 p1 = repo[p1]
1464 1463 p2 = repo[p2]
1465 1464 # Without any options, consider p2 only if the
1466 1465 # patch is being applied on top of the recorded
1467 1466 # first parent.
1468 1467 if p1 != parents[0]:
1469 1468 p1 = parents[0]
1470 1469 p2 = repo[nullid]
1471 1470 except error.RepoError:
1472 1471 p1, p2 = parents
1473 1472 if p2.node() == nullid:
1474 1473 ui.warn(_("warning: import the patch as a normal revision\n"
1475 1474 "(use --exact to import the patch as a merge)\n"))
1476 1475 else:
1477 1476 p1, p2 = parents
1478 1477
1479 1478 n = None
1480 1479 if update:
1481 1480 if p1 != parents[0]:
1482 1481 updatefunc(repo, p1.node())
1483 1482 if p2 != parents[1]:
1484 1483 repo.setparents(p1.node(), p2.node())
1485 1484
1486 1485 if opts.get('exact') or importbranch:
1487 1486 repo.dirstate.setbranch(branch or 'default')
1488 1487
1489 1488 partial = opts.get('partial', False)
1490 1489 files = set()
1491 1490 try:
1492 1491 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
1493 1492 files=files, eolmode=None, similarity=sim / 100.0)
1494 1493 except error.PatchError as e:
1495 1494 if not partial:
1496 1495 raise error.Abort(pycompat.bytestr(e))
1497 1496 if partial:
1498 1497 rejects = True
1499 1498
1500 1499 files = list(files)
1501 1500 if nocommit:
1502 1501 if message:
1503 1502 msgs.append(message)
1504 1503 else:
1505 1504 if opts.get('exact') or p2:
1506 1505 # If you got here, you either use --force and know what
1507 1506 # you are doing or used --exact or a merge patch while
1508 1507 # being updated to its first parent.
1509 1508 m = None
1510 1509 else:
1511 1510 m = scmutil.matchfiles(repo, files or [])
1512 1511 editform = mergeeditform(repo[None], 'import.normal')
1513 1512 if opts.get('exact'):
1514 1513 editor = None
1515 1514 else:
1516 1515 editor = getcommiteditor(editform=editform,
1517 1516 **pycompat.strkwargs(opts))
1518 1517 extra = {}
1519 1518 for idfunc in extrapreimport:
1520 1519 extrapreimportmap[idfunc](repo, patchdata, extra, opts)
1521 1520 overrides = {}
1522 1521 if partial:
1523 1522 overrides[('ui', 'allowemptycommit')] = True
1524 1523 with repo.ui.configoverride(overrides, 'import'):
1525 1524 n = repo.commit(message, user,
1526 1525 date, match=m,
1527 1526 editor=editor, extra=extra)
1528 1527 for idfunc in extrapostimport:
1529 1528 extrapostimportmap[idfunc](repo[n])
1530 1529 else:
1531 1530 if opts.get('exact') or importbranch:
1532 1531 branch = branch or 'default'
1533 1532 else:
1534 1533 branch = p1.branch()
1535 1534 store = patch.filestore()
1536 1535 try:
1537 1536 files = set()
1538 1537 try:
1539 1538 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
1540 1539 files, eolmode=None)
1541 1540 except error.PatchError as e:
1542 1541 raise error.Abort(stringutil.forcebytestr(e))
1543 1542 if opts.get('exact'):
1544 1543 editor = None
1545 1544 else:
1546 1545 editor = getcommiteditor(editform='import.bypass')
1547 1546 memctx = context.memctx(repo, (p1.node(), p2.node()),
1548 1547 message,
1549 1548 files=files,
1550 1549 filectxfn=store,
1551 1550 user=user,
1552 1551 date=date,
1553 1552 branch=branch,
1554 1553 editor=editor)
1555 1554 n = memctx.commit()
1556 1555 finally:
1557 1556 store.close()
1558 1557 if opts.get('exact') and nocommit:
1559 1558 # --exact with --no-commit is still useful in that it does merge
1560 1559 # and branch bits
1561 1560 ui.warn(_("warning: can't check exact import with --no-commit\n"))
1562 1561 elif opts.get('exact') and (not n or hex(n) != nodeid):
1563 1562 raise error.Abort(_('patch is damaged or loses information'))
1564 1563 msg = _('applied to working directory')
1565 1564 if n:
1566 1565 # i18n: refers to a short changeset id
1567 1566 msg = _('created %s') % short(n)
1568 1567 return msg, n, rejects
1569 1568
1570 1569 # facility to let extensions include additional data in an exported patch
1571 1570 # list of identifiers to be executed in order
1572 1571 extraexport = []
1573 1572 # mapping from identifier to actual export function
1574 1573 # function as to return a string to be added to the header or None
1575 1574 # it is given two arguments (sequencenumber, changectx)
1576 1575 extraexportmap = {}
1577 1576
1578 1577 def _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts):
1579 1578 node = scmutil.binnode(ctx)
1580 1579 parents = [p.node() for p in ctx.parents() if p]
1581 1580 branch = ctx.branch()
1582 1581 if switch_parent:
1583 1582 parents.reverse()
1584 1583
1585 1584 if parents:
1586 1585 prev = parents[0]
1587 1586 else:
1588 1587 prev = nullid
1589 1588
1590 1589 fm.context(ctx=ctx)
1591 1590 fm.plain('# HG changeset patch\n')
1592 1591 fm.write('user', '# User %s\n', ctx.user())
1593 1592 fm.plain('# Date %d %d\n' % ctx.date())
1594 1593 fm.write('date', '# %s\n', fm.formatdate(ctx.date()))
1595 1594 fm.condwrite(branch and branch != 'default',
1596 1595 'branch', '# Branch %s\n', branch)
1597 1596 fm.write('node', '# Node ID %s\n', hex(node))
1598 1597 fm.plain('# Parent %s\n' % hex(prev))
1599 1598 if len(parents) > 1:
1600 1599 fm.plain('# Parent %s\n' % hex(parents[1]))
1601 1600 fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name='node'))
1602 1601
1603 1602 # TODO: redesign extraexportmap function to support formatter
1604 1603 for headerid in extraexport:
1605 1604 header = extraexportmap[headerid](seqno, ctx)
1606 1605 if header is not None:
1607 1606 fm.plain('# %s\n' % header)
1608 1607
1609 1608 fm.write('desc', '%s\n', ctx.description().rstrip())
1610 1609 fm.plain('\n')
1611 1610
1612 1611 if fm.isplain():
1613 1612 chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
1614 1613 for chunk, label in chunkiter:
1615 1614 fm.plain(chunk, label=label)
1616 1615 else:
1617 1616 chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
1618 1617 # TODO: make it structured?
1619 1618 fm.data(diff=b''.join(chunkiter))
1620 1619
1621 1620 def _exportfile(repo, revs, fm, dest, switch_parent, diffopts, match):
1622 1621 """Export changesets to stdout or a single file"""
1623 1622 for seqno, rev in enumerate(revs, 1):
1624 1623 ctx = repo[rev]
1625 1624 if not dest.startswith('<'):
1626 1625 repo.ui.note("%s\n" % dest)
1627 1626 fm.startitem()
1628 1627 _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts)
1629 1628
1630 1629 def _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, diffopts,
1631 1630 match):
1632 1631 """Export changesets to possibly multiple files"""
1633 1632 total = len(revs)
1634 1633 revwidth = max(len(str(rev)) for rev in revs)
1635 1634 filemap = util.sortdict() # filename: [(seqno, rev), ...]
1636 1635
1637 1636 for seqno, rev in enumerate(revs, 1):
1638 1637 ctx = repo[rev]
1639 1638 dest = makefilename(ctx, fntemplate,
1640 1639 total=total, seqno=seqno, revwidth=revwidth)
1641 1640 filemap.setdefault(dest, []).append((seqno, rev))
1642 1641
1643 1642 for dest in filemap:
1644 1643 with formatter.maybereopen(basefm, dest) as fm:
1645 1644 repo.ui.note("%s\n" % dest)
1646 1645 for seqno, rev in filemap[dest]:
1647 1646 fm.startitem()
1648 1647 ctx = repo[rev]
1649 1648 _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
1650 1649 diffopts)
1651 1650
1652 1651 def export(repo, revs, basefm, fntemplate='hg-%h.patch', switch_parent=False,
1653 1652 opts=None, match=None):
1654 1653 '''export changesets as hg patches
1655 1654
1656 1655 Args:
1657 1656 repo: The repository from which we're exporting revisions.
1658 1657 revs: A list of revisions to export as revision numbers.
1659 1658 basefm: A formatter to which patches should be written.
1660 1659 fntemplate: An optional string to use for generating patch file names.
1661 1660 switch_parent: If True, show diffs against second parent when not nullid.
1662 1661 Default is false, which always shows diff against p1.
1663 1662 opts: diff options to use for generating the patch.
1664 1663 match: If specified, only export changes to files matching this matcher.
1665 1664
1666 1665 Returns:
1667 1666 Nothing.
1668 1667
1669 1668 Side Effect:
1670 1669 "HG Changeset Patch" data is emitted to one of the following
1671 1670 destinations:
1672 1671 fntemplate specified: Each rev is written to a unique file named using
1673 1672 the given template.
1674 1673 Otherwise: All revs will be written to basefm.
1675 1674 '''
1676 1675 scmutil.prefetchfiles(repo, revs, match)
1677 1676
1678 1677 if not fntemplate:
1679 1678 _exportfile(repo, revs, basefm, '<unnamed>', switch_parent, opts, match)
1680 1679 else:
1681 1680 _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, opts,
1682 1681 match)
1683 1682
1684 1683 def exportfile(repo, revs, fp, switch_parent=False, opts=None, match=None):
1685 1684 """Export changesets to the given file stream"""
1686 1685 scmutil.prefetchfiles(repo, revs, match)
1687 1686
1688 1687 dest = getattr(fp, 'name', '<unnamed>')
1689 1688 with formatter.formatter(repo.ui, fp, 'export', {}) as fm:
1690 1689 _exportfile(repo, revs, fm, dest, switch_parent, opts, match)
1691 1690
1692 1691 def showmarker(fm, marker, index=None):
1693 1692 """utility function to display obsolescence marker in a readable way
1694 1693
1695 1694 To be used by debug function."""
1696 1695 if index is not None:
1697 1696 fm.write('index', '%i ', index)
1698 1697 fm.write('prednode', '%s ', hex(marker.prednode()))
1699 1698 succs = marker.succnodes()
1700 1699 fm.condwrite(succs, 'succnodes', '%s ',
1701 1700 fm.formatlist(map(hex, succs), name='node'))
1702 1701 fm.write('flag', '%X ', marker.flags())
1703 1702 parents = marker.parentnodes()
1704 1703 if parents is not None:
1705 1704 fm.write('parentnodes', '{%s} ',
1706 1705 fm.formatlist(map(hex, parents), name='node', sep=', '))
1707 1706 fm.write('date', '(%s) ', fm.formatdate(marker.date()))
1708 1707 meta = marker.metadata().copy()
1709 1708 meta.pop('date', None)
1710 1709 smeta = pycompat.rapply(pycompat.maybebytestr, meta)
1711 1710 fm.write('metadata', '{%s}', fm.formatdict(smeta, fmt='%r: %r', sep=', '))
1712 1711 fm.plain('\n')
1713 1712
1714 1713 def finddate(ui, repo, date):
1715 1714 """Find the tipmost changeset that matches the given date spec"""
1716 1715
1717 1716 df = dateutil.matchdate(date)
1718 1717 m = scmutil.matchall(repo)
1719 1718 results = {}
1720 1719
1721 1720 def prep(ctx, fns):
1722 1721 d = ctx.date()
1723 1722 if df(d[0]):
1724 1723 results[ctx.rev()] = d
1725 1724
1726 1725 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1727 1726 rev = ctx.rev()
1728 1727 if rev in results:
1729 1728 ui.status(_("found revision %s from %s\n") %
1730 1729 (rev, dateutil.datestr(results[rev])))
1731 1730 return '%d' % rev
1732 1731
1733 1732 raise error.Abort(_("revision matching date not found"))
1734 1733
1735 1734 def increasingwindows(windowsize=8, sizelimit=512):
1736 1735 while True:
1737 1736 yield windowsize
1738 1737 if windowsize < sizelimit:
1739 1738 windowsize *= 2
1740 1739
1741 1740 def _walkrevs(repo, opts):
1742 1741 # Default --rev value depends on --follow but --follow behavior
1743 1742 # depends on revisions resolved from --rev...
1744 1743 follow = opts.get('follow') or opts.get('follow_first')
1745 1744 if opts.get('rev'):
1746 1745 revs = scmutil.revrange(repo, opts['rev'])
1747 1746 elif follow and repo.dirstate.p1() == nullid:
1748 1747 revs = smartset.baseset()
1749 1748 elif follow:
1750 1749 revs = repo.revs('reverse(:.)')
1751 1750 else:
1752 1751 revs = smartset.spanset(repo)
1753 1752 revs.reverse()
1754 1753 return revs
1755 1754
1756 1755 class FileWalkError(Exception):
1757 1756 pass
1758 1757
1759 1758 def walkfilerevs(repo, match, follow, revs, fncache):
1760 1759 '''Walks the file history for the matched files.
1761 1760
1762 1761 Returns the changeset revs that are involved in the file history.
1763 1762
1764 1763 Throws FileWalkError if the file history can't be walked using
1765 1764 filelogs alone.
1766 1765 '''
1767 1766 wanted = set()
1768 1767 copies = []
1769 1768 minrev, maxrev = min(revs), max(revs)
1770 1769 def filerevgen(filelog, last):
1771 1770 """
1772 1771 Only files, no patterns. Check the history of each file.
1773 1772
1774 1773 Examines filelog entries within minrev, maxrev linkrev range
1775 1774 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1776 1775 tuples in backwards order
1777 1776 """
1778 1777 cl_count = len(repo)
1779 1778 revs = []
1780 1779 for j in pycompat.xrange(0, last + 1):
1781 1780 linkrev = filelog.linkrev(j)
1782 1781 if linkrev < minrev:
1783 1782 continue
1784 1783 # only yield rev for which we have the changelog, it can
1785 1784 # happen while doing "hg log" during a pull or commit
1786 1785 if linkrev >= cl_count:
1787 1786 break
1788 1787
1789 1788 parentlinkrevs = []
1790 1789 for p in filelog.parentrevs(j):
1791 1790 if p != nullrev:
1792 1791 parentlinkrevs.append(filelog.linkrev(p))
1793 1792 n = filelog.node(j)
1794 1793 revs.append((linkrev, parentlinkrevs,
1795 1794 follow and filelog.renamed(n)))
1796 1795
1797 1796 return reversed(revs)
1798 1797 def iterfiles():
1799 1798 pctx = repo['.']
1800 1799 for filename in match.files():
1801 1800 if follow:
1802 1801 if filename not in pctx:
1803 1802 raise error.Abort(_('cannot follow file not in parent '
1804 1803 'revision: "%s"') % filename)
1805 1804 yield filename, pctx[filename].filenode()
1806 1805 else:
1807 1806 yield filename, None
1808 1807 for filename_node in copies:
1809 1808 yield filename_node
1810 1809
1811 1810 for file_, node in iterfiles():
1812 1811 filelog = repo.file(file_)
1813 1812 if not len(filelog):
1814 1813 if node is None:
1815 1814 # A zero count may be a directory or deleted file, so
1816 1815 # try to find matching entries on the slow path.
1817 1816 if follow:
1818 1817 raise error.Abort(
1819 1818 _('cannot follow nonexistent file: "%s"') % file_)
1820 1819 raise FileWalkError("Cannot walk via filelog")
1821 1820 else:
1822 1821 continue
1823 1822
1824 1823 if node is None:
1825 1824 last = len(filelog) - 1
1826 1825 else:
1827 1826 last = filelog.rev(node)
1828 1827
1829 1828 # keep track of all ancestors of the file
1830 1829 ancestors = {filelog.linkrev(last)}
1831 1830
1832 1831 # iterate from latest to oldest revision
1833 1832 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1834 1833 if not follow:
1835 1834 if rev > maxrev:
1836 1835 continue
1837 1836 else:
1838 1837 # Note that last might not be the first interesting
1839 1838 # rev to us:
1840 1839 # if the file has been changed after maxrev, we'll
1841 1840 # have linkrev(last) > maxrev, and we still need
1842 1841 # to explore the file graph
1843 1842 if rev not in ancestors:
1844 1843 continue
1845 1844 # XXX insert 1327 fix here
1846 1845 if flparentlinkrevs:
1847 1846 ancestors.update(flparentlinkrevs)
1848 1847
1849 1848 fncache.setdefault(rev, []).append(file_)
1850 1849 wanted.add(rev)
1851 1850 if copied:
1852 1851 copies.append(copied)
1853 1852
1854 1853 return wanted
1855 1854
1856 1855 class _followfilter(object):
1857 1856 def __init__(self, repo, onlyfirst=False):
1858 1857 self.repo = repo
1859 1858 self.startrev = nullrev
1860 1859 self.roots = set()
1861 1860 self.onlyfirst = onlyfirst
1862 1861
1863 1862 def match(self, rev):
1864 1863 def realparents(rev):
1865 1864 if self.onlyfirst:
1866 1865 return self.repo.changelog.parentrevs(rev)[0:1]
1867 1866 else:
1868 1867 return filter(lambda x: x != nullrev,
1869 1868 self.repo.changelog.parentrevs(rev))
1870 1869
1871 1870 if self.startrev == nullrev:
1872 1871 self.startrev = rev
1873 1872 return True
1874 1873
1875 1874 if rev > self.startrev:
1876 1875 # forward: all descendants
1877 1876 if not self.roots:
1878 1877 self.roots.add(self.startrev)
1879 1878 for parent in realparents(rev):
1880 1879 if parent in self.roots:
1881 1880 self.roots.add(rev)
1882 1881 return True
1883 1882 else:
1884 1883 # backwards: all parents
1885 1884 if not self.roots:
1886 1885 self.roots.update(realparents(self.startrev))
1887 1886 if rev in self.roots:
1888 1887 self.roots.remove(rev)
1889 1888 self.roots.update(realparents(rev))
1890 1889 return True
1891 1890
1892 1891 return False
1893 1892
1894 1893 def walkchangerevs(repo, match, opts, prepare):
1895 1894 '''Iterate over files and the revs in which they changed.
1896 1895
1897 1896 Callers most commonly need to iterate backwards over the history
1898 1897 in which they are interested. Doing so has awful (quadratic-looking)
1899 1898 performance, so we use iterators in a "windowed" way.
1900 1899
1901 1900 We walk a window of revisions in the desired order. Within the
1902 1901 window, we first walk forwards to gather data, then in the desired
1903 1902 order (usually backwards) to display it.
1904 1903
1905 1904 This function returns an iterator yielding contexts. Before
1906 1905 yielding each context, the iterator will first call the prepare
1907 1906 function on each context in the window in forward order.'''
1908 1907
1909 1908 allfiles = opts.get('all_files')
1910 1909 follow = opts.get('follow') or opts.get('follow_first')
1911 1910 revs = _walkrevs(repo, opts)
1912 1911 if not revs:
1913 1912 return []
1914 1913 wanted = set()
1915 1914 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
1916 1915 fncache = {}
1917 1916 change = repo.__getitem__
1918 1917
1919 1918 # First step is to fill wanted, the set of revisions that we want to yield.
1920 1919 # When it does not induce extra cost, we also fill fncache for revisions in
1921 1920 # wanted: a cache of filenames that were changed (ctx.files()) and that
1922 1921 # match the file filtering conditions.
1923 1922
1924 1923 if match.always() or allfiles:
1925 1924 # No files, no patterns. Display all revs.
1926 1925 wanted = revs
1927 1926 elif not slowpath:
1928 1927 # We only have to read through the filelog to find wanted revisions
1929 1928
1930 1929 try:
1931 1930 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1932 1931 except FileWalkError:
1933 1932 slowpath = True
1934 1933
1935 1934 # We decided to fall back to the slowpath because at least one
1936 1935 # of the paths was not a file. Check to see if at least one of them
1937 1936 # existed in history, otherwise simply return
1938 1937 for path in match.files():
1939 1938 if path == '.' or path in repo.store:
1940 1939 break
1941 1940 else:
1942 1941 return []
1943 1942
1944 1943 if slowpath:
1945 1944 # We have to read the changelog to match filenames against
1946 1945 # changed files
1947 1946
1948 1947 if follow:
1949 1948 raise error.Abort(_('can only follow copies/renames for explicit '
1950 1949 'filenames'))
1951 1950
1952 1951 # The slow path checks files modified in every changeset.
1953 1952 # This is really slow on large repos, so compute the set lazily.
1954 1953 class lazywantedset(object):
1955 1954 def __init__(self):
1956 1955 self.set = set()
1957 1956 self.revs = set(revs)
1958 1957
1959 1958 # No need to worry about locality here because it will be accessed
1960 1959 # in the same order as the increasing window below.
1961 1960 def __contains__(self, value):
1962 1961 if value in self.set:
1963 1962 return True
1964 1963 elif not value in self.revs:
1965 1964 return False
1966 1965 else:
1967 1966 self.revs.discard(value)
1968 1967 ctx = change(value)
1969 1968 matches = [f for f in ctx.files() if match(f)]
1970 1969 if matches:
1971 1970 fncache[value] = matches
1972 1971 self.set.add(value)
1973 1972 return True
1974 1973 return False
1975 1974
1976 1975 def discard(self, value):
1977 1976 self.revs.discard(value)
1978 1977 self.set.discard(value)
1979 1978
1980 1979 wanted = lazywantedset()
1981 1980
1982 1981 # it might be worthwhile to do this in the iterator if the rev range
1983 1982 # is descending and the prune args are all within that range
1984 1983 for rev in opts.get('prune', ()):
1985 1984 rev = repo[rev].rev()
1986 1985 ff = _followfilter(repo)
1987 1986 stop = min(revs[0], revs[-1])
1988 1987 for x in pycompat.xrange(rev, stop - 1, -1):
1989 1988 if ff.match(x):
1990 1989 wanted = wanted - [x]
1991 1990
1992 1991 # Now that wanted is correctly initialized, we can iterate over the
1993 1992 # revision range, yielding only revisions in wanted.
1994 1993 def iterate():
1995 1994 if follow and match.always():
1996 1995 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
1997 1996 def want(rev):
1998 1997 return ff.match(rev) and rev in wanted
1999 1998 else:
2000 1999 def want(rev):
2001 2000 return rev in wanted
2002 2001
2003 2002 it = iter(revs)
2004 2003 stopiteration = False
2005 2004 for windowsize in increasingwindows():
2006 2005 nrevs = []
2007 2006 for i in pycompat.xrange(windowsize):
2008 2007 rev = next(it, None)
2009 2008 if rev is None:
2010 2009 stopiteration = True
2011 2010 break
2012 2011 elif want(rev):
2013 2012 nrevs.append(rev)
2014 2013 for rev in sorted(nrevs):
2015 2014 fns = fncache.get(rev)
2016 2015 ctx = change(rev)
2017 2016 if not fns:
2018 2017 def fns_generator():
2019 2018 if allfiles:
2020 2019 fiter = iter(ctx)
2021 2020 else:
2022 2021 fiter = ctx.files()
2023 2022 for f in fiter:
2024 2023 if match(f):
2025 2024 yield f
2026 2025 fns = fns_generator()
2027 2026 prepare(ctx, fns)
2028 2027 for rev in nrevs:
2029 2028 yield change(rev)
2030 2029
2031 2030 if stopiteration:
2032 2031 break
2033 2032
2034 2033 return iterate()
2035 2034
2036 2035 def add(ui, repo, match, prefix, explicitonly, **opts):
2037 2036 join = lambda f: os.path.join(prefix, f)
2038 2037 bad = []
2039 2038
2040 2039 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2041 2040 names = []
2042 2041 wctx = repo[None]
2043 2042 cca = None
2044 2043 abort, warn = scmutil.checkportabilityalert(ui)
2045 2044 if abort or warn:
2046 2045 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2047 2046
2048 2047 badmatch = matchmod.badmatch(match, badfn)
2049 2048 dirstate = repo.dirstate
2050 2049 # We don't want to just call wctx.walk here, since it would return a lot of
2051 2050 # clean files, which we aren't interested in and takes time.
2052 2051 for f in sorted(dirstate.walk(badmatch, subrepos=sorted(wctx.substate),
2053 2052 unknown=True, ignored=False, full=False)):
2054 2053 exact = match.exact(f)
2055 2054 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2056 2055 if cca:
2057 2056 cca(f)
2058 2057 names.append(f)
2059 2058 if ui.verbose or not exact:
2060 2059 ui.status(_('adding %s\n') % match.rel(f),
2061 2060 label='addremove.added')
2062 2061
2063 2062 for subpath in sorted(wctx.substate):
2064 2063 sub = wctx.sub(subpath)
2065 2064 try:
2066 2065 submatch = matchmod.subdirmatcher(subpath, match)
2067 2066 if opts.get(r'subrepos'):
2068 2067 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2069 2068 else:
2070 2069 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2071 2070 except error.LookupError:
2072 2071 ui.status(_("skipping missing subrepository: %s\n")
2073 2072 % join(subpath))
2074 2073
2075 2074 if not opts.get(r'dry_run'):
2076 2075 rejected = wctx.add(names, prefix)
2077 2076 bad.extend(f for f in rejected if f in match.files())
2078 2077 return bad
2079 2078
2080 2079 def addwebdirpath(repo, serverpath, webconf):
2081 2080 webconf[serverpath] = repo.root
2082 2081 repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
2083 2082
2084 2083 for r in repo.revs('filelog("path:.hgsub")'):
2085 2084 ctx = repo[r]
2086 2085 for subpath in ctx.substate:
2087 2086 ctx.sub(subpath).addwebdirpath(serverpath, webconf)
2088 2087
2089 2088 def forget(ui, repo, match, prefix, explicitonly, dryrun, interactive):
2090 2089 if dryrun and interactive:
2091 2090 raise error.Abort(_("cannot specify both --dry-run and --interactive"))
2092 2091 join = lambda f: os.path.join(prefix, f)
2093 2092 bad = []
2094 2093 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2095 2094 wctx = repo[None]
2096 2095 forgot = []
2097 2096
2098 2097 s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
2099 2098 forget = sorted(s.modified + s.added + s.deleted + s.clean)
2100 2099 if explicitonly:
2101 2100 forget = [f for f in forget if match.exact(f)]
2102 2101
2103 2102 for subpath in sorted(wctx.substate):
2104 2103 sub = wctx.sub(subpath)
2105 2104 try:
2106 2105 submatch = matchmod.subdirmatcher(subpath, match)
2107 2106 subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun,
2108 2107 interactive=interactive)
2109 2108 bad.extend([subpath + '/' + f for f in subbad])
2110 2109 forgot.extend([subpath + '/' + f for f in subforgot])
2111 2110 except error.LookupError:
2112 2111 ui.status(_("skipping missing subrepository: %s\n")
2113 2112 % join(subpath))
2114 2113
2115 2114 if not explicitonly:
2116 2115 for f in match.files():
2117 2116 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2118 2117 if f not in forgot:
2119 2118 if repo.wvfs.exists(f):
2120 2119 # Don't complain if the exact case match wasn't given.
2121 2120 # But don't do this until after checking 'forgot', so
2122 2121 # that subrepo files aren't normalized, and this op is
2123 2122 # purely from data cached by the status walk above.
2124 2123 if repo.dirstate.normalize(f) in repo.dirstate:
2125 2124 continue
2126 2125 ui.warn(_('not removing %s: '
2127 2126 'file is already untracked\n')
2128 2127 % match.rel(f))
2129 2128 bad.append(f)
2130 2129
2131 2130 if interactive:
2132 2131 responses = _('[Ynsa?]'
2133 2132 '$$ &Yes, forget this file'
2134 2133 '$$ &No, skip this file'
2135 2134 '$$ &Skip remaining files'
2136 2135 '$$ Include &all remaining files'
2137 2136 '$$ &? (display help)')
2138 2137 for filename in forget[:]:
2139 2138 r = ui.promptchoice(_('forget %s %s') % (filename, responses))
2140 2139 if r == 4: # ?
2141 2140 while r == 4:
2142 2141 for c, t in ui.extractchoices(responses)[1]:
2143 2142 ui.write('%s - %s\n' % (c, encoding.lower(t)))
2144 2143 r = ui.promptchoice(_('forget %s %s') % (filename,
2145 2144 responses))
2146 2145 if r == 0: # yes
2147 2146 continue
2148 2147 elif r == 1: # no
2149 2148 forget.remove(filename)
2150 2149 elif r == 2: # Skip
2151 2150 fnindex = forget.index(filename)
2152 2151 del forget[fnindex:]
2153 2152 break
2154 2153 elif r == 3: # All
2155 2154 break
2156 2155
2157 2156 for f in forget:
2158 2157 if ui.verbose or not match.exact(f) or interactive:
2159 2158 ui.status(_('removing %s\n') % match.rel(f),
2160 2159 label='addremove.removed')
2161 2160
2162 2161 if not dryrun:
2163 2162 rejected = wctx.forget(forget, prefix)
2164 2163 bad.extend(f for f in rejected if f in match.files())
2165 2164 forgot.extend(f for f in forget if f not in rejected)
2166 2165 return bad, forgot
2167 2166
2168 2167 def files(ui, ctx, m, fm, fmt, subrepos):
2169 2168 ret = 1
2170 2169
2171 2170 needsfctx = ui.verbose or {'size', 'flags'} & fm.datahint()
2172 2171 for f in ctx.matches(m):
2173 2172 fm.startitem()
2174 2173 fm.context(ctx=ctx)
2175 2174 if needsfctx:
2176 2175 fc = ctx[f]
2177 2176 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2178 2177 fm.data(path=f)
2179 2178 fm.plain(fmt % m.rel(f))
2180 2179 ret = 0
2181 2180
2182 2181 for subpath in sorted(ctx.substate):
2183 2182 submatch = matchmod.subdirmatcher(subpath, m)
2184 2183 if (subrepos or m.exact(subpath) or any(submatch.files())):
2185 2184 sub = ctx.sub(subpath)
2186 2185 try:
2187 2186 recurse = m.exact(subpath) or subrepos
2188 2187 if sub.printfiles(ui, submatch, fm, fmt, recurse) == 0:
2189 2188 ret = 0
2190 2189 except error.LookupError:
2191 2190 ui.status(_("skipping missing subrepository: %s\n")
2192 2191 % m.abs(subpath))
2193 2192
2194 2193 return ret
2195 2194
2196 2195 def remove(ui, repo, m, prefix, after, force, subrepos, dryrun, warnings=None):
2197 2196 join = lambda f: os.path.join(prefix, f)
2198 2197 ret = 0
2199 2198 s = repo.status(match=m, clean=True)
2200 2199 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2201 2200
2202 2201 wctx = repo[None]
2203 2202
2204 2203 if warnings is None:
2205 2204 warnings = []
2206 2205 warn = True
2207 2206 else:
2208 2207 warn = False
2209 2208
2210 2209 subs = sorted(wctx.substate)
2211 2210 progress = ui.makeprogress(_('searching'), total=len(subs),
2212 2211 unit=_('subrepos'))
2213 2212 for subpath in subs:
2214 2213 submatch = matchmod.subdirmatcher(subpath, m)
2215 2214 if subrepos or m.exact(subpath) or any(submatch.files()):
2216 2215 progress.increment()
2217 2216 sub = wctx.sub(subpath)
2218 2217 try:
2219 2218 if sub.removefiles(submatch, prefix, after, force, subrepos,
2220 2219 dryrun, warnings):
2221 2220 ret = 1
2222 2221 except error.LookupError:
2223 2222 warnings.append(_("skipping missing subrepository: %s\n")
2224 2223 % join(subpath))
2225 2224 progress.complete()
2226 2225
2227 2226 # warn about failure to delete explicit files/dirs
2228 2227 deleteddirs = util.dirs(deleted)
2229 2228 files = m.files()
2230 2229 progress = ui.makeprogress(_('deleting'), total=len(files),
2231 2230 unit=_('files'))
2232 2231 for f in files:
2233 2232 def insubrepo():
2234 2233 for subpath in wctx.substate:
2235 2234 if f.startswith(subpath + '/'):
2236 2235 return True
2237 2236 return False
2238 2237
2239 2238 progress.increment()
2240 2239 isdir = f in deleteddirs or wctx.hasdir(f)
2241 2240 if (f in repo.dirstate or isdir or f == '.'
2242 2241 or insubrepo() or f in subs):
2243 2242 continue
2244 2243
2245 2244 if repo.wvfs.exists(f):
2246 2245 if repo.wvfs.isdir(f):
2247 2246 warnings.append(_('not removing %s: no tracked files\n')
2248 2247 % m.rel(f))
2249 2248 else:
2250 2249 warnings.append(_('not removing %s: file is untracked\n')
2251 2250 % m.rel(f))
2252 2251 # missing files will generate a warning elsewhere
2253 2252 ret = 1
2254 2253 progress.complete()
2255 2254
2256 2255 if force:
2257 2256 list = modified + deleted + clean + added
2258 2257 elif after:
2259 2258 list = deleted
2260 2259 remaining = modified + added + clean
2261 2260 progress = ui.makeprogress(_('skipping'), total=len(remaining),
2262 2261 unit=_('files'))
2263 2262 for f in remaining:
2264 2263 progress.increment()
2265 2264 if ui.verbose or (f in files):
2266 2265 warnings.append(_('not removing %s: file still exists\n')
2267 2266 % m.rel(f))
2268 2267 ret = 1
2269 2268 progress.complete()
2270 2269 else:
2271 2270 list = deleted + clean
2272 2271 progress = ui.makeprogress(_('skipping'),
2273 2272 total=(len(modified) + len(added)),
2274 2273 unit=_('files'))
2275 2274 for f in modified:
2276 2275 progress.increment()
2277 2276 warnings.append(_('not removing %s: file is modified (use -f'
2278 2277 ' to force removal)\n') % m.rel(f))
2279 2278 ret = 1
2280 2279 for f in added:
2281 2280 progress.increment()
2282 2281 warnings.append(_("not removing %s: file has been marked for add"
2283 2282 " (use 'hg forget' to undo add)\n") % m.rel(f))
2284 2283 ret = 1
2285 2284 progress.complete()
2286 2285
2287 2286 list = sorted(list)
2288 2287 progress = ui.makeprogress(_('deleting'), total=len(list),
2289 2288 unit=_('files'))
2290 2289 for f in list:
2291 2290 if ui.verbose or not m.exact(f):
2292 2291 progress.increment()
2293 2292 ui.status(_('removing %s\n') % m.rel(f),
2294 2293 label='addremove.removed')
2295 2294 progress.complete()
2296 2295
2297 2296 if not dryrun:
2298 2297 with repo.wlock():
2299 2298 if not after:
2300 2299 for f in list:
2301 2300 if f in added:
2302 2301 continue # we never unlink added files on remove
2303 2302 rmdir = repo.ui.configbool('experimental',
2304 2303 'removeemptydirs')
2305 2304 repo.wvfs.unlinkpath(f, ignoremissing=True, rmdir=rmdir)
2306 2305 repo[None].forget(list)
2307 2306
2308 2307 if warn:
2309 2308 for warning in warnings:
2310 2309 ui.warn(warning)
2311 2310
2312 2311 return ret
2313 2312
2314 2313 def _updatecatformatter(fm, ctx, matcher, path, decode):
2315 2314 """Hook for adding data to the formatter used by ``hg cat``.
2316 2315
2317 2316 Extensions (e.g., lfs) can wrap this to inject keywords/data, but must call
2318 2317 this method first."""
2319 2318 data = ctx[path].data()
2320 2319 if decode:
2321 2320 data = ctx.repo().wwritedata(path, data)
2322 2321 fm.startitem()
2323 2322 fm.context(ctx=ctx)
2324 2323 fm.write('data', '%s', data)
2325 2324 fm.data(path=path)
2326 2325
2327 2326 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
2328 2327 err = 1
2329 2328 opts = pycompat.byteskwargs(opts)
2330 2329
2331 2330 def write(path):
2332 2331 filename = None
2333 2332 if fntemplate:
2334 2333 filename = makefilename(ctx, fntemplate,
2335 2334 pathname=os.path.join(prefix, path))
2336 2335 # attempt to create the directory if it does not already exist
2337 2336 try:
2338 2337 os.makedirs(os.path.dirname(filename))
2339 2338 except OSError:
2340 2339 pass
2341 2340 with formatter.maybereopen(basefm, filename) as fm:
2342 2341 _updatecatformatter(fm, ctx, matcher, path, opts.get('decode'))
2343 2342
2344 2343 # Automation often uses hg cat on single files, so special case it
2345 2344 # for performance to avoid the cost of parsing the manifest.
2346 2345 if len(matcher.files()) == 1 and not matcher.anypats():
2347 2346 file = matcher.files()[0]
2348 2347 mfl = repo.manifestlog
2349 2348 mfnode = ctx.manifestnode()
2350 2349 try:
2351 2350 if mfnode and mfl[mfnode].find(file)[0]:
2352 2351 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2353 2352 write(file)
2354 2353 return 0
2355 2354 except KeyError:
2356 2355 pass
2357 2356
2358 2357 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2359 2358
2360 2359 for abs in ctx.walk(matcher):
2361 2360 write(abs)
2362 2361 err = 0
2363 2362
2364 2363 for subpath in sorted(ctx.substate):
2365 2364 sub = ctx.sub(subpath)
2366 2365 try:
2367 2366 submatch = matchmod.subdirmatcher(subpath, matcher)
2368 2367
2369 2368 if not sub.cat(submatch, basefm, fntemplate,
2370 2369 os.path.join(prefix, sub._path),
2371 2370 **pycompat.strkwargs(opts)):
2372 2371 err = 0
2373 2372 except error.RepoLookupError:
2374 2373 ui.status(_("skipping missing subrepository: %s\n")
2375 2374 % os.path.join(prefix, subpath))
2376 2375
2377 2376 return err
2378 2377
2379 2378 def commit(ui, repo, commitfunc, pats, opts):
2380 2379 '''commit the specified files or all outstanding changes'''
2381 2380 date = opts.get('date')
2382 2381 if date:
2383 2382 opts['date'] = dateutil.parsedate(date)
2384 2383 message = logmessage(ui, opts)
2385 2384 matcher = scmutil.match(repo[None], pats, opts)
2386 2385
2387 2386 dsguard = None
2388 2387 # extract addremove carefully -- this function can be called from a command
2389 2388 # that doesn't support addremove
2390 2389 if opts.get('addremove'):
2391 2390 dsguard = dirstateguard.dirstateguard(repo, 'commit')
2392 2391 with dsguard or util.nullcontextmanager():
2393 2392 if dsguard:
2394 2393 if scmutil.addremove(repo, matcher, "", opts) != 0:
2395 2394 raise error.Abort(
2396 2395 _("failed to mark all new/missing files as added/removed"))
2397 2396
2398 2397 return commitfunc(ui, repo, message, matcher, opts)
2399 2398
2400 2399 def samefile(f, ctx1, ctx2):
2401 2400 if f in ctx1.manifest():
2402 2401 a = ctx1.filectx(f)
2403 2402 if f in ctx2.manifest():
2404 2403 b = ctx2.filectx(f)
2405 2404 return (not a.cmp(b)
2406 2405 and a.flags() == b.flags())
2407 2406 else:
2408 2407 return False
2409 2408 else:
2410 2409 return f not in ctx2.manifest()
2411 2410
2412 2411 def amend(ui, repo, old, extra, pats, opts):
2413 2412 # avoid cycle context -> subrepo -> cmdutil
2414 2413 from . import context
2415 2414
2416 2415 # amend will reuse the existing user if not specified, but the obsolete
2417 2416 # marker creation requires that the current user's name is specified.
2418 2417 if obsolete.isenabled(repo, obsolete.createmarkersopt):
2419 2418 ui.username() # raise exception if username not set
2420 2419
2421 2420 ui.note(_('amending changeset %s\n') % old)
2422 2421 base = old.p1()
2423 2422
2424 2423 with repo.wlock(), repo.lock(), repo.transaction('amend'):
2425 2424 # Participating changesets:
2426 2425 #
2427 2426 # wctx o - workingctx that contains changes from working copy
2428 2427 # | to go into amending commit
2429 2428 # |
2430 2429 # old o - changeset to amend
2431 2430 # |
2432 2431 # base o - first parent of the changeset to amend
2433 2432 wctx = repo[None]
2434 2433
2435 2434 # Copy to avoid mutating input
2436 2435 extra = extra.copy()
2437 2436 # Update extra dict from amended commit (e.g. to preserve graft
2438 2437 # source)
2439 2438 extra.update(old.extra())
2440 2439
2441 2440 # Also update it from the from the wctx
2442 2441 extra.update(wctx.extra())
2443 2442
2444 2443 user = opts.get('user') or old.user()
2445 2444 date = opts.get('date') or old.date()
2446 2445
2447 2446 # Parse the date to allow comparison between date and old.date()
2448 2447 date = dateutil.parsedate(date)
2449 2448
2450 2449 if len(old.parents()) > 1:
2451 2450 # ctx.files() isn't reliable for merges, so fall back to the
2452 2451 # slower repo.status() method
2453 2452 files = set([fn for st in base.status(old)[:3]
2454 2453 for fn in st])
2455 2454 else:
2456 2455 files = set(old.files())
2457 2456
2458 2457 # add/remove the files to the working copy if the "addremove" option
2459 2458 # was specified.
2460 2459 matcher = scmutil.match(wctx, pats, opts)
2461 2460 if (opts.get('addremove')
2462 2461 and scmutil.addremove(repo, matcher, "", opts)):
2463 2462 raise error.Abort(
2464 2463 _("failed to mark all new/missing files as added/removed"))
2465 2464
2466 2465 # Check subrepos. This depends on in-place wctx._status update in
2467 2466 # subrepo.precommit(). To minimize the risk of this hack, we do
2468 2467 # nothing if .hgsub does not exist.
2469 2468 if '.hgsub' in wctx or '.hgsub' in old:
2470 2469 subs, commitsubs, newsubstate = subrepoutil.precommit(
2471 2470 ui, wctx, wctx._status, matcher)
2472 2471 # amend should abort if commitsubrepos is enabled
2473 2472 assert not commitsubs
2474 2473 if subs:
2475 2474 subrepoutil.writestate(repo, newsubstate)
2476 2475
2477 2476 ms = mergemod.mergestate.read(repo)
2478 2477 mergeutil.checkunresolved(ms)
2479 2478
2480 2479 filestoamend = set(f for f in wctx.files() if matcher(f))
2481 2480
2482 2481 changes = (len(filestoamend) > 0)
2483 2482 if changes:
2484 2483 # Recompute copies (avoid recording a -> b -> a)
2485 2484 copied = copies.pathcopies(base, wctx, matcher)
2486 2485 if old.p2:
2487 2486 copied.update(copies.pathcopies(old.p2(), wctx, matcher))
2488 2487
2489 2488 # Prune files which were reverted by the updates: if old
2490 2489 # introduced file X and the file was renamed in the working
2491 2490 # copy, then those two files are the same and
2492 2491 # we can discard X from our list of files. Likewise if X
2493 2492 # was removed, it's no longer relevant. If X is missing (aka
2494 2493 # deleted), old X must be preserved.
2495 2494 files.update(filestoamend)
2496 2495 files = [f for f in files if (not samefile(f, wctx, base)
2497 2496 or f in wctx.deleted())]
2498 2497
2499 2498 def filectxfn(repo, ctx_, path):
2500 2499 try:
2501 2500 # If the file being considered is not amongst the files
2502 2501 # to be amended, we should return the file context from the
2503 2502 # old changeset. This avoids issues when only some files in
2504 2503 # the working copy are being amended but there are also
2505 2504 # changes to other files from the old changeset.
2506 2505 if path not in filestoamend:
2507 2506 return old.filectx(path)
2508 2507
2509 2508 # Return None for removed files.
2510 2509 if path in wctx.removed():
2511 2510 return None
2512 2511
2513 2512 fctx = wctx[path]
2514 2513 flags = fctx.flags()
2515 2514 mctx = context.memfilectx(repo, ctx_,
2516 2515 fctx.path(), fctx.data(),
2517 2516 islink='l' in flags,
2518 2517 isexec='x' in flags,
2519 2518 copied=copied.get(path))
2520 2519 return mctx
2521 2520 except KeyError:
2522 2521 return None
2523 2522 else:
2524 2523 ui.note(_('copying changeset %s to %s\n') % (old, base))
2525 2524
2526 2525 # Use version of files as in the old cset
2527 2526 def filectxfn(repo, ctx_, path):
2528 2527 try:
2529 2528 return old.filectx(path)
2530 2529 except KeyError:
2531 2530 return None
2532 2531
2533 2532 # See if we got a message from -m or -l, if not, open the editor with
2534 2533 # the message of the changeset to amend.
2535 2534 message = logmessage(ui, opts)
2536 2535
2537 2536 editform = mergeeditform(old, 'commit.amend')
2538 2537 editor = getcommiteditor(editform=editform,
2539 2538 **pycompat.strkwargs(opts))
2540 2539
2541 2540 if not message:
2542 2541 editor = getcommiteditor(edit=True, editform=editform)
2543 2542 message = old.description()
2544 2543
2545 2544 pureextra = extra.copy()
2546 2545 extra['amend_source'] = old.hex()
2547 2546
2548 2547 new = context.memctx(repo,
2549 2548 parents=[base.node(), old.p2().node()],
2550 2549 text=message,
2551 2550 files=files,
2552 2551 filectxfn=filectxfn,
2553 2552 user=user,
2554 2553 date=date,
2555 2554 extra=extra,
2556 2555 editor=editor)
2557 2556
2558 2557 newdesc = changelog.stripdesc(new.description())
2559 2558 if ((not changes)
2560 2559 and newdesc == old.description()
2561 2560 and user == old.user()
2562 2561 and date == old.date()
2563 2562 and pureextra == old.extra()):
2564 2563 # nothing changed. continuing here would create a new node
2565 2564 # anyway because of the amend_source noise.
2566 2565 #
2567 2566 # This not what we expect from amend.
2568 2567 return old.node()
2569 2568
2570 2569 commitphase = None
2571 2570 if opts.get('secret'):
2572 2571 commitphase = phases.secret
2573 2572 newid = repo.commitctx(new)
2574 2573
2575 2574 # Reroute the working copy parent to the new changeset
2576 2575 repo.setparents(newid, nullid)
2577 2576 mapping = {old.node(): (newid,)}
2578 2577 obsmetadata = None
2579 2578 if opts.get('note'):
2580 2579 obsmetadata = {'note': encoding.fromlocal(opts['note'])}
2581 2580 backup = ui.configbool('ui', 'history-editing-backup')
2582 2581 scmutil.cleanupnodes(repo, mapping, 'amend', metadata=obsmetadata,
2583 2582 fixphase=True, targetphase=commitphase,
2584 2583 backup=backup)
2585 2584
2586 2585 # Fixing the dirstate because localrepo.commitctx does not update
2587 2586 # it. This is rather convenient because we did not need to update
2588 2587 # the dirstate for all the files in the new commit which commitctx
2589 2588 # could have done if it updated the dirstate. Now, we can
2590 2589 # selectively update the dirstate only for the amended files.
2591 2590 dirstate = repo.dirstate
2592 2591
2593 2592 # Update the state of the files which were added and
2594 2593 # and modified in the amend to "normal" in the dirstate.
2595 2594 normalfiles = set(wctx.modified() + wctx.added()) & filestoamend
2596 2595 for f in normalfiles:
2597 2596 dirstate.normal(f)
2598 2597
2599 2598 # Update the state of files which were removed in the amend
2600 2599 # to "removed" in the dirstate.
2601 2600 removedfiles = set(wctx.removed()) & filestoamend
2602 2601 for f in removedfiles:
2603 2602 dirstate.drop(f)
2604 2603
2605 2604 return newid
2606 2605
2607 2606 def commiteditor(repo, ctx, subs, editform=''):
2608 2607 if ctx.description():
2609 2608 return ctx.description()
2610 2609 return commitforceeditor(repo, ctx, subs, editform=editform,
2611 2610 unchangedmessagedetection=True)
2612 2611
2613 2612 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2614 2613 editform='', unchangedmessagedetection=False):
2615 2614 if not extramsg:
2616 2615 extramsg = _("Leave message empty to abort commit.")
2617 2616
2618 2617 forms = [e for e in editform.split('.') if e]
2619 2618 forms.insert(0, 'changeset')
2620 2619 templatetext = None
2621 2620 while forms:
2622 2621 ref = '.'.join(forms)
2623 2622 if repo.ui.config('committemplate', ref):
2624 2623 templatetext = committext = buildcommittemplate(
2625 2624 repo, ctx, subs, extramsg, ref)
2626 2625 break
2627 2626 forms.pop()
2628 2627 else:
2629 2628 committext = buildcommittext(repo, ctx, subs, extramsg)
2630 2629
2631 2630 # run editor in the repository root
2632 2631 olddir = encoding.getcwd()
2633 2632 os.chdir(repo.root)
2634 2633
2635 2634 # make in-memory changes visible to external process
2636 2635 tr = repo.currenttransaction()
2637 2636 repo.dirstate.write(tr)
2638 2637 pending = tr and tr.writepending() and repo.root
2639 2638
2640 2639 editortext = repo.ui.edit(committext, ctx.user(), ctx.extra(),
2641 2640 editform=editform, pending=pending,
2642 2641 repopath=repo.path, action='commit')
2643 2642 text = editortext
2644 2643
2645 2644 # strip away anything below this special string (used for editors that want
2646 2645 # to display the diff)
2647 2646 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE)
2648 2647 if stripbelow:
2649 2648 text = text[:stripbelow.start()]
2650 2649
2651 2650 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2652 2651 os.chdir(olddir)
2653 2652
2654 2653 if finishdesc:
2655 2654 text = finishdesc(text)
2656 2655 if not text.strip():
2657 2656 raise error.Abort(_("empty commit message"))
2658 2657 if unchangedmessagedetection and editortext == templatetext:
2659 2658 raise error.Abort(_("commit message unchanged"))
2660 2659
2661 2660 return text
2662 2661
2663 2662 def buildcommittemplate(repo, ctx, subs, extramsg, ref):
2664 2663 ui = repo.ui
2665 2664 spec = formatter.templatespec(ref, None, None)
2666 2665 t = logcmdutil.changesettemplater(ui, repo, spec)
2667 2666 t.t.cache.update((k, templater.unquotestring(v))
2668 2667 for k, v in repo.ui.configitems('committemplate'))
2669 2668
2670 2669 if not extramsg:
2671 2670 extramsg = '' # ensure that extramsg is string
2672 2671
2673 2672 ui.pushbuffer()
2674 2673 t.show(ctx, extramsg=extramsg)
2675 2674 return ui.popbuffer()
2676 2675
2677 2676 def hgprefix(msg):
2678 2677 return "\n".join(["HG: %s" % a for a in msg.split("\n") if a])
2679 2678
2680 2679 def buildcommittext(repo, ctx, subs, extramsg):
2681 2680 edittext = []
2682 2681 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2683 2682 if ctx.description():
2684 2683 edittext.append(ctx.description())
2685 2684 edittext.append("")
2686 2685 edittext.append("") # Empty line between message and comments.
2687 2686 edittext.append(hgprefix(_("Enter commit message."
2688 2687 " Lines beginning with 'HG:' are removed.")))
2689 2688 edittext.append(hgprefix(extramsg))
2690 2689 edittext.append("HG: --")
2691 2690 edittext.append(hgprefix(_("user: %s") % ctx.user()))
2692 2691 if ctx.p2():
2693 2692 edittext.append(hgprefix(_("branch merge")))
2694 2693 if ctx.branch():
2695 2694 edittext.append(hgprefix(_("branch '%s'") % ctx.branch()))
2696 2695 if bookmarks.isactivewdirparent(repo):
2697 2696 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark))
2698 2697 edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs])
2699 2698 edittext.extend([hgprefix(_("added %s") % f) for f in added])
2700 2699 edittext.extend([hgprefix(_("changed %s") % f) for f in modified])
2701 2700 edittext.extend([hgprefix(_("removed %s") % f) for f in removed])
2702 2701 if not added and not modified and not removed:
2703 2702 edittext.append(hgprefix(_("no files changed")))
2704 2703 edittext.append("")
2705 2704
2706 2705 return "\n".join(edittext)
2707 2706
2708 2707 def commitstatus(repo, node, branch, bheads=None, opts=None):
2709 2708 if opts is None:
2710 2709 opts = {}
2711 2710 ctx = repo[node]
2712 2711 parents = ctx.parents()
2713 2712
2714 2713 if (not opts.get('amend') and bheads and node not in bheads and not
2715 2714 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2716 2715 repo.ui.status(_('created new head\n'))
2717 2716 # The message is not printed for initial roots. For the other
2718 2717 # changesets, it is printed in the following situations:
2719 2718 #
2720 2719 # Par column: for the 2 parents with ...
2721 2720 # N: null or no parent
2722 2721 # B: parent is on another named branch
2723 2722 # C: parent is a regular non head changeset
2724 2723 # H: parent was a branch head of the current branch
2725 2724 # Msg column: whether we print "created new head" message
2726 2725 # In the following, it is assumed that there already exists some
2727 2726 # initial branch heads of the current branch, otherwise nothing is
2728 2727 # printed anyway.
2729 2728 #
2730 2729 # Par Msg Comment
2731 2730 # N N y additional topo root
2732 2731 #
2733 2732 # B N y additional branch root
2734 2733 # C N y additional topo head
2735 2734 # H N n usual case
2736 2735 #
2737 2736 # B B y weird additional branch root
2738 2737 # C B y branch merge
2739 2738 # H B n merge with named branch
2740 2739 #
2741 2740 # C C y additional head from merge
2742 2741 # C H n merge with a head
2743 2742 #
2744 2743 # H H n head merge: head count decreases
2745 2744
2746 2745 if not opts.get('close_branch'):
2747 2746 for r in parents:
2748 2747 if r.closesbranch() and r.branch() == branch:
2749 2748 repo.ui.status(_('reopening closed branch head %d\n') % r.rev())
2750 2749
2751 2750 if repo.ui.debugflag:
2752 2751 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx.hex()))
2753 2752 elif repo.ui.verbose:
2754 2753 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx))
2755 2754
2756 2755 def postcommitstatus(repo, pats, opts):
2757 2756 return repo.status(match=scmutil.match(repo[None], pats, opts))
2758 2757
2759 2758 def revert(ui, repo, ctx, parents, *pats, **opts):
2760 2759 opts = pycompat.byteskwargs(opts)
2761 2760 parent, p2 = parents
2762 2761 node = ctx.node()
2763 2762
2764 2763 mf = ctx.manifest()
2765 2764 if node == p2:
2766 2765 parent = p2
2767 2766
2768 2767 # need all matching names in dirstate and manifest of target rev,
2769 2768 # so have to walk both. do not print errors if files exist in one
2770 2769 # but not other. in both cases, filesets should be evaluated against
2771 2770 # workingctx to get consistent result (issue4497). this means 'set:**'
2772 2771 # cannot be used to select missing files from target rev.
2773 2772
2774 2773 # `names` is a mapping for all elements in working copy and target revision
2775 2774 # The mapping is in the form:
2776 2775 # <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2777 2776 names = {}
2778 2777
2779 2778 with repo.wlock():
2780 2779 ## filling of the `names` mapping
2781 2780 # walk dirstate to fill `names`
2782 2781
2783 2782 interactive = opts.get('interactive', False)
2784 2783 wctx = repo[None]
2785 2784 m = scmutil.match(wctx, pats, opts)
2786 2785
2787 2786 # we'll need this later
2788 2787 targetsubs = sorted(s for s in wctx.substate if m(s))
2789 2788
2790 2789 if not m.always():
2791 2790 matcher = matchmod.badmatch(m, lambda x, y: False)
2792 2791 for abs in wctx.walk(matcher):
2793 2792 names[abs] = m.rel(abs), m.exact(abs)
2794 2793
2795 2794 # walk target manifest to fill `names`
2796 2795
2797 2796 def badfn(path, msg):
2798 2797 if path in names:
2799 2798 return
2800 2799 if path in ctx.substate:
2801 2800 return
2802 2801 path_ = path + '/'
2803 2802 for f in names:
2804 2803 if f.startswith(path_):
2805 2804 return
2806 2805 ui.warn("%s: %s\n" % (m.rel(path), msg))
2807 2806
2808 2807 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
2809 2808 if abs not in names:
2810 2809 names[abs] = m.rel(abs), m.exact(abs)
2811 2810
2812 2811 # Find status of all file in `names`.
2813 2812 m = scmutil.matchfiles(repo, names)
2814 2813
2815 2814 changes = repo.status(node1=node, match=m,
2816 2815 unknown=True, ignored=True, clean=True)
2817 2816 else:
2818 2817 changes = repo.status(node1=node, match=m)
2819 2818 for kind in changes:
2820 2819 for abs in kind:
2821 2820 names[abs] = m.rel(abs), m.exact(abs)
2822 2821
2823 2822 m = scmutil.matchfiles(repo, names)
2824 2823
2825 2824 modified = set(changes.modified)
2826 2825 added = set(changes.added)
2827 2826 removed = set(changes.removed)
2828 2827 _deleted = set(changes.deleted)
2829 2828 unknown = set(changes.unknown)
2830 2829 unknown.update(changes.ignored)
2831 2830 clean = set(changes.clean)
2832 2831 modadded = set()
2833 2832
2834 2833 # We need to account for the state of the file in the dirstate,
2835 2834 # even when we revert against something else than parent. This will
2836 2835 # slightly alter the behavior of revert (doing back up or not, delete
2837 2836 # or just forget etc).
2838 2837 if parent == node:
2839 2838 dsmodified = modified
2840 2839 dsadded = added
2841 2840 dsremoved = removed
2842 2841 # store all local modifications, useful later for rename detection
2843 2842 localchanges = dsmodified | dsadded
2844 2843 modified, added, removed = set(), set(), set()
2845 2844 else:
2846 2845 changes = repo.status(node1=parent, match=m)
2847 2846 dsmodified = set(changes.modified)
2848 2847 dsadded = set(changes.added)
2849 2848 dsremoved = set(changes.removed)
2850 2849 # store all local modifications, useful later for rename detection
2851 2850 localchanges = dsmodified | dsadded
2852 2851
2853 2852 # only take into account for removes between wc and target
2854 2853 clean |= dsremoved - removed
2855 2854 dsremoved &= removed
2856 2855 # distinct between dirstate remove and other
2857 2856 removed -= dsremoved
2858 2857
2859 2858 modadded = added & dsmodified
2860 2859 added -= modadded
2861 2860
2862 2861 # tell newly modified apart.
2863 2862 dsmodified &= modified
2864 2863 dsmodified |= modified & dsadded # dirstate added may need backup
2865 2864 modified -= dsmodified
2866 2865
2867 2866 # We need to wait for some post-processing to update this set
2868 2867 # before making the distinction. The dirstate will be used for
2869 2868 # that purpose.
2870 2869 dsadded = added
2871 2870
2872 2871 # in case of merge, files that are actually added can be reported as
2873 2872 # modified, we need to post process the result
2874 2873 if p2 != nullid:
2875 2874 mergeadd = set(dsmodified)
2876 2875 for path in dsmodified:
2877 2876 if path in mf:
2878 2877 mergeadd.remove(path)
2879 2878 dsadded |= mergeadd
2880 2879 dsmodified -= mergeadd
2881 2880
2882 2881 # if f is a rename, update `names` to also revert the source
2883 2882 cwd = repo.getcwd()
2884 2883 for f in localchanges:
2885 2884 src = repo.dirstate.copied(f)
2886 2885 # XXX should we check for rename down to target node?
2887 2886 if src and src not in names and repo.dirstate[src] == 'r':
2888 2887 dsremoved.add(src)
2889 2888 names[src] = (repo.pathto(src, cwd), True)
2890 2889
2891 2890 # determine the exact nature of the deleted changesets
2892 2891 deladded = set(_deleted)
2893 2892 for path in _deleted:
2894 2893 if path in mf:
2895 2894 deladded.remove(path)
2896 2895 deleted = _deleted - deladded
2897 2896
2898 2897 # distinguish between file to forget and the other
2899 2898 added = set()
2900 2899 for abs in dsadded:
2901 2900 if repo.dirstate[abs] != 'a':
2902 2901 added.add(abs)
2903 2902 dsadded -= added
2904 2903
2905 2904 for abs in deladded:
2906 2905 if repo.dirstate[abs] == 'a':
2907 2906 dsadded.add(abs)
2908 2907 deladded -= dsadded
2909 2908
2910 2909 # For files marked as removed, we check if an unknown file is present at
2911 2910 # the same path. If a such file exists it may need to be backed up.
2912 2911 # Making the distinction at this stage helps have simpler backup
2913 2912 # logic.
2914 2913 removunk = set()
2915 2914 for abs in removed:
2916 2915 target = repo.wjoin(abs)
2917 2916 if os.path.lexists(target):
2918 2917 removunk.add(abs)
2919 2918 removed -= removunk
2920 2919
2921 2920 dsremovunk = set()
2922 2921 for abs in dsremoved:
2923 2922 target = repo.wjoin(abs)
2924 2923 if os.path.lexists(target):
2925 2924 dsremovunk.add(abs)
2926 2925 dsremoved -= dsremovunk
2927 2926
2928 2927 # action to be actually performed by revert
2929 2928 # (<list of file>, message>) tuple
2930 2929 actions = {'revert': ([], _('reverting %s\n')),
2931 2930 'add': ([], _('adding %s\n')),
2932 2931 'remove': ([], _('removing %s\n')),
2933 2932 'drop': ([], _('removing %s\n')),
2934 2933 'forget': ([], _('forgetting %s\n')),
2935 2934 'undelete': ([], _('undeleting %s\n')),
2936 2935 'noop': (None, _('no changes needed to %s\n')),
2937 2936 'unknown': (None, _('file not managed: %s\n')),
2938 2937 }
2939 2938
2940 2939 # "constant" that convey the backup strategy.
2941 2940 # All set to `discard` if `no-backup` is set do avoid checking
2942 2941 # no_backup lower in the code.
2943 2942 # These values are ordered for comparison purposes
2944 2943 backupinteractive = 3 # do backup if interactively modified
2945 2944 backup = 2 # unconditionally do backup
2946 2945 check = 1 # check if the existing file differs from target
2947 2946 discard = 0 # never do backup
2948 2947 if opts.get('no_backup'):
2949 2948 backupinteractive = backup = check = discard
2950 2949 if interactive:
2951 2950 dsmodifiedbackup = backupinteractive
2952 2951 else:
2953 2952 dsmodifiedbackup = backup
2954 2953 tobackup = set()
2955 2954
2956 2955 backupanddel = actions['remove']
2957 2956 if not opts.get('no_backup'):
2958 2957 backupanddel = actions['drop']
2959 2958
2960 2959 disptable = (
2961 2960 # dispatch table:
2962 2961 # file state
2963 2962 # action
2964 2963 # make backup
2965 2964
2966 2965 ## Sets that results that will change file on disk
2967 2966 # Modified compared to target, no local change
2968 2967 (modified, actions['revert'], discard),
2969 2968 # Modified compared to target, but local file is deleted
2970 2969 (deleted, actions['revert'], discard),
2971 2970 # Modified compared to target, local change
2972 2971 (dsmodified, actions['revert'], dsmodifiedbackup),
2973 2972 # Added since target
2974 2973 (added, actions['remove'], discard),
2975 2974 # Added in working directory
2976 2975 (dsadded, actions['forget'], discard),
2977 2976 # Added since target, have local modification
2978 2977 (modadded, backupanddel, backup),
2979 2978 # Added since target but file is missing in working directory
2980 2979 (deladded, actions['drop'], discard),
2981 2980 # Removed since target, before working copy parent
2982 2981 (removed, actions['add'], discard),
2983 2982 # Same as `removed` but an unknown file exists at the same path
2984 2983 (removunk, actions['add'], check),
2985 2984 # Removed since targe, marked as such in working copy parent
2986 2985 (dsremoved, actions['undelete'], discard),
2987 2986 # Same as `dsremoved` but an unknown file exists at the same path
2988 2987 (dsremovunk, actions['undelete'], check),
2989 2988 ## the following sets does not result in any file changes
2990 2989 # File with no modification
2991 2990 (clean, actions['noop'], discard),
2992 2991 # Existing file, not tracked anywhere
2993 2992 (unknown, actions['unknown'], discard),
2994 2993 )
2995 2994
2996 2995 for abs, (rel, exact) in sorted(names.items()):
2997 2996 # target file to be touch on disk (relative to cwd)
2998 2997 target = repo.wjoin(abs)
2999 2998 # search the entry in the dispatch table.
3000 2999 # if the file is in any of these sets, it was touched in the working
3001 3000 # directory parent and we are sure it needs to be reverted.
3002 3001 for table, (xlist, msg), dobackup in disptable:
3003 3002 if abs not in table:
3004 3003 continue
3005 3004 if xlist is not None:
3006 3005 xlist.append(abs)
3007 3006 if dobackup:
3008 3007 # If in interactive mode, don't automatically create
3009 3008 # .orig files (issue4793)
3010 3009 if dobackup == backupinteractive:
3011 3010 tobackup.add(abs)
3012 3011 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
3013 3012 bakname = scmutil.origpath(ui, repo, rel)
3014 3013 ui.note(_('saving current version of %s as %s\n') %
3015 3014 (rel, bakname))
3016 3015 if not opts.get('dry_run'):
3017 3016 if interactive:
3018 3017 util.copyfile(target, bakname)
3019 3018 else:
3020 3019 util.rename(target, bakname)
3021 3020 if opts.get('dry_run'):
3022 3021 if ui.verbose or not exact:
3023 3022 ui.status(msg % rel)
3024 3023 elif exact:
3025 3024 ui.warn(msg % rel)
3026 3025 break
3027 3026
3028 3027 if not opts.get('dry_run'):
3029 3028 needdata = ('revert', 'add', 'undelete')
3030 3029 oplist = [actions[name][0] for name in needdata]
3031 3030 prefetch = scmutil.prefetchfiles
3032 3031 matchfiles = scmutil.matchfiles
3033 3032 prefetch(repo, [ctx.rev()],
3034 3033 matchfiles(repo,
3035 3034 [f for sublist in oplist for f in sublist]))
3036 3035 _performrevert(repo, parents, ctx, names, actions, interactive,
3037 3036 tobackup)
3038 3037
3039 3038 if targetsubs:
3040 3039 # Revert the subrepos on the revert list
3041 3040 for sub in targetsubs:
3042 3041 try:
3043 3042 wctx.sub(sub).revert(ctx.substate[sub], *pats,
3044 3043 **pycompat.strkwargs(opts))
3045 3044 except KeyError:
3046 3045 raise error.Abort("subrepository '%s' does not exist in %s!"
3047 3046 % (sub, short(ctx.node())))
3048 3047
3049 3048 def _performrevert(repo, parents, ctx, names, actions, interactive=False,
3050 3049 tobackup=None):
3051 3050 """function that actually perform all the actions computed for revert
3052 3051
3053 3052 This is an independent function to let extension to plug in and react to
3054 3053 the imminent revert.
3055 3054
3056 3055 Make sure you have the working directory locked when calling this function.
3057 3056 """
3058 3057 parent, p2 = parents
3059 3058 node = ctx.node()
3060 3059 excluded_files = []
3061 3060
3062 3061 def checkout(f):
3063 3062 fc = ctx[f]
3064 3063 repo.wwrite(f, fc.data(), fc.flags())
3065 3064
3066 3065 def doremove(f):
3067 3066 try:
3068 3067 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
3069 3068 repo.wvfs.unlinkpath(f, rmdir=rmdir)
3070 3069 except OSError:
3071 3070 pass
3072 3071 repo.dirstate.remove(f)
3073 3072
3074 3073 def prntstatusmsg(action, f):
3075 3074 rel, exact = names[f]
3076 3075 if repo.ui.verbose or not exact:
3077 3076 repo.ui.status(actions[action][1] % rel)
3078 3077
3079 3078 audit_path = pathutil.pathauditor(repo.root, cached=True)
3080 3079 for f in actions['forget'][0]:
3081 3080 if interactive:
3082 3081 choice = repo.ui.promptchoice(
3083 3082 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
3084 3083 if choice == 0:
3085 3084 prntstatusmsg('forget', f)
3086 3085 repo.dirstate.drop(f)
3087 3086 else:
3088 3087 excluded_files.append(f)
3089 3088 else:
3090 3089 prntstatusmsg('forget', f)
3091 3090 repo.dirstate.drop(f)
3092 3091 for f in actions['remove'][0]:
3093 3092 audit_path(f)
3094 3093 if interactive:
3095 3094 choice = repo.ui.promptchoice(
3096 3095 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
3097 3096 if choice == 0:
3098 3097 prntstatusmsg('remove', f)
3099 3098 doremove(f)
3100 3099 else:
3101 3100 excluded_files.append(f)
3102 3101 else:
3103 3102 prntstatusmsg('remove', f)
3104 3103 doremove(f)
3105 3104 for f in actions['drop'][0]:
3106 3105 audit_path(f)
3107 3106 prntstatusmsg('drop', f)
3108 3107 repo.dirstate.remove(f)
3109 3108
3110 3109 normal = None
3111 3110 if node == parent:
3112 3111 # We're reverting to our parent. If possible, we'd like status
3113 3112 # to report the file as clean. We have to use normallookup for
3114 3113 # merges to avoid losing information about merged/dirty files.
3115 3114 if p2 != nullid:
3116 3115 normal = repo.dirstate.normallookup
3117 3116 else:
3118 3117 normal = repo.dirstate.normal
3119 3118
3120 3119 newlyaddedandmodifiedfiles = set()
3121 3120 if interactive:
3122 3121 # Prompt the user for changes to revert
3123 3122 torevert = [f for f in actions['revert'][0] if f not in excluded_files]
3124 3123 m = scmutil.matchfiles(repo, torevert)
3125 3124 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
3126 3125 diffopts.nodates = True
3127 3126 diffopts.git = True
3128 3127 operation = 'discard'
3129 3128 reversehunks = True
3130 3129 if node != parent:
3131 3130 operation = 'apply'
3132 3131 reversehunks = False
3133 3132 if reversehunks:
3134 3133 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
3135 3134 else:
3136 3135 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
3137 3136 originalchunks = patch.parsepatch(diff)
3138 3137
3139 3138 try:
3140 3139
3141 3140 chunks, opts = recordfilter(repo.ui, originalchunks,
3142 3141 operation=operation)
3143 3142 if reversehunks:
3144 3143 chunks = patch.reversehunks(chunks)
3145 3144
3146 3145 except error.PatchError as err:
3147 3146 raise error.Abort(_('error parsing patch: %s') % err)
3148 3147
3149 3148 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
3150 3149 if tobackup is None:
3151 3150 tobackup = set()
3152 3151 # Apply changes
3153 3152 fp = stringio()
3154 3153 # chunks are serialized per file, but files aren't sorted
3155 3154 for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))):
3156 3155 prntstatusmsg('revert', f)
3157 3156 for c in chunks:
3158 3157 if ishunk(c):
3159 3158 abs = c.header.filename()
3160 3159 # Create a backup file only if this hunk should be backed up
3161 3160 if c.header.filename() in tobackup:
3162 3161 target = repo.wjoin(abs)
3163 3162 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
3164 3163 util.copyfile(target, bakname)
3165 3164 tobackup.remove(abs)
3166 3165 c.write(fp)
3167 3166 dopatch = fp.tell()
3168 3167 fp.seek(0)
3169 3168 if dopatch:
3170 3169 try:
3171 3170 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
3172 3171 except error.PatchError as err:
3173 3172 raise error.Abort(pycompat.bytestr(err))
3174 3173 del fp
3175 3174 else:
3176 3175 for f in actions['revert'][0]:
3177 3176 prntstatusmsg('revert', f)
3178 3177 checkout(f)
3179 3178 if normal:
3180 3179 normal(f)
3181 3180
3182 3181 for f in actions['add'][0]:
3183 3182 # Don't checkout modified files, they are already created by the diff
3184 3183 if f not in newlyaddedandmodifiedfiles:
3185 3184 prntstatusmsg('add', f)
3186 3185 checkout(f)
3187 3186 repo.dirstate.add(f)
3188 3187
3189 3188 normal = repo.dirstate.normallookup
3190 3189 if node == parent and p2 == nullid:
3191 3190 normal = repo.dirstate.normal
3192 3191 for f in actions['undelete'][0]:
3193 3192 prntstatusmsg('undelete', f)
3194 3193 checkout(f)
3195 3194 normal(f)
3196 3195
3197 3196 copied = copies.pathcopies(repo[parent], ctx)
3198 3197
3199 3198 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3200 3199 if f in copied:
3201 3200 repo.dirstate.copy(copied[f], f)
3202 3201
3203 3202 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3204 3203 # commands.outgoing. "missing" is "missing" of the result of
3205 3204 # "findcommonoutgoing()"
3206 3205 outgoinghooks = util.hooks()
3207 3206
3208 3207 # a list of (ui, repo) functions called by commands.summary
3209 3208 summaryhooks = util.hooks()
3210 3209
3211 3210 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3212 3211 #
3213 3212 # functions should return tuple of booleans below, if 'changes' is None:
3214 3213 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3215 3214 #
3216 3215 # otherwise, 'changes' is a tuple of tuples below:
3217 3216 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3218 3217 # - (desturl, destbranch, destpeer, outgoing)
3219 3218 summaryremotehooks = util.hooks()
3220 3219
3221 3220 # A list of state files kept by multistep operations like graft.
3222 3221 # Since graft cannot be aborted, it is considered 'clearable' by update.
3223 3222 # note: bisect is intentionally excluded
3224 3223 # (state file, clearable, allowcommit, error, hint)
3225 3224 unfinishedstates = [
3226 3225 ('graftstate', True, False, _('graft in progress'),
3227 3226 _("use 'hg graft --continue' or 'hg graft --stop' to stop")),
3228 3227 ('updatestate', True, False, _('last update was interrupted'),
3229 3228 _("use 'hg update' to get a consistent checkout"))
3230 3229 ]
3231 3230
3232 3231 def checkunfinished(repo, commit=False):
3233 3232 '''Look for an unfinished multistep operation, like graft, and abort
3234 3233 if found. It's probably good to check this right before
3235 3234 bailifchanged().
3236 3235 '''
3237 3236 # Check for non-clearable states first, so things like rebase will take
3238 3237 # precedence over update.
3239 3238 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3240 3239 if clearable or (commit and allowcommit):
3241 3240 continue
3242 3241 if repo.vfs.exists(f):
3243 3242 raise error.Abort(msg, hint=hint)
3244 3243
3245 3244 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3246 3245 if not clearable or (commit and allowcommit):
3247 3246 continue
3248 3247 if repo.vfs.exists(f):
3249 3248 raise error.Abort(msg, hint=hint)
3250 3249
3251 3250 def clearunfinished(repo):
3252 3251 '''Check for unfinished operations (as above), and clear the ones
3253 3252 that are clearable.
3254 3253 '''
3255 3254 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3256 3255 if not clearable and repo.vfs.exists(f):
3257 3256 raise error.Abort(msg, hint=hint)
3258 3257 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3259 3258 if clearable and repo.vfs.exists(f):
3260 3259 util.unlink(repo.vfs.join(f))
3261 3260
3262 3261 afterresolvedstates = [
3263 3262 ('graftstate',
3264 3263 _('hg graft --continue')),
3265 3264 ]
3266 3265
3267 3266 def howtocontinue(repo):
3268 3267 '''Check for an unfinished operation and return the command to finish
3269 3268 it.
3270 3269
3271 3270 afterresolvedstates tuples define a .hg/{file} and the corresponding
3272 3271 command needed to finish it.
3273 3272
3274 3273 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
3275 3274 a boolean.
3276 3275 '''
3277 3276 contmsg = _("continue: %s")
3278 3277 for f, msg in afterresolvedstates:
3279 3278 if repo.vfs.exists(f):
3280 3279 return contmsg % msg, True
3281 3280 if repo[None].dirty(missing=True, merge=False, branch=False):
3282 3281 return contmsg % _("hg commit"), False
3283 3282 return None, None
3284 3283
3285 3284 def checkafterresolved(repo):
3286 3285 '''Inform the user about the next action after completing hg resolve
3287 3286
3288 3287 If there's a matching afterresolvedstates, howtocontinue will yield
3289 3288 repo.ui.warn as the reporter.
3290 3289
3291 3290 Otherwise, it will yield repo.ui.note.
3292 3291 '''
3293 3292 msg, warning = howtocontinue(repo)
3294 3293 if msg is not None:
3295 3294 if warning:
3296 3295 repo.ui.warn("%s\n" % msg)
3297 3296 else:
3298 3297 repo.ui.note("%s\n" % msg)
3299 3298
3300 3299 def wrongtooltocontinue(repo, task):
3301 3300 '''Raise an abort suggesting how to properly continue if there is an
3302 3301 active task.
3303 3302
3304 3303 Uses howtocontinue() to find the active task.
3305 3304
3306 3305 If there's no task (repo.ui.note for 'hg commit'), it does not offer
3307 3306 a hint.
3308 3307 '''
3309 3308 after = howtocontinue(repo)
3310 3309 hint = None
3311 3310 if after[1]:
3312 3311 hint = after[0]
3313 3312 raise error.Abort(_('no %s in progress') % task, hint=hint)
@@ -1,717 +1,718 b''
1 1 $ HGFOO=BAR; export HGFOO
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [alias]
4 4 > # should clobber ci but not commit (issue2993)
5 5 > ci = version
6 6 > myinit = init
7 7 > myinit:doc = This is my documented alias for init.
8 8 > myinit:help = [OPTIONS] [BLA] [BLE]
9 9 > mycommit = commit
10 10 > mycommit:doc = This is my alias with only doc.
11 11 > optionalrepo = showconfig alias.myinit
12 12 > cleanstatus = status -c
13 13 > cleanstatus:help = [ONLYHELPHERE]
14 14 > unknown = bargle
15 15 > ambiguous = s
16 16 > recursive = recursive
17 17 > disabled = email
18 18 > nodefinition =
19 19 > noclosingquotation = '
20 20 > no--cwd = status --cwd elsewhere
21 21 > no-R = status -R elsewhere
22 22 > no--repo = status --repo elsewhere
23 23 > no--repository = status --repository elsewhere
24 24 > no--config = status --config a.config=1
25 25 > mylog = log
26 26 > lognull = log -r null
27 27 > lognull:doc = Logs the null rev
28 28 > lognull:help = foo bar baz
29 29 > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
30 30 > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
31 31 > dln = lognull --debug
32 32 > recursivedoc = dln
33 33 > recursivedoc:doc = Logs the null rev in debug mode
34 34 > nousage = rollback
35 35 > put = export -r 0 -o "\$FOO/%R.diff"
36 36 > blank = !printf '\n'
37 37 > self = !printf '\$0\n'
38 38 > echoall = !printf '\$@\n'
39 39 > echo1 = !printf '\$1\n'
40 40 > echo2 = !printf '\$2\n'
41 41 > echo13 = !printf '\$1 \$3\n'
42 42 > echotokens = !printf "%s\n" "\$@"
43 43 > count = !hg log -r "\$@" --template=. | wc -c | sed -e 's/ //g'
44 44 > mcount = !hg log \$@ --template=. | wc -c | sed -e 's/ //g'
45 45 > rt = root
46 46 > tglog = log -G --template "{rev}:{node|short}: '{desc}' {branches}\n"
47 47 > idalias = id
48 48 > idaliaslong = id
49 49 > idaliasshell = !echo test
50 50 > parentsshell1 = !echo one
51 51 > parentsshell2 = !echo two
52 52 > escaped1 = !printf 'test\$\$test\n'
53 53 > escaped2 = !sh -c 'echo "HGFOO is \$\$HGFOO"'
54 54 > escaped3 = !sh -c 'echo "\$1 is \$\$\$1"'
55 55 > escaped4 = !printf '\$\$0 \$\$@\n'
56 56 > exit1 = !sh -c 'exit 1'
57 57 >
58 58 > [defaults]
59 59 > mylog = -q
60 60 > lognull = -q
61 61 > log = -v
62 62 > EOF
63 63
64 64 basic
65 65
66 66 $ hg myinit alias
67 67
68 68 help
69 69
70 70 $ hg help -c | grep myinit
71 71 myinit This is my documented alias for init.
72 72 $ hg help -c | grep mycommit
73 73 mycommit This is my alias with only doc.
74 74 $ hg help -c | grep cleanstatus
75 75 cleanstatus show changed files in the working directory
76 76 $ hg help -c | grep lognull
77 77 lognull Logs the null rev
78 78 $ hg help -c | grep dln
79 79 dln Logs the null rev
80 80 $ hg help -c | grep recursivedoc
81 81 recursivedoc Logs the null rev in debug mode
82 82 $ hg help myinit
83 83 hg myinit [OPTIONS] [BLA] [BLE]
84 84
85 85 alias for: hg init
86 86
87 87 This is my documented alias for init.
88 88
89 89 defined by: * (glob)
90 90 */* (glob) (?)
91 91 */* (glob) (?)
92 92 */* (glob) (?)
93 93
94 94 options:
95 95
96 96 -e --ssh CMD specify ssh command to use
97 97 --remotecmd CMD specify hg command to run on the remote side
98 98 --insecure do not verify server certificate (ignoring web.cacerts
99 99 config)
100 100
101 101 (some details hidden, use --verbose to show complete help)
102 102
103 103 $ hg help mycommit
104 104 hg mycommit [OPTION]... [FILE]...
105 105
106 106 alias for: hg commit
107 107
108 108 This is my alias with only doc.
109 109
110 110 defined by: * (glob)
111 111 */* (glob) (?)
112 112 */* (glob) (?)
113 113 */* (glob) (?)
114 114
115 115 options ([+] can be repeated):
116 116
117 117 -A --addremove mark new/missing files as added/removed before
118 118 committing
119 119 --close-branch mark a branch head as closed
120 120 --amend amend the parent of the working directory
121 121 -s --secret use the secret phase for committing
122 122 -e --edit invoke editor on commit messages
123 123 -i --interactive use interactive mode
124 124 -I --include PATTERN [+] include names matching the given patterns
125 125 -X --exclude PATTERN [+] exclude names matching the given patterns
126 126 -m --message TEXT use text as commit message
127 127 -l --logfile FILE read commit message from file
128 128 -d --date DATE record the specified date as commit date
129 129 -u --user USER record the specified user as committer
130 130 -S --subrepos recurse into subrepositories
131 131
132 132 (some details hidden, use --verbose to show complete help)
133 133
134 134 $ hg help cleanstatus
135 135 hg cleanstatus [ONLYHELPHERE]
136 136
137 137 alias for: hg status -c
138 138
139 139 show changed files in the working directory
140 140
141 141 Show status of files in the repository. If names are given, only files
142 142 that match are shown. Files that are clean or ignored or the source of a
143 143 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
144 144 -C/--copies or -A/--all are given. Unless options described with "show
145 145 only ..." are given, the options -mardu are used.
146 146
147 147 Option -q/--quiet hides untracked (unknown and ignored) files unless
148 148 explicitly requested with -u/--unknown or -i/--ignored.
149 149
150 150 Note:
151 151 'hg status' may appear to disagree with diff if permissions have
152 152 changed or a merge has occurred. The standard diff format does not
153 153 report permission changes and diff only reports changes relative to one
154 154 merge parent.
155 155
156 156 If one revision is given, it is used as the base revision. If two
157 157 revisions are given, the differences between them are shown. The --change
158 158 option can also be used as a shortcut to list the changed files of a
159 159 revision from its first parent.
160 160
161 161 The codes used to show the status of files are:
162 162
163 163 M = modified
164 164 A = added
165 165 R = removed
166 166 C = clean
167 167 ! = missing (deleted by non-hg command, but still tracked)
168 168 ? = not tracked
169 169 I = ignored
170 170 = origin of the previous file (with --copies)
171 171
172 172 Returns 0 on success.
173 173
174 174 defined by: * (glob)
175 175 */* (glob) (?)
176 176 */* (glob) (?)
177 177 */* (glob) (?)
178 178
179 179 options ([+] can be repeated):
180 180
181 181 -A --all show status of all files
182 182 -m --modified show only modified files
183 183 -a --added show only added files
184 184 -r --removed show only removed files
185 185 -d --deleted show only deleted (but tracked) files
186 186 -c --clean show only files without changes
187 187 -u --unknown show only unknown (not tracked) files
188 188 -i --ignored show only ignored files
189 189 -n --no-status hide status prefix
190 190 -C --copies show source of copied files
191 191 -0 --print0 end filenames with NUL, for use with xargs
192 192 --rev REV [+] show difference from revision
193 193 --change REV list the changed files of a revision
194 194 -I --include PATTERN [+] include names matching the given patterns
195 195 -X --exclude PATTERN [+] exclude names matching the given patterns
196 196 -S --subrepos recurse into subrepositories
197 -T --template TEMPLATE display with template
197 198
198 199 (some details hidden, use --verbose to show complete help)
199 200
200 201 $ hg help recursivedoc | head -n 5
201 202 hg recursivedoc foo bar baz
202 203
203 204 alias for: hg dln
204 205
205 206 Logs the null rev in debug mode
206 207
207 208 unknown
208 209
209 210 $ hg unknown
210 211 abort: alias 'unknown' resolves to unknown command 'bargle'
211 212 [255]
212 213 $ hg help unknown
213 214 alias 'unknown' resolves to unknown command 'bargle'
214 215
215 216
216 217 ambiguous
217 218
218 219 $ hg ambiguous
219 220 abort: alias 'ambiguous' resolves to ambiguous command 's'
220 221 [255]
221 222 $ hg help ambiguous
222 223 alias 'ambiguous' resolves to ambiguous command 's'
223 224
224 225
225 226 recursive
226 227
227 228 $ hg recursive
228 229 abort: alias 'recursive' resolves to unknown command 'recursive'
229 230 [255]
230 231 $ hg help recursive
231 232 alias 'recursive' resolves to unknown command 'recursive'
232 233
233 234
234 235 disabled
235 236
236 237 $ hg disabled
237 238 abort: alias 'disabled' resolves to unknown command 'email'
238 239 ('email' is provided by 'patchbomb' extension)
239 240 [255]
240 241 $ hg help disabled
241 242 alias 'disabled' resolves to unknown command 'email'
242 243
243 244 'email' is provided by the following extension:
244 245
245 246 patchbomb command to send changesets as (a series of) patch emails
246 247
247 248 (use 'hg help extensions' for information on enabling extensions)
248 249
249 250
250 251 no definition
251 252
252 253 $ hg nodef
253 254 abort: no definition for alias 'nodefinition'
254 255 [255]
255 256 $ hg help nodef
256 257 no definition for alias 'nodefinition'
257 258
258 259
259 260 no closing quotation
260 261
261 262 $ hg noclosing
262 263 abort: error in definition for alias 'noclosingquotation': No closing quotation
263 264 [255]
264 265 $ hg help noclosing
265 266 error in definition for alias 'noclosingquotation': No closing quotation
266 267
267 268 "--" in alias definition should be preserved
268 269
269 270 $ hg --config alias.dash='cat --' -R alias dash -r0
270 271 abort: -r0 not under root '$TESTTMP/alias'
271 272 (consider using '--cwd alias')
272 273 [255]
273 274
274 275 invalid options
275 276
276 277 $ hg no--cwd
277 278 abort: error in definition for alias 'no--cwd': --cwd may only be given on the command line
278 279 [255]
279 280 $ hg help no--cwd
280 281 error in definition for alias 'no--cwd': --cwd may only be given on the
281 282 command line
282 283 $ hg no-R
283 284 abort: error in definition for alias 'no-R': -R may only be given on the command line
284 285 [255]
285 286 $ hg help no-R
286 287 error in definition for alias 'no-R': -R may only be given on the command line
287 288 $ hg no--repo
288 289 abort: error in definition for alias 'no--repo': --repo may only be given on the command line
289 290 [255]
290 291 $ hg help no--repo
291 292 error in definition for alias 'no--repo': --repo may only be given on the
292 293 command line
293 294 $ hg no--repository
294 295 abort: error in definition for alias 'no--repository': --repository may only be given on the command line
295 296 [255]
296 297 $ hg help no--repository
297 298 error in definition for alias 'no--repository': --repository may only be given
298 299 on the command line
299 300 $ hg no--config
300 301 abort: error in definition for alias 'no--config': --config may only be given on the command line
301 302 [255]
302 303 $ hg no --config alias.no='--repo elsewhere --cwd elsewhere status'
303 304 abort: error in definition for alias 'no': --repo/--cwd may only be given on the command line
304 305 [255]
305 306 $ hg no --config alias.no='--repo elsewhere'
306 307 abort: error in definition for alias 'no': --repo may only be given on the command line
307 308 [255]
308 309
309 310 optional repository
310 311
311 312 #if no-outer-repo
312 313 $ hg optionalrepo
313 314 init
314 315 #endif
315 316 $ cd alias
316 317 $ cat > .hg/hgrc <<EOF
317 318 > [alias]
318 319 > myinit = init -q
319 320 > EOF
320 321 $ hg optionalrepo
321 322 init -q
322 323
323 324 no usage
324 325
325 326 $ hg nousage
326 327 no rollback information available
327 328 [1]
328 329
329 330 $ echo foo > foo
330 331 $ hg commit -Amfoo
331 332 adding foo
332 333
333 334 infer repository
334 335
335 336 $ cd ..
336 337
337 338 #if no-outer-repo
338 339 $ hg shortlog alias/foo
339 340 0 e63c23eaa88a | 1970-01-01 00:00 +0000
340 341 #endif
341 342
342 343 $ cd alias
343 344
344 345 with opts
345 346
346 347 $ hg cleanst
347 348 C foo
348 349
349 350
350 351 with opts and whitespace
351 352
352 353 $ hg shortlog
353 354 0 e63c23eaa88a | 1970-01-01 00:00 +0000
354 355
355 356 positional arguments
356 357
357 358 $ hg positional
358 359 abort: too few arguments for command alias
359 360 [255]
360 361 $ hg positional a
361 362 abort: too few arguments for command alias
362 363 [255]
363 364 $ hg positional 'node|short' rev
364 365 0 e63c23eaa88a | 1970-01-01 00:00 +0000
365 366
366 367 interaction with defaults
367 368
368 369 $ hg mylog
369 370 0:e63c23eaa88a
370 371 $ hg lognull
371 372 -1:000000000000
372 373
373 374
374 375 properly recursive
375 376
376 377 $ hg dln
377 378 changeset: -1:0000000000000000000000000000000000000000
378 379 phase: public
379 380 parent: -1:0000000000000000000000000000000000000000
380 381 parent: -1:0000000000000000000000000000000000000000
381 382 manifest: -1:0000000000000000000000000000000000000000
382 383 user:
383 384 date: Thu Jan 01 00:00:00 1970 +0000
384 385 extra: branch=default
385 386
386 387
387 388
388 389 path expanding
389 390
390 391 $ FOO=`pwd` hg put
391 392 $ cat 0.diff
392 393 # HG changeset patch
393 394 # User test
394 395 # Date 0 0
395 396 # Thu Jan 01 00:00:00 1970 +0000
396 397 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
397 398 # Parent 0000000000000000000000000000000000000000
398 399 foo
399 400
400 401 diff -r 000000000000 -r e63c23eaa88a foo
401 402 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
402 403 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
403 404 @@ -0,0 +1,1 @@
404 405 +foo
405 406
406 407
407 408 simple shell aliases
408 409
409 410 $ hg blank
410 411
411 412 $ hg blank foo
412 413
413 414 $ hg self
414 415 self
415 416 $ hg echoall
416 417
417 418 $ hg echoall foo
418 419 foo
419 420 $ hg echoall 'test $2' foo
420 421 test $2 foo
421 422 $ hg echoall 'test $@' foo '$@'
422 423 test $@ foo $@
423 424 $ hg echoall 'test "$@"' foo '"$@"'
424 425 test "$@" foo "$@"
425 426 $ hg echo1 foo bar baz
426 427 foo
427 428 $ hg echo2 foo bar baz
428 429 bar
429 430 $ hg echo13 foo bar baz test
430 431 foo baz
431 432 $ hg echo2 foo
432 433
433 434 $ hg echotokens
434 435
435 436 $ hg echotokens foo 'bar $1 baz'
436 437 foo
437 438 bar $1 baz
438 439 $ hg echotokens 'test $2' foo
439 440 test $2
440 441 foo
441 442 $ hg echotokens 'test $@' foo '$@'
442 443 test $@
443 444 foo
444 445 $@
445 446 $ hg echotokens 'test "$@"' foo '"$@"'
446 447 test "$@"
447 448 foo
448 449 "$@"
449 450 $ echo bar > bar
450 451 $ hg commit -qA -m bar
451 452 $ hg count .
452 453 1
453 454 $ hg count 'branch(default)'
454 455 2
455 456 $ hg mcount -r '"branch(default)"'
456 457 2
457 458
458 459 $ hg tglog
459 460 @ 1:042423737847: 'bar'
460 461 |
461 462 o 0:e63c23eaa88a: 'foo'
462 463
463 464
464 465
465 466 shadowing
466 467
467 468 $ hg i
468 469 hg: command 'i' is ambiguous:
469 470 idalias idaliaslong idaliasshell identify import incoming init
470 471 [255]
471 472 $ hg id
472 473 042423737847 tip
473 474 $ hg ida
474 475 hg: command 'ida' is ambiguous:
475 476 idalias idaliaslong idaliasshell
476 477 [255]
477 478 $ hg idalias
478 479 042423737847 tip
479 480 $ hg idaliasl
480 481 042423737847 tip
481 482 $ hg idaliass
482 483 test
483 484 $ hg parentsshell
484 485 hg: command 'parentsshell' is ambiguous:
485 486 parentsshell1 parentsshell2
486 487 [255]
487 488 $ hg parentsshell1
488 489 one
489 490 $ hg parentsshell2
490 491 two
491 492
492 493
493 494 shell aliases with global options
494 495
495 496 $ hg init sub
496 497 $ cd sub
497 498 $ hg count 'branch(default)'
498 499 abort: unknown revision 'default'!
499 500 0
500 501 $ hg -v count 'branch(default)'
501 502 abort: unknown revision 'default'!
502 503 0
503 504 $ hg -R .. count 'branch(default)'
504 505 abort: unknown revision 'default'!
505 506 0
506 507 $ hg --cwd .. count 'branch(default)'
507 508 2
508 509 $ hg echoall --cwd ..
509 510
510 511
511 512 "--" passed to shell alias should be preserved
512 513
513 514 $ hg --config alias.printf='!printf "$@"' printf '%s %s %s\n' -- --cwd ..
514 515 -- --cwd ..
515 516
516 517 repo specific shell aliases
517 518
518 519 $ cat >> .hg/hgrc <<EOF
519 520 > [alias]
520 521 > subalias = !echo sub
521 522 > EOF
522 523 $ cat >> ../.hg/hgrc <<EOF
523 524 > [alias]
524 525 > mainalias = !echo main
525 526 > EOF
526 527
527 528
528 529 shell alias defined in current repo
529 530
530 531 $ hg subalias
531 532 sub
532 533 $ hg --cwd .. subalias > /dev/null
533 534 hg: unknown command 'subalias'
534 535 (did you mean idalias?)
535 536 [255]
536 537 $ hg -R .. subalias > /dev/null
537 538 hg: unknown command 'subalias'
538 539 (did you mean idalias?)
539 540 [255]
540 541
541 542
542 543 shell alias defined in other repo
543 544
544 545 $ hg mainalias > /dev/null
545 546 hg: unknown command 'mainalias'
546 547 (did you mean idalias?)
547 548 [255]
548 549 $ hg -R .. mainalias
549 550 main
550 551 $ hg --cwd .. mainalias
551 552 main
552 553
553 554 typos get useful suggestions
554 555 $ hg --cwd .. manalias
555 556 hg: unknown command 'manalias'
556 557 (did you mean one of idalias, mainalias, manifest?)
557 558 [255]
558 559
559 560 shell aliases with escaped $ chars
560 561
561 562 $ hg escaped1
562 563 test$test
563 564 $ hg escaped2
564 565 HGFOO is BAR
565 566 $ hg escaped3 HGFOO
566 567 HGFOO is BAR
567 568 $ hg escaped4 test
568 569 $0 $@
569 570
570 571 abbreviated name, which matches against both shell alias and the
571 572 command provided extension, should be aborted.
572 573
573 574 $ cat >> .hg/hgrc <<EOF
574 575 > [extensions]
575 576 > hgext.rebase =
576 577 > EOF
577 578 #if windows
578 579 $ cat >> .hg/hgrc <<EOF
579 580 > [alias]
580 581 > rebate = !echo this is %HG_ARGS%
581 582 > EOF
582 583 #else
583 584 $ cat >> .hg/hgrc <<EOF
584 585 > [alias]
585 586 > rebate = !echo this is \$HG_ARGS
586 587 > EOF
587 588 #endif
588 589 $ cat >> .hg/hgrc <<EOF
589 590 > rebate:doc = This is my alias which just prints something.
590 591 > rebate:help = [MYARGS]
591 592 > EOF
592 593 $ hg reba
593 594 hg: command 'reba' is ambiguous:
594 595 rebase rebate
595 596 [255]
596 597 $ hg rebat
597 598 this is rebate
598 599 $ hg rebat --foo-bar
599 600 this is rebate --foo-bar
600 601
601 602 help for a shell alias
602 603
603 604 $ hg help -c | grep rebate
604 605 rebate This is my alias which just prints something.
605 606 $ hg help rebate
606 607 hg rebate [MYARGS]
607 608
608 609 shell alias for: echo this is %HG_ARGS% (windows !)
609 610 shell alias for: echo this is $HG_ARGS (no-windows !)
610 611
611 612 This is my alias which just prints something.
612 613
613 614 defined by:* (glob)
614 615 */* (glob) (?)
615 616 */* (glob) (?)
616 617 */* (glob) (?)
617 618
618 619 (some details hidden, use --verbose to show complete help)
619 620
620 621 invalid character in user-specified help
621 622
622 623 >>> with open('.hg/hgrc', 'ab') as f:
623 624 ... f.write(b'[alias]\n'
624 625 ... b'invaliddoc = log\n'
625 626 ... b'invaliddoc:doc = \xc0\n'
626 627 ... b'invalidhelp = log\n'
627 628 ... b'invalidhelp:help = \xc0\n') and None
628 629 $ hg help invaliddoc
629 630 non-ASCII character in alias definition 'invaliddoc:doc'
630 631 $ hg help invalidhelp
631 632 non-ASCII character in alias definition 'invalidhelp:help'
632 633 $ hg invaliddoc
633 634 abort: non-ASCII character in alias definition 'invaliddoc:doc'
634 635 [255]
635 636 $ hg invalidhelp
636 637 abort: non-ASCII character in alias definition 'invalidhelp:help'
637 638 [255]
638 639
639 640 invalid arguments
640 641
641 642 $ hg rt foo
642 643 hg rt: invalid arguments
643 644 hg rt
644 645
645 646 alias for: hg root
646 647
647 648 (use 'hg rt -h' to show more help)
648 649 [255]
649 650
650 651 invalid global arguments for normal commands, aliases, and shell aliases
651 652
652 653 $ hg --invalid root
653 654 hg: option --invalid not recognized
654 655 (use 'hg help -v' for a list of global options)
655 656 [255]
656 657 $ hg --invalid mylog
657 658 hg: option --invalid not recognized
658 659 (use 'hg help -v' for a list of global options)
659 660 [255]
660 661 $ hg --invalid blank
661 662 hg: option --invalid not recognized
662 663 (use 'hg help -v' for a list of global options)
663 664 [255]
664 665
665 666 environment variable changes in alias commands
666 667
667 668 $ cat > $TESTTMP/expandalias.py <<EOF
668 669 > import os
669 670 > from mercurial import cmdutil, commands, registrar
670 671 > cmdtable = {}
671 672 > command = registrar.command(cmdtable)
672 673 > @command(b'expandalias')
673 674 > def expandalias(ui, repo, name):
674 675 > alias = cmdutil.findcmd(name, commands.table)[1][0]
675 676 > ui.write(b'%s args: %s\n' % (name, b' '.join(alias.args)))
676 677 > os.environ['COUNT'] = '2'
677 678 > ui.write(b'%s args: %s (with COUNT=2)\n' % (name, b' '.join(alias.args)))
678 679 > EOF
679 680
680 681 $ cat >> $HGRCPATH <<'EOF'
681 682 > [extensions]
682 683 > expandalias = $TESTTMP/expandalias.py
683 684 > [alias]
684 685 > showcount = log -T "$COUNT" -r .
685 686 > EOF
686 687
687 688 $ COUNT=1 hg expandalias showcount
688 689 showcount args: -T 1 -r .
689 690 showcount args: -T 2 -r . (with COUNT=2)
690 691
691 692 This should show id:
692 693
693 694 $ hg --config alias.log='id' log
694 695 000000000000 tip
695 696
696 697 This shouldn't:
697 698
698 699 $ hg --config alias.log='id' history
699 700
700 701 $ cd ../..
701 702
702 703 return code of command and shell aliases:
703 704
704 705 $ hg mycommit -R alias
705 706 nothing changed
706 707 [1]
707 708 $ hg exit1
708 709 [1]
709 710
710 711 #if no-outer-repo
711 712 $ hg root
712 713 abort: no repository found in '$TESTTMP' (.hg not found)!
713 714 [255]
714 715 $ hg --config alias.hgroot='!hg root' hgroot
715 716 abort: no repository found in '$TESTTMP' (.hg not found)!
716 717 [255]
717 718 #endif
@@ -1,219 +1,220 b''
1 1 test command parsing and dispatch
2 2
3 3 $ hg init a
4 4 $ cd a
5 5
6 6 Redundant options used to crash (issue436):
7 7 $ hg -v log -v
8 8 $ hg -v log -v x
9 9
10 10 $ echo a > a
11 11 $ hg ci -Ama
12 12 adding a
13 13
14 14 Missing arg:
15 15
16 16 $ hg cat
17 17 hg cat: invalid arguments
18 18 hg cat [OPTION]... FILE...
19 19
20 20 output the current or given revision of files
21 21
22 22 options ([+] can be repeated):
23 23
24 24 -o --output FORMAT print output to file with formatted name
25 25 -r --rev REV print the given revision
26 26 --decode apply any matching decode filter
27 27 -I --include PATTERN [+] include names matching the given patterns
28 28 -X --exclude PATTERN [+] exclude names matching the given patterns
29 -T --template TEMPLATE display with template
29 30
30 31 (use 'hg cat -h' to show more help)
31 32 [255]
32 33
33 34 Missing parameter for early option:
34 35
35 36 $ hg log -R 2>&1 | grep 'hg log'
36 37 hg log: option -R requires argument
37 38 hg log [OPTION]... [FILE]
38 39 (use 'hg log -h' to show more help)
39 40
40 41 "--" may be an option value:
41 42
42 43 $ hg -R -- log
43 44 abort: repository -- not found!
44 45 [255]
45 46 $ hg log -R --
46 47 abort: repository -- not found!
47 48 [255]
48 49 $ hg log -T --
49 50 -- (no-eol)
50 51 $ hg log -T -- -k nomatch
51 52
52 53 Parsing of early options should stop at "--":
53 54
54 55 $ hg cat -- --config=hooks.pre-cat=false
55 56 --config=hooks.pre-cat=false: no such file in rev cb9a9f314b8b
56 57 [1]
57 58 $ hg cat -- --debugger
58 59 --debugger: no such file in rev cb9a9f314b8b
59 60 [1]
60 61
61 62 Unparsable form of early options:
62 63
63 64 $ hg cat --debugg
64 65 abort: option --debugger may not be abbreviated!
65 66 [255]
66 67
67 68 Parsing failure of early options should be detected before executing the
68 69 command:
69 70
70 71 $ hg log -b '--config=hooks.pre-log=false' default
71 72 abort: option --config may not be abbreviated!
72 73 [255]
73 74 $ hg log -b -R. default
74 75 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
75 76 [255]
76 77 $ hg log --cwd .. -b --cwd=. default
77 78 abort: option --cwd may not be abbreviated!
78 79 [255]
79 80
80 81 However, we can't prevent it from loading extensions and configs:
81 82
82 83 $ cat <<EOF > bad.py
83 84 > raise Exception('bad')
84 85 > EOF
85 86 $ hg log -b '--config=extensions.bad=bad.py' default
86 87 *** failed to import extension bad from bad.py: bad
87 88 abort: option --config may not be abbreviated!
88 89 [255]
89 90
90 91 $ mkdir -p badrepo/.hg
91 92 $ echo 'invalid-syntax' > badrepo/.hg/hgrc
92 93 $ hg log -b -Rbadrepo default
93 94 hg: parse error at badrepo/.hg/hgrc:1: invalid-syntax
94 95 [255]
95 96
96 97 $ hg log -b --cwd=inexistent default
97 98 abort: $ENOENT$: 'inexistent'
98 99 [255]
99 100
100 101 $ hg log -b '--config=ui.traceback=yes' 2>&1 | grep '^Traceback'
101 102 Traceback (most recent call last):
102 103 $ hg log -b '--config=profiling.enabled=yes' 2>&1 | grep -i sample
103 104 Sample count: .*|No samples recorded\. (re)
104 105
105 106 Early options can't be specified in [aliases] and [defaults] because they are
106 107 applied before the command name is resolved:
107 108
108 109 $ hg log -b '--config=alias.log=log --config=hooks.pre-log=false'
109 110 hg log: option -b not recognized
110 111 error in definition for alias 'log': --config may only be given on the command
111 112 line
112 113 [255]
113 114
114 115 $ hg log -b '--config=defaults.log=--config=hooks.pre-log=false'
115 116 abort: option --config may not be abbreviated!
116 117 [255]
117 118
118 119 Shell aliases bypass any command parsing rules but for the early one:
119 120
120 121 $ hg log -b '--config=alias.log=!echo howdy'
121 122 howdy
122 123
123 124 Early options must come first if HGPLAIN=+strictflags is specified:
124 125 (BUG: chg cherry-picks early options to pass them as a server command)
125 126
126 127 #if no-chg
127 128 $ HGPLAIN=+strictflags hg log -b --config='hooks.pre-log=false' default
128 129 abort: unknown revision '--config=hooks.pre-log=false'!
129 130 [255]
130 131 $ HGPLAIN=+strictflags hg log -b -R. default
131 132 abort: unknown revision '-R.'!
132 133 [255]
133 134 $ HGPLAIN=+strictflags hg log -b --cwd=. default
134 135 abort: unknown revision '--cwd=.'!
135 136 [255]
136 137 #endif
137 138 $ HGPLAIN=+strictflags hg log -b --debugger default
138 139 abort: unknown revision '--debugger'!
139 140 [255]
140 141 $ HGPLAIN=+strictflags hg log -b --config='alias.log=!echo pwned' default
141 142 abort: unknown revision '--config=alias.log=!echo pwned'!
142 143 [255]
143 144
144 145 $ HGPLAIN=+strictflags hg log --config='hooks.pre-log=false' -b default
145 146 abort: option --config may not be abbreviated!
146 147 [255]
147 148 $ HGPLAIN=+strictflags hg log -q --cwd=.. -b default
148 149 abort: option --cwd may not be abbreviated!
149 150 [255]
150 151 $ HGPLAIN=+strictflags hg log -q -R . -b default
151 152 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
152 153 [255]
153 154
154 155 $ HGPLAIN=+strictflags hg --config='hooks.pre-log=false' log -b default
155 156 abort: pre-log hook exited with status 1
156 157 [255]
157 158 $ HGPLAIN=+strictflags hg --cwd .. -q -Ra log -b default
158 159 0:cb9a9f314b8b
159 160 $ HGPLAIN=+strictflags hg --cwd .. -q --repository a log -b default
160 161 0:cb9a9f314b8b
161 162 $ HGPLAIN=+strictflags hg --cwd .. -q --repo a log -b default
162 163 0:cb9a9f314b8b
163 164
164 165 For compatibility reasons, HGPLAIN=+strictflags is not enabled by plain HGPLAIN:
165 166
166 167 $ HGPLAIN= hg log --config='hooks.pre-log=false' -b default
167 168 abort: pre-log hook exited with status 1
168 169 [255]
169 170 $ HGPLAINEXCEPT= hg log --cwd .. -q -Ra -b default
170 171 0:cb9a9f314b8b
171 172
172 173 [defaults]
173 174
174 175 $ hg cat a
175 176 a
176 177 $ cat >> $HGRCPATH <<EOF
177 178 > [defaults]
178 179 > cat = -r null
179 180 > EOF
180 181 $ hg cat a
181 182 a: no such file in rev 000000000000
182 183 [1]
183 184
184 185 $ cd "$TESTTMP"
185 186
186 187 OSError "No such file or directory" / "The system cannot find the path
187 188 specified" should include filename even when it is empty
188 189
189 190 $ hg -R a archive ''
190 191 abort: *: '' (glob)
191 192 [255]
192 193
193 194 #if no-outer-repo
194 195
195 196 No repo:
196 197
197 198 $ hg cat
198 199 abort: no repository found in '$TESTTMP' (.hg not found)!
199 200 [255]
200 201
201 202 #endif
202 203
203 204 #if rmcwd
204 205
205 206 Current directory removed:
206 207
207 208 $ mkdir $TESTTMP/repo1
208 209 $ cd $TESTTMP/repo1
209 210 $ rm -rf $TESTTMP/repo1
210 211
211 212 The output could be one of the following and something else:
212 213 chg: abort: failed to getcwd (errno = *) (glob)
213 214 abort: error getting current working directory: * (glob)
214 215 sh: 0: getcwd() failed: $ENOENT$
215 216 Since the exact behavior depends on the shell, only check it returns non-zero.
216 217 $ HGDEMANDIMPORT=disable hg version -q 2>/dev/null || false
217 218 [1]
218 219
219 220 #endif
@@ -1,1756 +1,1758 b''
1 1 Test basic extension support
2 2
3 3 $ cat > foobar.py <<EOF
4 4 > import os
5 5 > from mercurial import commands, registrar
6 6 > cmdtable = {}
7 7 > command = registrar.command(cmdtable)
8 8 > configtable = {}
9 9 > configitem = registrar.configitem(configtable)
10 10 > configitem(b'tests', b'foo', default=b"Foo")
11 11 > def uisetup(ui):
12 12 > ui.debug(b"uisetup called [debug]\\n")
13 13 > ui.write(b"uisetup called\\n")
14 14 > ui.status(b"uisetup called [status]\\n")
15 15 > ui.flush()
16 16 > def reposetup(ui, repo):
17 17 > ui.write(b"reposetup called for %s\\n" % os.path.basename(repo.root))
18 18 > ui.write(b"ui %s= repo.ui\\n" % (ui == repo.ui and b"=" or b"!"))
19 19 > ui.flush()
20 20 > @command(b'foo', [], b'hg foo')
21 21 > def foo(ui, *args, **kwargs):
22 22 > foo = ui.config(b'tests', b'foo')
23 23 > ui.write(foo)
24 24 > ui.write(b"\\n")
25 25 > @command(b'bar', [], b'hg bar', norepo=True)
26 26 > def bar(ui, *args, **kwargs):
27 27 > ui.write(b"Bar\\n")
28 28 > EOF
29 29 $ abspath=`pwd`/foobar.py
30 30
31 31 $ mkdir barfoo
32 32 $ cp foobar.py barfoo/__init__.py
33 33 $ barfoopath=`pwd`/barfoo
34 34
35 35 $ hg init a
36 36 $ cd a
37 37 $ echo foo > file
38 38 $ hg add file
39 39 $ hg commit -m 'add file'
40 40
41 41 $ echo '[extensions]' >> $HGRCPATH
42 42 $ echo "foobar = $abspath" >> $HGRCPATH
43 43 $ hg foo
44 44 uisetup called
45 45 uisetup called [status]
46 46 reposetup called for a
47 47 ui == repo.ui
48 48 reposetup called for a (chg !)
49 49 ui == repo.ui (chg !)
50 50 Foo
51 51 $ hg foo --quiet
52 52 uisetup called (no-chg !)
53 53 reposetup called for a (chg !)
54 54 ui == repo.ui
55 55 Foo
56 56 $ hg foo --debug
57 57 uisetup called [debug] (no-chg !)
58 58 uisetup called (no-chg !)
59 59 uisetup called [status] (no-chg !)
60 60 reposetup called for a (chg !)
61 61 ui == repo.ui
62 62 Foo
63 63
64 64 $ cd ..
65 65 $ hg clone a b
66 66 uisetup called (no-chg !)
67 67 uisetup called [status] (no-chg !)
68 68 reposetup called for a
69 69 ui == repo.ui
70 70 reposetup called for b
71 71 ui == repo.ui
72 72 updating to branch default
73 73 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 74
75 75 $ hg bar
76 76 uisetup called (no-chg !)
77 77 uisetup called [status] (no-chg !)
78 78 Bar
79 79 $ echo 'foobar = !' >> $HGRCPATH
80 80
81 81 module/__init__.py-style
82 82
83 83 $ echo "barfoo = $barfoopath" >> $HGRCPATH
84 84 $ cd a
85 85 $ hg foo
86 86 uisetup called
87 87 uisetup called [status]
88 88 reposetup called for a
89 89 ui == repo.ui
90 90 reposetup called for a (chg !)
91 91 ui == repo.ui (chg !)
92 92 Foo
93 93 $ echo 'barfoo = !' >> $HGRCPATH
94 94
95 95 Check that extensions are loaded in phases:
96 96
97 97 $ cat > foo.py <<EOF
98 98 > import os
99 99 > name = os.path.basename(__file__).rsplit('.', 1)[0]
100 100 > print("1) %s imported" % name)
101 101 > def uisetup(ui):
102 102 > print("2) %s uisetup" % name)
103 103 > def extsetup():
104 104 > print("3) %s extsetup" % name)
105 105 > def reposetup(ui, repo):
106 106 > print("4) %s reposetup" % name)
107 107 >
108 108 > bytesname = name.encode('utf-8')
109 109 > # custom predicate to check registration of functions at loading
110 110 > from mercurial import (
111 111 > registrar,
112 112 > smartset,
113 113 > )
114 114 > revsetpredicate = registrar.revsetpredicate()
115 115 > @revsetpredicate(bytesname, safe=True) # safe=True for query via hgweb
116 116 > def custompredicate(repo, subset, x):
117 117 > return smartset.baseset([r for r in subset if r in {0}])
118 118 > EOF
119 119
120 120 $ cp foo.py bar.py
121 121 $ echo 'foo = foo.py' >> $HGRCPATH
122 122 $ echo 'bar = bar.py' >> $HGRCPATH
123 123
124 124 Check normal command's load order of extensions and registration of functions
125 125
126 126 $ hg log -r "foo() and bar()" -q
127 127 1) foo imported
128 128 1) bar imported
129 129 2) foo uisetup
130 130 2) bar uisetup
131 131 3) foo extsetup
132 132 3) bar extsetup
133 133 4) foo reposetup
134 134 4) bar reposetup
135 135 0:c24b9ac61126
136 136
137 137 Check hgweb's load order of extensions and registration of functions
138 138
139 139 $ cat > hgweb.cgi <<EOF
140 140 > #!$PYTHON
141 141 > from mercurial import demandimport; demandimport.enable()
142 142 > from mercurial.hgweb import hgweb
143 143 > from mercurial.hgweb import wsgicgi
144 144 > application = hgweb(b'.', b'test repo')
145 145 > wsgicgi.launch(application)
146 146 > EOF
147 147 $ . "$TESTDIR/cgienv"
148 148
149 149 $ PATH_INFO='/' SCRIPT_NAME='' "$PYTHON" hgweb.cgi \
150 150 > | grep '^[0-9]) ' # ignores HTML output
151 151 1) foo imported
152 152 1) bar imported
153 153 2) foo uisetup
154 154 2) bar uisetup
155 155 3) foo extsetup
156 156 3) bar extsetup
157 157 4) foo reposetup
158 158 4) bar reposetup
159 159
160 160 (check that revset predicate foo() and bar() are available)
161 161
162 162 #if msys
163 163 $ PATH_INFO='//shortlog'
164 164 #else
165 165 $ PATH_INFO='/shortlog'
166 166 #endif
167 167 $ export PATH_INFO
168 168 $ SCRIPT_NAME='' QUERY_STRING='rev=foo() and bar()' "$PYTHON" hgweb.cgi \
169 169 > | grep '<a href="/rev/[0-9a-z]*">'
170 170 <a href="/rev/c24b9ac61126">add file</a>
171 171
172 172 $ echo 'foo = !' >> $HGRCPATH
173 173 $ echo 'bar = !' >> $HGRCPATH
174 174
175 175 Check "from __future__ import absolute_import" support for external libraries
176 176
177 177 #if windows
178 178 $ PATHSEP=";"
179 179 #else
180 180 $ PATHSEP=":"
181 181 #endif
182 182 $ export PATHSEP
183 183
184 184 $ mkdir $TESTTMP/libroot
185 185 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
186 186 $ mkdir $TESTTMP/libroot/mod
187 187 $ touch $TESTTMP/libroot/mod/__init__.py
188 188 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
189 189
190 190 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
191 191 > from __future__ import absolute_import
192 192 > import ambig # should load "libroot/ambig.py"
193 193 > s = ambig.s
194 194 > EOF
195 195 $ cat > loadabs.py <<EOF
196 196 > import mod.ambigabs as ambigabs
197 197 > def extsetup():
198 198 > print('ambigabs.s=%s' % ambigabs.s)
199 199 > EOF
200 200 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
201 201 ambigabs.s=libroot/ambig.py
202 202 $TESTTMP/a
203 203
204 204 #if no-py3k
205 205 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
206 206 > import ambig # should load "libroot/mod/ambig.py"
207 207 > s = ambig.s
208 208 > EOF
209 209 $ cat > loadrel.py <<EOF
210 210 > import mod.ambigrel as ambigrel
211 211 > def extsetup():
212 212 > print('ambigrel.s=%s' % ambigrel.s)
213 213 > EOF
214 214 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
215 215 ambigrel.s=libroot/mod/ambig.py
216 216 $TESTTMP/a
217 217 #endif
218 218
219 219 Check absolute/relative import of extension specific modules
220 220
221 221 $ mkdir $TESTTMP/extroot
222 222 $ cat > $TESTTMP/extroot/bar.py <<EOF
223 223 > s = 'this is extroot.bar'
224 224 > EOF
225 225 $ mkdir $TESTTMP/extroot/sub1
226 226 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
227 227 > s = 'this is extroot.sub1.__init__'
228 228 > EOF
229 229 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
230 230 > s = 'this is extroot.sub1.baz'
231 231 > EOF
232 232 $ cat > $TESTTMP/extroot/__init__.py <<EOF
233 233 > s = 'this is extroot.__init__'
234 234 > import foo
235 235 > def extsetup(ui):
236 236 > ui.write('(extroot) ', foo.func(), '\n')
237 237 > ui.flush()
238 238 > EOF
239 239
240 240 $ cat > $TESTTMP/extroot/foo.py <<EOF
241 241 > # test absolute import
242 242 > buf = []
243 243 > def func():
244 244 > # "not locals" case
245 245 > import extroot.bar
246 246 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
247 247 > return '\n(extroot) '.join(buf)
248 248 > # "fromlist == ('*',)" case
249 249 > from extroot.bar import *
250 250 > buf.append('from extroot.bar import *: %s' % s)
251 251 > # "not fromlist" and "if '.' in name" case
252 252 > import extroot.sub1.baz
253 253 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
254 254 > # "not fromlist" and NOT "if '.' in name" case
255 255 > import extroot
256 256 > buf.append('import extroot: %s' % extroot.s)
257 257 > # NOT "not fromlist" and NOT "level != -1" case
258 258 > from extroot.bar import s
259 259 > buf.append('from extroot.bar import s: %s' % s)
260 260 > EOF
261 261 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
262 262 (extroot) from extroot.bar import *: this is extroot.bar
263 263 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
264 264 (extroot) import extroot: this is extroot.__init__
265 265 (extroot) from extroot.bar import s: this is extroot.bar
266 266 (extroot) import extroot.bar in func(): this is extroot.bar
267 267 $TESTTMP/a
268 268
269 269 #if no-py3k
270 270 $ rm "$TESTTMP"/extroot/foo.*
271 271 $ rm -Rf "$TESTTMP/extroot/__pycache__"
272 272 $ cat > $TESTTMP/extroot/foo.py <<EOF
273 273 > # test relative import
274 274 > buf = []
275 275 > def func():
276 276 > # "not locals" case
277 277 > import bar
278 278 > buf.append('import bar in func(): %s' % bar.s)
279 279 > return '\n(extroot) '.join(buf)
280 280 > # "fromlist == ('*',)" case
281 281 > from bar import *
282 282 > buf.append('from bar import *: %s' % s)
283 283 > # "not fromlist" and "if '.' in name" case
284 284 > import sub1.baz
285 285 > buf.append('import sub1.baz: %s' % sub1.baz.s)
286 286 > # "not fromlist" and NOT "if '.' in name" case
287 287 > import sub1
288 288 > buf.append('import sub1: %s' % sub1.s)
289 289 > # NOT "not fromlist" and NOT "level != -1" case
290 290 > from bar import s
291 291 > buf.append('from bar import s: %s' % s)
292 292 > EOF
293 293 $ hg --config extensions.extroot=$TESTTMP/extroot root
294 294 (extroot) from bar import *: this is extroot.bar
295 295 (extroot) import sub1.baz: this is extroot.sub1.baz
296 296 (extroot) import sub1: this is extroot.sub1.__init__
297 297 (extroot) from bar import s: this is extroot.bar
298 298 (extroot) import bar in func(): this is extroot.bar
299 299 $TESTTMP/a
300 300 #endif
301 301
302 302 #if demandimport
303 303
304 304 Examine whether module loading is delayed until actual referring, even
305 305 though module is imported with "absolute_import" feature.
306 306
307 307 Files below in each packages are used for described purpose:
308 308
309 309 - "called": examine whether "from MODULE import ATTR" works correctly
310 310 - "unused": examine whether loading is delayed correctly
311 311 - "used": examine whether "from PACKAGE import MODULE" works correctly
312 312
313 313 Package hierarchy is needed to examine whether demand importing works
314 314 as expected for "from SUB.PACK.AGE import MODULE".
315 315
316 316 Setup "external library" to be imported with "absolute_import"
317 317 feature.
318 318
319 319 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
320 320 $ touch $TESTTMP/extlibroot/__init__.py
321 321 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
322 322 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
323 323
324 324 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF
325 325 > def func():
326 326 > return b"this is extlibroot.lsub1.lsub2.called.func()"
327 327 > EOF
328 328 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF
329 329 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
330 330 > EOF
331 331 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF
332 332 > detail = b"this is extlibroot.lsub1.lsub2.used"
333 333 > EOF
334 334
335 335 Setup sub-package of "external library", which causes instantiation of
336 336 demandmod in "recurse down the module chain" code path. Relative
337 337 importing with "absolute_import" feature isn't tested, because "level
338 338 >=1 " doesn't cause instantiation of demandmod.
339 339
340 340 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
341 341 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF
342 342 > detail = b"this is extlibroot.recursedown.abs.used"
343 343 > EOF
344 344 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF
345 345 > from __future__ import absolute_import
346 346 > from extlibroot.recursedown.abs.used import detail
347 347 > EOF
348 348
349 349 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
350 350 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF
351 351 > detail = b"this is extlibroot.recursedown.legacy.used"
352 352 > EOF
353 353 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF
354 354 > # legacy style (level == -1) import
355 355 > from extlibroot.recursedown.legacy.used import detail
356 356 > EOF
357 357
358 358 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF
359 359 > from __future__ import absolute_import
360 360 > from extlibroot.recursedown.abs import detail as absdetail
361 361 > from .legacy import detail as legacydetail
362 362 > EOF
363 363
364 364 Setup package that re-exports an attribute of its submodule as the same
365 365 name. This leaves 'shadowing.used' pointing to 'used.detail', but still
366 366 the submodule 'used' should be somehow accessible. (issue5617)
367 367
368 368 $ mkdir -p $TESTTMP/extlibroot/shadowing
369 369 $ cat > $TESTTMP/extlibroot/shadowing/used.py <<EOF
370 370 > detail = b"this is extlibroot.shadowing.used"
371 371 > EOF
372 372 $ cat > $TESTTMP/extlibroot/shadowing/proxied.py <<EOF
373 373 > from __future__ import absolute_import
374 374 > from extlibroot.shadowing.used import detail
375 375 > EOF
376 376 $ cat > $TESTTMP/extlibroot/shadowing/__init__.py <<EOF
377 377 > from __future__ import absolute_import
378 378 > from .used import detail as used
379 379 > EOF
380 380
381 381 Setup extension local modules to be imported with "absolute_import"
382 382 feature.
383 383
384 384 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
385 385 $ touch $TESTTMP/absextroot/xsub1/__init__.py
386 386 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
387 387
388 388 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF
389 389 > def func():
390 390 > return b"this is absextroot.xsub1.xsub2.called.func()"
391 391 > EOF
392 392 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF
393 393 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
394 394 > EOF
395 395 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF
396 396 > detail = b"this is absextroot.xsub1.xsub2.used"
397 397 > EOF
398 398
399 399 Setup extension local modules to examine whether demand importing
400 400 works as expected in "level > 1" case.
401 401
402 402 $ cat > $TESTTMP/absextroot/relimportee.py <<EOF
403 403 > detail = b"this is absextroot.relimportee"
404 404 > EOF
405 405 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF
406 406 > from __future__ import absolute_import
407 407 > from ... import relimportee
408 408 > detail = b"this relimporter imports %r" % (relimportee.detail)
409 409 > EOF
410 410
411 411 Setup modules, which actually import extension local modules at
412 412 runtime.
413 413
414 414 $ cat > $TESTTMP/absextroot/absolute.py << EOF
415 415 > from __future__ import absolute_import
416 416 >
417 417 > # import extension local modules absolutely (level = 0)
418 418 > from absextroot.xsub1.xsub2 import used, unused
419 419 > from absextroot.xsub1.xsub2.called import func
420 420 >
421 421 > def getresult():
422 422 > result = []
423 423 > result.append(used.detail)
424 424 > result.append(func())
425 425 > return result
426 426 > EOF
427 427
428 428 $ cat > $TESTTMP/absextroot/relative.py << EOF
429 429 > from __future__ import absolute_import
430 430 >
431 431 > # import extension local modules relatively (level == 1)
432 432 > from .xsub1.xsub2 import used, unused
433 433 > from .xsub1.xsub2.called import func
434 434 >
435 435 > # import a module, which implies "importing with level > 1"
436 436 > from .xsub1.xsub2 import relimporter
437 437 >
438 438 > def getresult():
439 439 > result = []
440 440 > result.append(used.detail)
441 441 > result.append(func())
442 442 > result.append(relimporter.detail)
443 443 > return result
444 444 > EOF
445 445
446 446 Setup main procedure of extension.
447 447
448 448 $ cat > $TESTTMP/absextroot/__init__.py <<EOF
449 449 > from __future__ import absolute_import
450 450 > from mercurial import registrar
451 451 > cmdtable = {}
452 452 > command = registrar.command(cmdtable)
453 453 >
454 454 > # "absolute" and "relative" shouldn't be imported before actual
455 455 > # command execution, because (1) they import same modules, and (2)
456 456 > # preceding import (= instantiate "demandmod" object instead of
457 457 > # real "module" object) might hide problem of succeeding import.
458 458 >
459 459 > @command(b'showabsolute', [], norepo=True)
460 460 > def showabsolute(ui, *args, **opts):
461 461 > from absextroot import absolute
462 462 > ui.write(b'ABS: %s\n' % '\nABS: '.join(absolute.getresult()))
463 463 >
464 464 > @command(b'showrelative', [], norepo=True)
465 465 > def showrelative(ui, *args, **opts):
466 466 > from . import relative
467 467 > ui.write(b'REL: %s\n' % '\nREL: '.join(relative.getresult()))
468 468 >
469 469 > # import modules from external library
470 470 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
471 471 > from extlibroot.lsub1.lsub2.called import func as lfunc
472 472 > from extlibroot.recursedown import absdetail, legacydetail
473 473 > from extlibroot.shadowing import proxied
474 474 >
475 475 > def uisetup(ui):
476 476 > result = []
477 477 > result.append(lused.detail)
478 478 > result.append(lfunc())
479 479 > result.append(absdetail)
480 480 > result.append(legacydetail)
481 481 > result.append(proxied.detail)
482 482 > ui.write(b'LIB: %s\n' % '\nLIB: '.join(result))
483 483 > EOF
484 484
485 485 Examine module importing.
486 486
487 487 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
488 488 LIB: this is extlibroot.lsub1.lsub2.used
489 489 LIB: this is extlibroot.lsub1.lsub2.called.func()
490 490 LIB: this is extlibroot.recursedown.abs.used
491 491 LIB: this is extlibroot.recursedown.legacy.used
492 492 LIB: this is extlibroot.shadowing.used
493 493 ABS: this is absextroot.xsub1.xsub2.used
494 494 ABS: this is absextroot.xsub1.xsub2.called.func()
495 495
496 496 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
497 497 LIB: this is extlibroot.lsub1.lsub2.used
498 498 LIB: this is extlibroot.lsub1.lsub2.called.func()
499 499 LIB: this is extlibroot.recursedown.abs.used
500 500 LIB: this is extlibroot.recursedown.legacy.used
501 501 LIB: this is extlibroot.shadowing.used
502 502 REL: this is absextroot.xsub1.xsub2.used
503 503 REL: this is absextroot.xsub1.xsub2.called.func()
504 504 REL: this relimporter imports 'this is absextroot.relimportee'
505 505
506 506 Examine whether sub-module is imported relatively as expected.
507 507
508 508 See also issue5208 for detail about example case on Python 3.x.
509 509
510 510 $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py
511 511 $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found
512 512
513 513 $ cat > $TESTTMP/notexist.py <<EOF
514 514 > text = 'notexist.py at root is loaded unintentionally\n'
515 515 > EOF
516 516
517 517 $ cat > $TESTTMP/checkrelativity.py <<EOF
518 518 > from mercurial import registrar
519 519 > cmdtable = {}
520 520 > command = registrar.command(cmdtable)
521 521 >
522 522 > # demand import avoids failure of importing notexist here
523 523 > import extlibroot.lsub1.lsub2.notexist
524 524 >
525 525 > @command(b'checkrelativity', [], norepo=True)
526 526 > def checkrelativity(ui, *args, **opts):
527 527 > try:
528 528 > ui.write(extlibroot.lsub1.lsub2.notexist.text)
529 529 > return 1 # unintentional success
530 530 > except ImportError:
531 531 > pass # intentional failure
532 532 > EOF
533 533
534 534 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity)
535 535
536 536 #endif
537 537
538 538 Make sure a broken uisetup doesn't globally break hg:
539 539 $ cat > $TESTTMP/baduisetup.py <<EOF
540 540 > def uisetup(ui):
541 541 > 1/0
542 542 > EOF
543 543
544 544 Even though the extension fails during uisetup, hg is still basically usable:
545 545 $ hg --config extensions.baduisetup=$TESTTMP/baduisetup.py version
546 546 Traceback (most recent call last):
547 547 File "*/mercurial/extensions.py", line *, in _runuisetup (glob)
548 548 uisetup(ui)
549 549 File "$TESTTMP/baduisetup.py", line 2, in uisetup
550 550 1/0
551 551 ZeroDivisionError: integer division or modulo by zero
552 552 *** failed to set up extension baduisetup: integer division or modulo by zero
553 553 Mercurial Distributed SCM (version *) (glob)
554 554 (see https://mercurial-scm.org for more information)
555 555
556 556 Copyright (C) 2005-* Matt Mackall and others (glob)
557 557 This is free software; see the source for copying conditions. There is NO
558 558 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
559 559
560 560 $ cd ..
561 561
562 562 hide outer repo
563 563 $ hg init
564 564
565 565 $ cat > empty.py <<EOF
566 566 > '''empty cmdtable
567 567 > '''
568 568 > cmdtable = {}
569 569 > EOF
570 570 $ emptypath=`pwd`/empty.py
571 571 $ echo "empty = $emptypath" >> $HGRCPATH
572 572 $ hg help empty
573 573 empty extension - empty cmdtable
574 574
575 575 no commands defined
576 576
577 577
578 578 $ echo 'empty = !' >> $HGRCPATH
579 579
580 580 $ cat > debugextension.py <<EOF
581 581 > '''only debugcommands
582 582 > '''
583 583 > from mercurial import registrar
584 584 > cmdtable = {}
585 585 > command = registrar.command(cmdtable)
586 586 > @command(b'debugfoobar', [], b'hg debugfoobar')
587 587 > def debugfoobar(ui, repo, *args, **opts):
588 588 > "yet another debug command"
589 589 > pass
590 590 > @command(b'foo', [], b'hg foo')
591 591 > def foo(ui, repo, *args, **opts):
592 592 > """yet another foo command
593 593 > This command has been DEPRECATED since forever.
594 594 > """
595 595 > pass
596 596 > EOF
597 597 $ debugpath=`pwd`/debugextension.py
598 598 $ echo "debugextension = $debugpath" >> $HGRCPATH
599 599
600 600 $ hg help debugextension
601 601 hg debugextensions
602 602
603 603 show information about active extensions
604 604
605 605 options:
606 606
607 -T --template TEMPLATE display with template
608
607 609 (some details hidden, use --verbose to show complete help)
608 610
609 611
610 612 $ hg --verbose help debugextension
611 613 hg debugextensions
612 614
613 615 show information about active extensions
614 616
615 617 options:
616 618
617 -T --template TEMPLATE display with template (EXPERIMENTAL)
619 -T --template TEMPLATE display with template
618 620
619 621 global options ([+] can be repeated):
620 622
621 623 -R --repository REPO repository root directory or name of overlay bundle
622 624 file
623 625 --cwd DIR change working directory
624 626 -y --noninteractive do not prompt, automatically pick the first choice for
625 627 all prompts
626 628 -q --quiet suppress output
627 629 -v --verbose enable additional output
628 630 --color TYPE when to colorize (boolean, always, auto, never, or
629 631 debug)
630 632 --config CONFIG [+] set/override config option (use 'section.name=value')
631 633 --debug enable debugging output
632 634 --debugger start debugger
633 635 --encoding ENCODE set the charset encoding (default: ascii)
634 636 --encodingmode MODE set the charset encoding mode (default: strict)
635 637 --traceback always print a traceback on exception
636 638 --time time how long the command takes
637 639 --profile print command execution profile
638 640 --version output version information and exit
639 641 -h --help display help and exit
640 642 --hidden consider hidden changesets
641 643 --pager TYPE when to paginate (boolean, always, auto, or never)
642 644 (default: auto)
643 645
644 646
645 647
646 648
647 649
648 650
649 651 $ hg --debug help debugextension
650 652 hg debugextensions
651 653
652 654 show information about active extensions
653 655
654 656 options:
655 657
656 -T --template TEMPLATE display with template (EXPERIMENTAL)
658 -T --template TEMPLATE display with template
657 659
658 660 global options ([+] can be repeated):
659 661
660 662 -R --repository REPO repository root directory or name of overlay bundle
661 663 file
662 664 --cwd DIR change working directory
663 665 -y --noninteractive do not prompt, automatically pick the first choice for
664 666 all prompts
665 667 -q --quiet suppress output
666 668 -v --verbose enable additional output
667 669 --color TYPE when to colorize (boolean, always, auto, never, or
668 670 debug)
669 671 --config CONFIG [+] set/override config option (use 'section.name=value')
670 672 --debug enable debugging output
671 673 --debugger start debugger
672 674 --encoding ENCODE set the charset encoding (default: ascii)
673 675 --encodingmode MODE set the charset encoding mode (default: strict)
674 676 --traceback always print a traceback on exception
675 677 --time time how long the command takes
676 678 --profile print command execution profile
677 679 --version output version information and exit
678 680 -h --help display help and exit
679 681 --hidden consider hidden changesets
680 682 --pager TYPE when to paginate (boolean, always, auto, or never)
681 683 (default: auto)
682 684
683 685
684 686
685 687
686 688
687 689 $ echo 'debugextension = !' >> $HGRCPATH
688 690
689 691 Asking for help about a deprecated extension should do something useful:
690 692
691 693 $ hg help glog
692 694 'glog' is provided by the following extension:
693 695
694 696 graphlog command to view revision graphs from a shell (DEPRECATED)
695 697
696 698 (use 'hg help extensions' for information on enabling extensions)
697 699
698 700 Extension module help vs command help:
699 701
700 702 $ echo 'extdiff =' >> $HGRCPATH
701 703 $ hg help extdiff
702 704 hg extdiff [OPT]... [FILE]...
703 705
704 706 use external program to diff repository (or selected files)
705 707
706 708 Show differences between revisions for the specified files, using an
707 709 external program. The default program used is diff, with default options
708 710 "-Npru".
709 711
710 712 To select a different program, use the -p/--program option. The program
711 713 will be passed the names of two directories to compare. To pass additional
712 714 options to the program, use -o/--option. These will be passed before the
713 715 names of the directories to compare.
714 716
715 717 When two revision arguments are given, then changes are shown between
716 718 those revisions. If only one revision is specified then that revision is
717 719 compared to the working directory, and, when no revisions are specified,
718 720 the working directory files are compared to its parent.
719 721
720 722 (use 'hg help -e extdiff' to show help for the extdiff extension)
721 723
722 724 options ([+] can be repeated):
723 725
724 726 -p --program CMD comparison program to run
725 727 -o --option OPT [+] pass option to comparison program
726 728 -r --rev REV [+] revision
727 729 -c --change REV change made by revision
728 730 --patch compare patches for two revisions
729 731 -I --include PATTERN [+] include names matching the given patterns
730 732 -X --exclude PATTERN [+] exclude names matching the given patterns
731 733 -S --subrepos recurse into subrepositories
732 734
733 735 (some details hidden, use --verbose to show complete help)
734 736
735 737
736 738
737 739
738 740
739 741
740 742
741 743
742 744
743 745
744 746 $ hg help --extension extdiff
745 747 extdiff extension - command to allow external programs to compare revisions
746 748
747 749 The extdiff Mercurial extension allows you to use external programs to compare
748 750 revisions, or revision with working directory. The external diff programs are
749 751 called with a configurable set of options and two non-option arguments: paths
750 752 to directories containing snapshots of files to compare.
751 753
752 754 If there is more than one file being compared and the "child" revision is the
753 755 working directory, any modifications made in the external diff program will be
754 756 copied back to the working directory from the temporary directory.
755 757
756 758 The extdiff extension also allows you to configure new diff commands, so you
757 759 do not need to type 'hg extdiff -p kdiff3' always.
758 760
759 761 [extdiff]
760 762 # add new command that runs GNU diff(1) in 'context diff' mode
761 763 cdiff = gdiff -Nprc5
762 764 ## or the old way:
763 765 #cmd.cdiff = gdiff
764 766 #opts.cdiff = -Nprc5
765 767
766 768 # add new command called meld, runs meld (no need to name twice). If
767 769 # the meld executable is not available, the meld tool in [merge-tools]
768 770 # will be used, if available
769 771 meld =
770 772
771 773 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
772 774 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
773 775 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
774 776 # your .vimrc
775 777 vimdiff = gvim -f "+next" \
776 778 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
777 779
778 780 Tool arguments can include variables that are expanded at runtime:
779 781
780 782 $parent1, $plabel1 - filename, descriptive label of first parent
781 783 $child, $clabel - filename, descriptive label of child revision
782 784 $parent2, $plabel2 - filename, descriptive label of second parent
783 785 $root - repository root
784 786 $parent is an alias for $parent1.
785 787
786 788 The extdiff extension will look in your [diff-tools] and [merge-tools]
787 789 sections for diff tool arguments, when none are specified in [extdiff].
788 790
789 791 [extdiff]
790 792 kdiff3 =
791 793
792 794 [diff-tools]
793 795 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
794 796
795 797 You can use -I/-X and list of file or directory names like normal 'hg diff'
796 798 command. The extdiff extension makes snapshots of only needed files, so
797 799 running the external diff program will actually be pretty fast (at least
798 800 faster than having to compare the entire tree).
799 801
800 802 list of commands:
801 803
802 804 extdiff use external program to diff repository (or selected files)
803 805
804 806 (use 'hg help -v -e extdiff' to show built-in aliases and global options)
805 807
806 808
807 809
808 810
809 811
810 812
811 813
812 814
813 815
814 816
815 817
816 818
817 819
818 820
819 821
820 822
821 823 $ echo 'extdiff = !' >> $HGRCPATH
822 824
823 825 Test help topic with same name as extension
824 826
825 827 $ cat > multirevs.py <<EOF
826 828 > from mercurial import commands, registrar
827 829 > cmdtable = {}
828 830 > command = registrar.command(cmdtable)
829 831 > """multirevs extension
830 832 > Big multi-line module docstring."""
831 833 > @command(b'multirevs', [], b'ARG', norepo=True)
832 834 > def multirevs(ui, repo, arg, *args, **opts):
833 835 > """multirevs command"""
834 836 > pass
835 837 > EOF
836 838 $ echo "multirevs = multirevs.py" >> $HGRCPATH
837 839
838 840 $ hg help multirevs | tail
839 841 used):
840 842
841 843 hg update :@
842 844
843 845 - Show diff between tags 1.3 and 1.5 (this works because the first and the
844 846 last revisions of the revset are used):
845 847
846 848 hg diff -r 1.3::1.5
847 849
848 850 use 'hg help -c multirevs' to see help for the multirevs command
849 851
850 852
851 853
852 854
853 855
854 856
855 857 $ hg help -c multirevs
856 858 hg multirevs ARG
857 859
858 860 multirevs command
859 861
860 862 (some details hidden, use --verbose to show complete help)
861 863
862 864
863 865
864 866 $ hg multirevs
865 867 hg multirevs: invalid arguments
866 868 hg multirevs ARG
867 869
868 870 multirevs command
869 871
870 872 (use 'hg multirevs -h' to show more help)
871 873 [255]
872 874
873 875
874 876
875 877 $ echo "multirevs = !" >> $HGRCPATH
876 878
877 879 Issue811: Problem loading extensions twice (by site and by user)
878 880
879 881 $ cat <<EOF >> $HGRCPATH
880 882 > mq =
881 883 > strip =
882 884 > hgext.mq =
883 885 > hgext/mq =
884 886 > EOF
885 887
886 888 Show extensions:
887 889 (note that mq force load strip, also checking it's not loaded twice)
888 890
889 891 #if no-extraextensions
890 892 $ hg debugextensions
891 893 mq
892 894 strip
893 895 #endif
894 896
895 897 For extensions, which name matches one of its commands, help
896 898 message should ask '-v -e' to get list of built-in aliases
897 899 along with extension help itself
898 900
899 901 $ mkdir $TESTTMP/d
900 902 $ cat > $TESTTMP/d/dodo.py <<EOF
901 903 > """
902 904 > This is an awesome 'dodo' extension. It does nothing and
903 905 > writes 'Foo foo'
904 906 > """
905 907 > from mercurial import commands, registrar
906 908 > cmdtable = {}
907 909 > command = registrar.command(cmdtable)
908 910 > @command(b'dodo', [], b'hg dodo')
909 911 > def dodo(ui, *args, **kwargs):
910 912 > """Does nothing"""
911 913 > ui.write(b"I do nothing. Yay\\n")
912 914 > @command(b'foofoo', [], b'hg foofoo')
913 915 > def foofoo(ui, *args, **kwargs):
914 916 > """Writes 'Foo foo'"""
915 917 > ui.write(b"Foo foo\\n")
916 918 > EOF
917 919 $ dodopath=$TESTTMP/d/dodo.py
918 920
919 921 $ echo "dodo = $dodopath" >> $HGRCPATH
920 922
921 923 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
922 924 $ hg help -e dodo
923 925 dodo extension -
924 926
925 927 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
926 928
927 929 list of commands:
928 930
929 931 dodo Does nothing
930 932 foofoo Writes 'Foo foo'
931 933
932 934 (use 'hg help -v -e dodo' to show built-in aliases and global options)
933 935
934 936 Make sure that '-v -e' prints list of built-in aliases along with
935 937 extension help itself
936 938 $ hg help -v -e dodo
937 939 dodo extension -
938 940
939 941 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
940 942
941 943 list of commands:
942 944
943 945 dodo Does nothing
944 946 foofoo Writes 'Foo foo'
945 947
946 948 global options ([+] can be repeated):
947 949
948 950 -R --repository REPO repository root directory or name of overlay bundle
949 951 file
950 952 --cwd DIR change working directory
951 953 -y --noninteractive do not prompt, automatically pick the first choice for
952 954 all prompts
953 955 -q --quiet suppress output
954 956 -v --verbose enable additional output
955 957 --color TYPE when to colorize (boolean, always, auto, never, or
956 958 debug)
957 959 --config CONFIG [+] set/override config option (use 'section.name=value')
958 960 --debug enable debugging output
959 961 --debugger start debugger
960 962 --encoding ENCODE set the charset encoding (default: ascii)
961 963 --encodingmode MODE set the charset encoding mode (default: strict)
962 964 --traceback always print a traceback on exception
963 965 --time time how long the command takes
964 966 --profile print command execution profile
965 967 --version output version information and exit
966 968 -h --help display help and exit
967 969 --hidden consider hidden changesets
968 970 --pager TYPE when to paginate (boolean, always, auto, or never)
969 971 (default: auto)
970 972
971 973 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
972 974 $ hg help -v dodo
973 975 hg dodo
974 976
975 977 Does nothing
976 978
977 979 (use 'hg help -e dodo' to show help for the dodo extension)
978 980
979 981 options:
980 982
981 983 --mq operate on patch repository
982 984
983 985 global options ([+] can be repeated):
984 986
985 987 -R --repository REPO repository root directory or name of overlay bundle
986 988 file
987 989 --cwd DIR change working directory
988 990 -y --noninteractive do not prompt, automatically pick the first choice for
989 991 all prompts
990 992 -q --quiet suppress output
991 993 -v --verbose enable additional output
992 994 --color TYPE when to colorize (boolean, always, auto, never, or
993 995 debug)
994 996 --config CONFIG [+] set/override config option (use 'section.name=value')
995 997 --debug enable debugging output
996 998 --debugger start debugger
997 999 --encoding ENCODE set the charset encoding (default: ascii)
998 1000 --encodingmode MODE set the charset encoding mode (default: strict)
999 1001 --traceback always print a traceback on exception
1000 1002 --time time how long the command takes
1001 1003 --profile print command execution profile
1002 1004 --version output version information and exit
1003 1005 -h --help display help and exit
1004 1006 --hidden consider hidden changesets
1005 1007 --pager TYPE when to paginate (boolean, always, auto, or never)
1006 1008 (default: auto)
1007 1009
1008 1010 In case when extension name doesn't match any of its commands,
1009 1011 help message should ask for '-v' to get list of built-in aliases
1010 1012 along with extension help
1011 1013 $ cat > $TESTTMP/d/dudu.py <<EOF
1012 1014 > """
1013 1015 > This is an awesome 'dudu' extension. It does something and
1014 1016 > also writes 'Beep beep'
1015 1017 > """
1016 1018 > from mercurial import commands, registrar
1017 1019 > cmdtable = {}
1018 1020 > command = registrar.command(cmdtable)
1019 1021 > @command(b'something', [], b'hg something')
1020 1022 > def something(ui, *args, **kwargs):
1021 1023 > """Does something"""
1022 1024 > ui.write(b"I do something. Yaaay\\n")
1023 1025 > @command(b'beep', [], b'hg beep')
1024 1026 > def beep(ui, *args, **kwargs):
1025 1027 > """Writes 'Beep beep'"""
1026 1028 > ui.write(b"Beep beep\\n")
1027 1029 > EOF
1028 1030 $ dudupath=$TESTTMP/d/dudu.py
1029 1031
1030 1032 $ echo "dudu = $dudupath" >> $HGRCPATH
1031 1033
1032 1034 $ hg help -e dudu
1033 1035 dudu extension -
1034 1036
1035 1037 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1036 1038 beep'
1037 1039
1038 1040 list of commands:
1039 1041
1040 1042 beep Writes 'Beep beep'
1041 1043 something Does something
1042 1044
1043 1045 (use 'hg help -v dudu' to show built-in aliases and global options)
1044 1046
1045 1047 In case when extension name doesn't match any of its commands,
1046 1048 help options '-v' and '-v -e' should be equivalent
1047 1049 $ hg help -v dudu
1048 1050 dudu extension -
1049 1051
1050 1052 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1051 1053 beep'
1052 1054
1053 1055 list of commands:
1054 1056
1055 1057 beep Writes 'Beep beep'
1056 1058 something Does something
1057 1059
1058 1060 global options ([+] can be repeated):
1059 1061
1060 1062 -R --repository REPO repository root directory or name of overlay bundle
1061 1063 file
1062 1064 --cwd DIR change working directory
1063 1065 -y --noninteractive do not prompt, automatically pick the first choice for
1064 1066 all prompts
1065 1067 -q --quiet suppress output
1066 1068 -v --verbose enable additional output
1067 1069 --color TYPE when to colorize (boolean, always, auto, never, or
1068 1070 debug)
1069 1071 --config CONFIG [+] set/override config option (use 'section.name=value')
1070 1072 --debug enable debugging output
1071 1073 --debugger start debugger
1072 1074 --encoding ENCODE set the charset encoding (default: ascii)
1073 1075 --encodingmode MODE set the charset encoding mode (default: strict)
1074 1076 --traceback always print a traceback on exception
1075 1077 --time time how long the command takes
1076 1078 --profile print command execution profile
1077 1079 --version output version information and exit
1078 1080 -h --help display help and exit
1079 1081 --hidden consider hidden changesets
1080 1082 --pager TYPE when to paginate (boolean, always, auto, or never)
1081 1083 (default: auto)
1082 1084
1083 1085 $ hg help -v -e dudu
1084 1086 dudu extension -
1085 1087
1086 1088 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1087 1089 beep'
1088 1090
1089 1091 list of commands:
1090 1092
1091 1093 beep Writes 'Beep beep'
1092 1094 something Does something
1093 1095
1094 1096 global options ([+] can be repeated):
1095 1097
1096 1098 -R --repository REPO repository root directory or name of overlay bundle
1097 1099 file
1098 1100 --cwd DIR change working directory
1099 1101 -y --noninteractive do not prompt, automatically pick the first choice for
1100 1102 all prompts
1101 1103 -q --quiet suppress output
1102 1104 -v --verbose enable additional output
1103 1105 --color TYPE when to colorize (boolean, always, auto, never, or
1104 1106 debug)
1105 1107 --config CONFIG [+] set/override config option (use 'section.name=value')
1106 1108 --debug enable debugging output
1107 1109 --debugger start debugger
1108 1110 --encoding ENCODE set the charset encoding (default: ascii)
1109 1111 --encodingmode MODE set the charset encoding mode (default: strict)
1110 1112 --traceback always print a traceback on exception
1111 1113 --time time how long the command takes
1112 1114 --profile print command execution profile
1113 1115 --version output version information and exit
1114 1116 -h --help display help and exit
1115 1117 --hidden consider hidden changesets
1116 1118 --pager TYPE when to paginate (boolean, always, auto, or never)
1117 1119 (default: auto)
1118 1120
1119 1121 Disabled extension commands:
1120 1122
1121 1123 $ ORGHGRCPATH=$HGRCPATH
1122 1124 $ HGRCPATH=
1123 1125 $ export HGRCPATH
1124 1126 $ hg help email
1125 1127 'email' is provided by the following extension:
1126 1128
1127 1129 patchbomb command to send changesets as (a series of) patch emails
1128 1130
1129 1131 (use 'hg help extensions' for information on enabling extensions)
1130 1132
1131 1133
1132 1134 $ hg qdel
1133 1135 hg: unknown command 'qdel'
1134 1136 'qdelete' is provided by the following extension:
1135 1137
1136 1138 mq manage a stack of patches
1137 1139
1138 1140 (use 'hg help extensions' for information on enabling extensions)
1139 1141 [255]
1140 1142
1141 1143
1142 1144 $ hg churn
1143 1145 hg: unknown command 'churn'
1144 1146 'churn' is provided by the following extension:
1145 1147
1146 1148 churn command to display statistics about repository history
1147 1149
1148 1150 (use 'hg help extensions' for information on enabling extensions)
1149 1151 [255]
1150 1152
1151 1153
1152 1154
1153 1155 Disabled extensions:
1154 1156
1155 1157 $ hg help churn
1156 1158 churn extension - command to display statistics about repository history
1157 1159
1158 1160 (use 'hg help extensions' for information on enabling extensions)
1159 1161
1160 1162 $ hg help patchbomb
1161 1163 patchbomb extension - command to send changesets as (a series of) patch emails
1162 1164
1163 1165 The series is started off with a "[PATCH 0 of N]" introduction, which
1164 1166 describes the series as a whole.
1165 1167
1166 1168 Each patch email has a Subject line of "[PATCH M of N] ...", using the first
1167 1169 line of the changeset description as the subject text. The message contains
1168 1170 two or three body parts:
1169 1171
1170 1172 - The changeset description.
1171 1173 - [Optional] The result of running diffstat on the patch.
1172 1174 - The patch itself, as generated by 'hg export'.
1173 1175
1174 1176 Each message refers to the first in the series using the In-Reply-To and
1175 1177 References headers, so they will show up as a sequence in threaded mail and
1176 1178 news readers, and in mail archives.
1177 1179
1178 1180 To configure other defaults, add a section like this to your configuration
1179 1181 file:
1180 1182
1181 1183 [email]
1182 1184 from = My Name <my@email>
1183 1185 to = recipient1, recipient2, ...
1184 1186 cc = cc1, cc2, ...
1185 1187 bcc = bcc1, bcc2, ...
1186 1188 reply-to = address1, address2, ...
1187 1189
1188 1190 Use "[patchbomb]" as configuration section name if you need to override global
1189 1191 "[email]" address settings.
1190 1192
1191 1193 Then you can use the 'hg email' command to mail a series of changesets as a
1192 1194 patchbomb.
1193 1195
1194 1196 You can also either configure the method option in the email section to be a
1195 1197 sendmail compatible mailer or fill out the [smtp] section so that the
1196 1198 patchbomb extension can automatically send patchbombs directly from the
1197 1199 commandline. See the [email] and [smtp] sections in hgrc(5) for details.
1198 1200
1199 1201 By default, 'hg email' will prompt for a "To" or "CC" header if you do not
1200 1202 supply one via configuration or the command line. You can override this to
1201 1203 never prompt by configuring an empty value:
1202 1204
1203 1205 [email]
1204 1206 cc =
1205 1207
1206 1208 You can control the default inclusion of an introduction message with the
1207 1209 "patchbomb.intro" configuration option. The configuration is always
1208 1210 overwritten by command line flags like --intro and --desc:
1209 1211
1210 1212 [patchbomb]
1211 1213 intro=auto # include introduction message if more than 1 patch (default)
1212 1214 intro=never # never include an introduction message
1213 1215 intro=always # always include an introduction message
1214 1216
1215 1217 You can specify a template for flags to be added in subject prefixes. Flags
1216 1218 specified by --flag option are exported as "{flags}" keyword:
1217 1219
1218 1220 [patchbomb]
1219 1221 flagtemplate = "{separate(' ',
1220 1222 ifeq(branch, 'default', '', branch|upper),
1221 1223 flags)}"
1222 1224
1223 1225 You can set patchbomb to always ask for confirmation by setting
1224 1226 "patchbomb.confirm" to true.
1225 1227
1226 1228 (use 'hg help extensions' for information on enabling extensions)
1227 1229
1228 1230
1229 1231 Broken disabled extension and command:
1230 1232
1231 1233 $ mkdir hgext
1232 1234 $ echo > hgext/__init__.py
1233 1235 $ cat > hgext/broken.py <<EOF
1234 1236 > "broken extension'
1235 1237 > EOF
1236 1238 $ cat > path.py <<EOF
1237 1239 > import os, sys
1238 1240 > sys.path.insert(0, os.environ['HGEXTPATH'])
1239 1241 > EOF
1240 1242 $ HGEXTPATH=`pwd`
1241 1243 $ export HGEXTPATH
1242 1244
1243 1245 $ hg --config extensions.path=./path.py help broken
1244 1246 broken extension - (no help text available)
1245 1247
1246 1248 (use 'hg help extensions' for information on enabling extensions)
1247 1249
1248 1250
1249 1251 $ cat > hgext/forest.py <<EOF
1250 1252 > cmdtable = None
1251 1253 > @command()
1252 1254 > def f():
1253 1255 > pass
1254 1256 > @command(123)
1255 1257 > def g():
1256 1258 > pass
1257 1259 > EOF
1258 1260 $ hg --config extensions.path=./path.py help foo
1259 1261 abort: no such help topic: foo
1260 1262 (try 'hg help --keyword foo')
1261 1263 [255]
1262 1264
1263 1265 $ cat > throw.py <<EOF
1264 1266 > from mercurial import commands, registrar, util
1265 1267 > cmdtable = {}
1266 1268 > command = registrar.command(cmdtable)
1267 1269 > class Bogon(Exception): pass
1268 1270 > @command(b'throw', [], b'hg throw', norepo=True)
1269 1271 > def throw(ui, **opts):
1270 1272 > """throws an exception"""
1271 1273 > raise Bogon()
1272 1274 > EOF
1273 1275
1274 1276 No declared supported version, extension complains:
1275 1277 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1276 1278 ** Unknown exception encountered with possibly-broken third-party extension throw
1277 1279 ** which supports versions unknown of Mercurial.
1278 1280 ** Please disable throw and try your action again.
1279 1281 ** If that fixes the bug please report it to the extension author.
1280 1282 ** Python * (glob)
1281 1283 ** Mercurial Distributed SCM * (glob)
1282 1284 ** Extensions loaded: throw
1283 1285
1284 1286 empty declaration of supported version, extension complains:
1285 1287 $ echo "testedwith = ''" >> throw.py
1286 1288 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1287 1289 ** Unknown exception encountered with possibly-broken third-party extension throw
1288 1290 ** which supports versions unknown of Mercurial.
1289 1291 ** Please disable throw and try your action again.
1290 1292 ** If that fixes the bug please report it to the extension author.
1291 1293 ** Python * (glob)
1292 1294 ** Mercurial Distributed SCM (*) (glob)
1293 1295 ** Extensions loaded: throw
1294 1296
1295 1297 If the extension specifies a buglink, show that:
1296 1298 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1297 1299 $ rm -f throw.pyc throw.pyo
1298 1300 $ rm -Rf __pycache__
1299 1301 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1300 1302 ** Unknown exception encountered with possibly-broken third-party extension throw
1301 1303 ** which supports versions unknown of Mercurial.
1302 1304 ** Please disable throw and try your action again.
1303 1305 ** If that fixes the bug please report it to http://example.com/bts
1304 1306 ** Python * (glob)
1305 1307 ** Mercurial Distributed SCM (*) (glob)
1306 1308 ** Extensions loaded: throw
1307 1309
1308 1310 If the extensions declare outdated versions, accuse the older extension first:
1309 1311 $ echo "from mercurial import util" >> older.py
1310 1312 $ echo "util.version = lambda:b'2.2'" >> older.py
1311 1313 $ echo "testedwith = b'1.9.3'" >> older.py
1312 1314 $ echo "testedwith = b'2.1.1'" >> throw.py
1313 1315 $ rm -f throw.pyc throw.pyo
1314 1316 $ rm -Rf __pycache__
1315 1317 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1316 1318 > throw 2>&1 | egrep '^\*\*'
1317 1319 ** Unknown exception encountered with possibly-broken third-party extension older
1318 1320 ** which supports versions 1.9 of Mercurial.
1319 1321 ** Please disable older and try your action again.
1320 1322 ** If that fixes the bug please report it to the extension author.
1321 1323 ** Python * (glob)
1322 1324 ** Mercurial Distributed SCM (version 2.2)
1323 1325 ** Extensions loaded: throw, older
1324 1326
1325 1327 One extension only tested with older, one only with newer versions:
1326 1328 $ echo "util.version = lambda:b'2.1'" >> older.py
1327 1329 $ rm -f older.pyc older.pyo
1328 1330 $ rm -Rf __pycache__
1329 1331 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1330 1332 > throw 2>&1 | egrep '^\*\*'
1331 1333 ** Unknown exception encountered with possibly-broken third-party extension older
1332 1334 ** which supports versions 1.9 of Mercurial.
1333 1335 ** Please disable older and try your action again.
1334 1336 ** If that fixes the bug please report it to the extension author.
1335 1337 ** Python * (glob)
1336 1338 ** Mercurial Distributed SCM (version 2.1)
1337 1339 ** Extensions loaded: throw, older
1338 1340
1339 1341 Older extension is tested with current version, the other only with newer:
1340 1342 $ echo "util.version = lambda:b'1.9.3'" >> older.py
1341 1343 $ rm -f older.pyc older.pyo
1342 1344 $ rm -Rf __pycache__
1343 1345 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1344 1346 > throw 2>&1 | egrep '^\*\*'
1345 1347 ** Unknown exception encountered with possibly-broken third-party extension throw
1346 1348 ** which supports versions 2.1 of Mercurial.
1347 1349 ** Please disable throw and try your action again.
1348 1350 ** If that fixes the bug please report it to http://example.com/bts
1349 1351 ** Python * (glob)
1350 1352 ** Mercurial Distributed SCM (version 1.9.3)
1351 1353 ** Extensions loaded: throw, older
1352 1354
1353 1355 Ability to point to a different point
1354 1356 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1355 1357 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1356 1358 ** unknown exception encountered, please report by visiting
1357 1359 ** Your Local Goat Lenders
1358 1360 ** Python * (glob)
1359 1361 ** Mercurial Distributed SCM (*) (glob)
1360 1362 ** Extensions loaded: throw, older
1361 1363
1362 1364 Declare the version as supporting this hg version, show regular bts link:
1363 1365 $ hgver=`hg debuginstall -T '{hgver}'`
1364 1366 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1365 1367 $ if [ -z "$hgver" ]; then
1366 1368 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1367 1369 > fi
1368 1370 $ rm -f throw.pyc throw.pyo
1369 1371 $ rm -Rf __pycache__
1370 1372 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1371 1373 ** unknown exception encountered, please report by visiting
1372 1374 ** https://mercurial-scm.org/wiki/BugTracker
1373 1375 ** Python * (glob)
1374 1376 ** Mercurial Distributed SCM (*) (glob)
1375 1377 ** Extensions loaded: throw
1376 1378
1377 1379 Patch version is ignored during compatibility check
1378 1380 $ echo "testedwith = b'3.2'" >> throw.py
1379 1381 $ echo "util.version = lambda:b'3.2.2'" >> throw.py
1380 1382 $ rm -f throw.pyc throw.pyo
1381 1383 $ rm -Rf __pycache__
1382 1384 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1383 1385 ** unknown exception encountered, please report by visiting
1384 1386 ** https://mercurial-scm.org/wiki/BugTracker
1385 1387 ** Python * (glob)
1386 1388 ** Mercurial Distributed SCM (*) (glob)
1387 1389 ** Extensions loaded: throw
1388 1390
1389 1391 Test version number support in 'hg version':
1390 1392 $ echo '__version__ = (1, 2, 3)' >> throw.py
1391 1393 $ rm -f throw.pyc throw.pyo
1392 1394 $ rm -Rf __pycache__
1393 1395 $ hg version -v
1394 1396 Mercurial Distributed SCM (version *) (glob)
1395 1397 (see https://mercurial-scm.org for more information)
1396 1398
1397 1399 Copyright (C) 2005-* Matt Mackall and others (glob)
1398 1400 This is free software; see the source for copying conditions. There is NO
1399 1401 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1400 1402
1401 1403 Enabled extensions:
1402 1404
1403 1405
1404 1406 $ hg version -v --config extensions.throw=throw.py
1405 1407 Mercurial Distributed SCM (version *) (glob)
1406 1408 (see https://mercurial-scm.org for more information)
1407 1409
1408 1410 Copyright (C) 2005-* Matt Mackall and others (glob)
1409 1411 This is free software; see the source for copying conditions. There is NO
1410 1412 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1411 1413
1412 1414 Enabled extensions:
1413 1415
1414 1416 throw external 1.2.3
1415 1417 $ echo 'getversion = lambda: b"1.twentythree"' >> throw.py
1416 1418 $ rm -f throw.pyc throw.pyo
1417 1419 $ rm -Rf __pycache__
1418 1420 $ hg version -v --config extensions.throw=throw.py --config extensions.strip=
1419 1421 Mercurial Distributed SCM (version *) (glob)
1420 1422 (see https://mercurial-scm.org for more information)
1421 1423
1422 1424 Copyright (C) 2005-* Matt Mackall and others (glob)
1423 1425 This is free software; see the source for copying conditions. There is NO
1424 1426 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1425 1427
1426 1428 Enabled extensions:
1427 1429
1428 1430 throw external 1.twentythree
1429 1431 strip internal
1430 1432
1431 1433 $ hg version -q --config extensions.throw=throw.py
1432 1434 Mercurial Distributed SCM (version *) (glob)
1433 1435
1434 1436 Test template output:
1435 1437
1436 1438 $ hg version --config extensions.strip= -T'{extensions}'
1437 1439 strip
1438 1440
1439 1441 Test JSON output of version:
1440 1442
1441 1443 $ hg version -Tjson
1442 1444 [
1443 1445 {
1444 1446 "extensions": [],
1445 1447 "ver": "*" (glob)
1446 1448 }
1447 1449 ]
1448 1450
1449 1451 $ hg version --config extensions.throw=throw.py -Tjson
1450 1452 [
1451 1453 {
1452 1454 "extensions": [{"bundled": false, "name": "throw", "ver": "1.twentythree"}],
1453 1455 "ver": "3.2.2"
1454 1456 }
1455 1457 ]
1456 1458
1457 1459 $ hg version --config extensions.strip= -Tjson
1458 1460 [
1459 1461 {
1460 1462 "extensions": [{"bundled": true, "name": "strip", "ver": null}],
1461 1463 "ver": "*" (glob)
1462 1464 }
1463 1465 ]
1464 1466
1465 1467 Test template output of version:
1466 1468
1467 1469 $ hg version --config extensions.throw=throw.py --config extensions.strip= \
1468 1470 > -T'{extensions % "{name} {pad(ver, 16)} ({if(bundled, "internal", "external")})\n"}'
1469 1471 throw 1.twentythree (external)
1470 1472 strip (internal)
1471 1473
1472 1474 Refuse to load extensions with minimum version requirements
1473 1475
1474 1476 $ cat > minversion1.py << EOF
1475 1477 > from mercurial import util
1476 1478 > util.version = lambda: b'3.5.2'
1477 1479 > minimumhgversion = b'3.6'
1478 1480 > EOF
1479 1481 $ hg --config extensions.minversion=minversion1.py version
1480 1482 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1481 1483 Mercurial Distributed SCM (version 3.5.2)
1482 1484 (see https://mercurial-scm.org for more information)
1483 1485
1484 1486 Copyright (C) 2005-* Matt Mackall and others (glob)
1485 1487 This is free software; see the source for copying conditions. There is NO
1486 1488 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1487 1489
1488 1490 $ cat > minversion2.py << EOF
1489 1491 > from mercurial import util
1490 1492 > util.version = lambda: b'3.6'
1491 1493 > minimumhgversion = b'3.7'
1492 1494 > EOF
1493 1495 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1494 1496 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1495 1497
1496 1498 Can load version that is only off by point release
1497 1499
1498 1500 $ cat > minversion2.py << EOF
1499 1501 > from mercurial import util
1500 1502 > util.version = lambda: b'3.6.1'
1501 1503 > minimumhgversion = b'3.6'
1502 1504 > EOF
1503 1505 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1504 1506 [1]
1505 1507
1506 1508 Can load minimum version identical to current
1507 1509
1508 1510 $ cat > minversion3.py << EOF
1509 1511 > from mercurial import util
1510 1512 > util.version = lambda: b'3.5'
1511 1513 > minimumhgversion = b'3.5'
1512 1514 > EOF
1513 1515 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1514 1516 [1]
1515 1517
1516 1518 Restore HGRCPATH
1517 1519
1518 1520 $ HGRCPATH=$ORGHGRCPATH
1519 1521 $ export HGRCPATH
1520 1522
1521 1523 Commands handling multiple repositories at a time should invoke only
1522 1524 "reposetup()" of extensions enabling in the target repository.
1523 1525
1524 1526 $ mkdir reposetup-test
1525 1527 $ cd reposetup-test
1526 1528
1527 1529 $ cat > $TESTTMP/reposetuptest.py <<EOF
1528 1530 > from mercurial import extensions
1529 1531 > def reposetup(ui, repo):
1530 1532 > ui.write(b'reposetup() for %s\n' % (repo.root))
1531 1533 > ui.flush()
1532 1534 > EOF
1533 1535 $ hg init src
1534 1536 $ echo a > src/a
1535 1537 $ hg -R src commit -Am '#0 at src/a'
1536 1538 adding a
1537 1539 $ echo '[extensions]' >> src/.hg/hgrc
1538 1540 $ echo '# enable extension locally' >> src/.hg/hgrc
1539 1541 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1540 1542 $ hg -R src status
1541 1543 reposetup() for $TESTTMP/reposetup-test/src
1542 1544 reposetup() for $TESTTMP/reposetup-test/src (chg !)
1543 1545
1544 1546 #if no-extraextensions
1545 1547 $ hg --cwd src debugextensions
1546 1548 reposetup() for $TESTTMP/reposetup-test/src
1547 1549 dodo (untested!)
1548 1550 dudu (untested!)
1549 1551 mq
1550 1552 reposetuptest (untested!)
1551 1553 strip
1552 1554 #endif
1553 1555
1554 1556 $ hg clone -U src clone-dst1
1555 1557 reposetup() for $TESTTMP/reposetup-test/src
1556 1558 $ hg init push-dst1
1557 1559 $ hg -q -R src push push-dst1
1558 1560 reposetup() for $TESTTMP/reposetup-test/src
1559 1561 $ hg init pull-src1
1560 1562 $ hg -q -R pull-src1 pull src
1561 1563 reposetup() for $TESTTMP/reposetup-test/src
1562 1564
1563 1565 $ cat <<EOF >> $HGRCPATH
1564 1566 > [extensions]
1565 1567 > # disable extension globally and explicitly
1566 1568 > reposetuptest = !
1567 1569 > EOF
1568 1570 $ hg clone -U src clone-dst2
1569 1571 reposetup() for $TESTTMP/reposetup-test/src
1570 1572 $ hg init push-dst2
1571 1573 $ hg -q -R src push push-dst2
1572 1574 reposetup() for $TESTTMP/reposetup-test/src
1573 1575 $ hg init pull-src2
1574 1576 $ hg -q -R pull-src2 pull src
1575 1577 reposetup() for $TESTTMP/reposetup-test/src
1576 1578
1577 1579 $ cat <<EOF >> $HGRCPATH
1578 1580 > [extensions]
1579 1581 > # enable extension globally
1580 1582 > reposetuptest = $TESTTMP/reposetuptest.py
1581 1583 > EOF
1582 1584 $ hg clone -U src clone-dst3
1583 1585 reposetup() for $TESTTMP/reposetup-test/src
1584 1586 reposetup() for $TESTTMP/reposetup-test/clone-dst3
1585 1587 $ hg init push-dst3
1586 1588 reposetup() for $TESTTMP/reposetup-test/push-dst3
1587 1589 $ hg -q -R src push push-dst3
1588 1590 reposetup() for $TESTTMP/reposetup-test/src
1589 1591 reposetup() for $TESTTMP/reposetup-test/push-dst3
1590 1592 $ hg init pull-src3
1591 1593 reposetup() for $TESTTMP/reposetup-test/pull-src3
1592 1594 $ hg -q -R pull-src3 pull src
1593 1595 reposetup() for $TESTTMP/reposetup-test/pull-src3
1594 1596 reposetup() for $TESTTMP/reposetup-test/src
1595 1597
1596 1598 $ echo '[extensions]' >> src/.hg/hgrc
1597 1599 $ echo '# disable extension locally' >> src/.hg/hgrc
1598 1600 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1599 1601 $ hg clone -U src clone-dst4
1600 1602 reposetup() for $TESTTMP/reposetup-test/clone-dst4
1601 1603 $ hg init push-dst4
1602 1604 reposetup() for $TESTTMP/reposetup-test/push-dst4
1603 1605 $ hg -q -R src push push-dst4
1604 1606 reposetup() for $TESTTMP/reposetup-test/push-dst4
1605 1607 $ hg init pull-src4
1606 1608 reposetup() for $TESTTMP/reposetup-test/pull-src4
1607 1609 $ hg -q -R pull-src4 pull src
1608 1610 reposetup() for $TESTTMP/reposetup-test/pull-src4
1609 1611
1610 1612 disabling in command line overlays with all configuration
1611 1613 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1612 1614 $ hg --config extensions.reposetuptest=! init push-dst5
1613 1615 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1614 1616 $ hg --config extensions.reposetuptest=! init pull-src5
1615 1617 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1616 1618
1617 1619 $ cat <<EOF >> $HGRCPATH
1618 1620 > [extensions]
1619 1621 > # disable extension globally and explicitly
1620 1622 > reposetuptest = !
1621 1623 > EOF
1622 1624 $ hg init parent
1623 1625 $ hg init parent/sub1
1624 1626 $ echo 1 > parent/sub1/1
1625 1627 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1626 1628 adding 1
1627 1629 $ hg init parent/sub2
1628 1630 $ hg init parent/sub2/sub21
1629 1631 $ echo 21 > parent/sub2/sub21/21
1630 1632 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1631 1633 adding 21
1632 1634 $ cat > parent/sub2/.hgsub <<EOF
1633 1635 > sub21 = sub21
1634 1636 > EOF
1635 1637 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1636 1638 adding .hgsub
1637 1639 $ hg init parent/sub3
1638 1640 $ echo 3 > parent/sub3/3
1639 1641 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1640 1642 adding 3
1641 1643 $ cat > parent/.hgsub <<EOF
1642 1644 > sub1 = sub1
1643 1645 > sub2 = sub2
1644 1646 > sub3 = sub3
1645 1647 > EOF
1646 1648 $ hg -R parent commit -Am '#0 at parent'
1647 1649 adding .hgsub
1648 1650 $ echo '[extensions]' >> parent/.hg/hgrc
1649 1651 $ echo '# enable extension locally' >> parent/.hg/hgrc
1650 1652 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1651 1653 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1652 1654 $ hg -R parent status -S -A
1653 1655 reposetup() for $TESTTMP/reposetup-test/parent
1654 1656 reposetup() for $TESTTMP/reposetup-test/parent/sub2
1655 1657 C .hgsub
1656 1658 C .hgsubstate
1657 1659 C sub1/1
1658 1660 C sub2/.hgsub
1659 1661 C sub2/.hgsubstate
1660 1662 C sub2/sub21/21
1661 1663 C sub3/3
1662 1664
1663 1665 $ cd ..
1664 1666
1665 1667 Prohibit registration of commands that don't use @command (issue5137)
1666 1668
1667 1669 $ hg init deprecated
1668 1670 $ cd deprecated
1669 1671
1670 1672 $ cat <<EOF > deprecatedcmd.py
1671 1673 > def deprecatedcmd(repo, ui):
1672 1674 > pass
1673 1675 > cmdtable = {
1674 1676 > b'deprecatedcmd': (deprecatedcmd, [], b''),
1675 1677 > }
1676 1678 > EOF
1677 1679 $ cat <<EOF > .hg/hgrc
1678 1680 > [extensions]
1679 1681 > deprecatedcmd = `pwd`/deprecatedcmd.py
1680 1682 > mq = !
1681 1683 > hgext.mq = !
1682 1684 > hgext/mq = !
1683 1685 > EOF
1684 1686
1685 1687 $ hg deprecatedcmd > /dev/null
1686 1688 *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo
1687 1689 *** (use @command decorator to register 'deprecatedcmd')
1688 1690 hg: unknown command 'deprecatedcmd'
1689 1691 (use 'hg help' for a list of commands)
1690 1692 [255]
1691 1693
1692 1694 the extension shouldn't be loaded at all so the mq works:
1693 1695
1694 1696 $ hg qseries --config extensions.mq= > /dev/null
1695 1697 *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo
1696 1698 *** (use @command decorator to register 'deprecatedcmd')
1697 1699
1698 1700 $ cd ..
1699 1701
1700 1702 Test synopsis and docstring extending
1701 1703
1702 1704 $ hg init exthelp
1703 1705 $ cat > exthelp.py <<EOF
1704 1706 > from mercurial import commands, extensions
1705 1707 > def exbookmarks(orig, *args, **opts):
1706 1708 > return orig(*args, **opts)
1707 1709 > def uisetup(ui):
1708 1710 > synopsis = b' GREPME [--foo] [-x]'
1709 1711 > docstring = '''
1710 1712 > GREPME make sure that this is in the help!
1711 1713 > '''
1712 1714 > extensions.wrapcommand(commands.table, b'bookmarks', exbookmarks,
1713 1715 > synopsis, docstring)
1714 1716 > EOF
1715 1717 $ abspath=`pwd`/exthelp.py
1716 1718 $ echo '[extensions]' >> $HGRCPATH
1717 1719 $ echo "exthelp = $abspath" >> $HGRCPATH
1718 1720 $ cd exthelp
1719 1721 $ hg help bookmarks | grep GREPME
1720 1722 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1721 1723 GREPME make sure that this is in the help!
1722 1724 $ cd ..
1723 1725
1724 1726 Show deprecation warning for the use of cmdutil.command
1725 1727
1726 1728 $ cat > nonregistrar.py <<EOF
1727 1729 > from mercurial import cmdutil
1728 1730 > cmdtable = {}
1729 1731 > command = cmdutil.command(cmdtable)
1730 1732 > @command(b'foo', [], norepo=True)
1731 1733 > def foo(ui):
1732 1734 > pass
1733 1735 > EOF
1734 1736
1735 1737 Prohibit the use of unicode strings as the default value of options
1736 1738
1737 1739 $ hg init $TESTTMP/opt-unicode-default
1738 1740
1739 1741 $ cat > $TESTTMP/test_unicode_default_value.py << EOF
1740 1742 > from mercurial import registrar
1741 1743 > cmdtable = {}
1742 1744 > command = registrar.command(cmdtable)
1743 1745 > @command(b'dummy', [(b'', b'opt', u'value', u'help')], 'ext [OPTIONS]')
1744 1746 > def ext(*args, **opts):
1745 1747 > print(opts[b'opt'])
1746 1748 > EOF
1747 1749 $ cat > $TESTTMP/opt-unicode-default/.hg/hgrc << EOF
1748 1750 > [extensions]
1749 1751 > test_unicode_default_value = $TESTTMP/test_unicode_default_value.py
1750 1752 > EOF
1751 1753 $ hg -R $TESTTMP/opt-unicode-default dummy
1752 1754 *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: unicode u'value' found in cmdtable.dummy
1753 1755 *** (use b'' to make it byte string)
1754 1756 hg: unknown command 'dummy'
1755 1757 (did you mean summary?)
1756 1758 [255]
@@ -1,3719 +1,3720 b''
1 1 Short help:
2 2
3 3 $ hg
4 4 Mercurial Distributed SCM
5 5
6 6 basic commands:
7 7
8 8 add add the specified files on the next commit
9 9 annotate show changeset information by line for each file
10 10 clone make a copy of an existing repository
11 11 commit commit the specified files or all outstanding changes
12 12 diff diff repository (or selected files)
13 13 export dump the header and diffs for one or more changesets
14 14 forget forget the specified files on the next commit
15 15 init create a new repository in the given directory
16 16 log show revision history of entire repository or files
17 17 merge merge another revision into working directory
18 18 pull pull changes from the specified source
19 19 push push changes to the specified destination
20 20 remove remove the specified files on the next commit
21 21 serve start stand-alone webserver
22 22 status show changed files in the working directory
23 23 summary summarize working directory state
24 24 update update working directory (or switch revisions)
25 25
26 26 (use 'hg help' for the full list of commands or 'hg -v' for details)
27 27
28 28 $ hg -q
29 29 add add the specified files on the next commit
30 30 annotate show changeset information by line for each file
31 31 clone make a copy of an existing repository
32 32 commit commit the specified files or all outstanding changes
33 33 diff diff repository (or selected files)
34 34 export dump the header and diffs for one or more changesets
35 35 forget forget the specified files on the next commit
36 36 init create a new repository in the given directory
37 37 log show revision history of entire repository or files
38 38 merge merge another revision into working directory
39 39 pull pull changes from the specified source
40 40 push push changes to the specified destination
41 41 remove remove the specified files on the next commit
42 42 serve start stand-alone webserver
43 43 status show changed files in the working directory
44 44 summary summarize working directory state
45 45 update update working directory (or switch revisions)
46 46
47 47 Extra extensions will be printed in help output in a non-reliable order since
48 48 the extension is unknown.
49 49 #if no-extraextensions
50 50
51 51 $ hg help
52 52 Mercurial Distributed SCM
53 53
54 54 list of commands:
55 55
56 56 add add the specified files on the next commit
57 57 addremove add all new files, delete all missing files
58 58 annotate show changeset information by line for each file
59 59 archive create an unversioned archive of a repository revision
60 60 backout reverse effect of earlier changeset
61 61 bisect subdivision search of changesets
62 62 bookmarks create a new bookmark or list existing bookmarks
63 63 branch set or show the current branch name
64 64 branches list repository named branches
65 65 bundle create a bundle file
66 66 cat output the current or given revision of files
67 67 clone make a copy of an existing repository
68 68 commit commit the specified files or all outstanding changes
69 69 config show combined config settings from all hgrc files
70 70 copy mark files as copied for the next commit
71 71 diff diff repository (or selected files)
72 72 export dump the header and diffs for one or more changesets
73 73 files list tracked files
74 74 forget forget the specified files on the next commit
75 75 graft copy changes from other branches onto the current branch
76 76 grep search revision history for a pattern in specified files
77 77 heads show branch heads
78 78 help show help for a given topic or a help overview
79 79 identify identify the working directory or specified revision
80 80 import import an ordered set of patches
81 81 incoming show new changesets found in source
82 82 init create a new repository in the given directory
83 83 log show revision history of entire repository or files
84 84 manifest output the current or given revision of the project manifest
85 85 merge merge another revision into working directory
86 86 outgoing show changesets not found in the destination
87 87 paths show aliases for remote repositories
88 88 phase set or show the current phase name
89 89 pull pull changes from the specified source
90 90 push push changes to the specified destination
91 91 recover roll back an interrupted transaction
92 92 remove remove the specified files on the next commit
93 93 rename rename files; equivalent of copy + remove
94 94 resolve redo merges or set/view the merge status of files
95 95 revert restore files to their checkout state
96 96 root print the root (top) of the current working directory
97 97 serve start stand-alone webserver
98 98 status show changed files in the working directory
99 99 summary summarize working directory state
100 100 tag add one or more tags for the current or given revision
101 101 tags list repository tags
102 102 unbundle apply one or more bundle files
103 103 update update working directory (or switch revisions)
104 104 verify verify the integrity of the repository
105 105 version output version and copyright information
106 106
107 107 additional help topics:
108 108
109 109 bundlespec Bundle File Formats
110 110 color Colorizing Outputs
111 111 config Configuration Files
112 112 dates Date Formats
113 113 deprecated Deprecated Features
114 114 diffs Diff Formats
115 115 environment Environment Variables
116 116 extensions Using Additional Features
117 117 filesets Specifying File Sets
118 118 flags Command-line flags
119 119 glossary Glossary
120 120 hgignore Syntax for Mercurial Ignore Files
121 121 hgweb Configuring hgweb
122 122 internals Technical implementation topics
123 123 merge-tools Merge Tools
124 124 pager Pager Support
125 125 patterns File Name Patterns
126 126 phases Working with Phases
127 127 revisions Specifying Revisions
128 128 scripting Using Mercurial from scripts and automation
129 129 subrepos Subrepositories
130 130 templating Template Usage
131 131 urls URL Paths
132 132
133 133 (use 'hg help -v' to show built-in aliases and global options)
134 134
135 135 $ hg -q help
136 136 add add the specified files on the next commit
137 137 addremove add all new files, delete all missing files
138 138 annotate show changeset information by line for each file
139 139 archive create an unversioned archive of a repository revision
140 140 backout reverse effect of earlier changeset
141 141 bisect subdivision search of changesets
142 142 bookmarks create a new bookmark or list existing bookmarks
143 143 branch set or show the current branch name
144 144 branches list repository named branches
145 145 bundle create a bundle file
146 146 cat output the current or given revision of files
147 147 clone make a copy of an existing repository
148 148 commit commit the specified files or all outstanding changes
149 149 config show combined config settings from all hgrc files
150 150 copy mark files as copied for the next commit
151 151 diff diff repository (or selected files)
152 152 export dump the header and diffs for one or more changesets
153 153 files list tracked files
154 154 forget forget the specified files on the next commit
155 155 graft copy changes from other branches onto the current branch
156 156 grep search revision history for a pattern in specified files
157 157 heads show branch heads
158 158 help show help for a given topic or a help overview
159 159 identify identify the working directory or specified revision
160 160 import import an ordered set of patches
161 161 incoming show new changesets found in source
162 162 init create a new repository in the given directory
163 163 log show revision history of entire repository or files
164 164 manifest output the current or given revision of the project manifest
165 165 merge merge another revision into working directory
166 166 outgoing show changesets not found in the destination
167 167 paths show aliases for remote repositories
168 168 phase set or show the current phase name
169 169 pull pull changes from the specified source
170 170 push push changes to the specified destination
171 171 recover roll back an interrupted transaction
172 172 remove remove the specified files on the next commit
173 173 rename rename files; equivalent of copy + remove
174 174 resolve redo merges or set/view the merge status of files
175 175 revert restore files to their checkout state
176 176 root print the root (top) of the current working directory
177 177 serve start stand-alone webserver
178 178 status show changed files in the working directory
179 179 summary summarize working directory state
180 180 tag add one or more tags for the current or given revision
181 181 tags list repository tags
182 182 unbundle apply one or more bundle files
183 183 update update working directory (or switch revisions)
184 184 verify verify the integrity of the repository
185 185 version output version and copyright information
186 186
187 187 additional help topics:
188 188
189 189 bundlespec Bundle File Formats
190 190 color Colorizing Outputs
191 191 config Configuration Files
192 192 dates Date Formats
193 193 deprecated Deprecated Features
194 194 diffs Diff Formats
195 195 environment Environment Variables
196 196 extensions Using Additional Features
197 197 filesets Specifying File Sets
198 198 flags Command-line flags
199 199 glossary Glossary
200 200 hgignore Syntax for Mercurial Ignore Files
201 201 hgweb Configuring hgweb
202 202 internals Technical implementation topics
203 203 merge-tools Merge Tools
204 204 pager Pager Support
205 205 patterns File Name Patterns
206 206 phases Working with Phases
207 207 revisions Specifying Revisions
208 208 scripting Using Mercurial from scripts and automation
209 209 subrepos Subrepositories
210 210 templating Template Usage
211 211 urls URL Paths
212 212
213 213 Test extension help:
214 214 $ hg help extensions --config extensions.rebase= --config extensions.children=
215 215 Using Additional Features
216 216 """""""""""""""""""""""""
217 217
218 218 Mercurial has the ability to add new features through the use of
219 219 extensions. Extensions may add new commands, add options to existing
220 220 commands, change the default behavior of commands, or implement hooks.
221 221
222 222 To enable the "foo" extension, either shipped with Mercurial or in the
223 223 Python search path, create an entry for it in your configuration file,
224 224 like this:
225 225
226 226 [extensions]
227 227 foo =
228 228
229 229 You may also specify the full path to an extension:
230 230
231 231 [extensions]
232 232 myfeature = ~/.hgext/myfeature.py
233 233
234 234 See 'hg help config' for more information on configuration files.
235 235
236 236 Extensions are not loaded by default for a variety of reasons: they can
237 237 increase startup overhead; they may be meant for advanced usage only; they
238 238 may provide potentially dangerous abilities (such as letting you destroy
239 239 or modify history); they might not be ready for prime time; or they may
240 240 alter some usual behaviors of stock Mercurial. It is thus up to the user
241 241 to activate extensions as needed.
242 242
243 243 To explicitly disable an extension enabled in a configuration file of
244 244 broader scope, prepend its path with !:
245 245
246 246 [extensions]
247 247 # disabling extension bar residing in /path/to/extension/bar.py
248 248 bar = !/path/to/extension/bar.py
249 249 # ditto, but no path was supplied for extension baz
250 250 baz = !
251 251
252 252 enabled extensions:
253 253
254 254 children command to display child changesets (DEPRECATED)
255 255 rebase command to move sets of revisions to a different ancestor
256 256
257 257 disabled extensions:
258 258
259 259 acl hooks for controlling repository access
260 260 blackbox log repository events to a blackbox for debugging
261 261 bugzilla hooks for integrating with the Bugzilla bug tracker
262 262 censor erase file content at a given revision
263 263 churn command to display statistics about repository history
264 264 clonebundles advertise pre-generated bundles to seed clones
265 265 convert import revisions from foreign VCS repositories into
266 266 Mercurial
267 267 eol automatically manage newlines in repository files
268 268 extdiff command to allow external programs to compare revisions
269 269 factotum http authentication with factotum
270 270 githelp try mapping git commands to Mercurial commands
271 271 gpg commands to sign and verify changesets
272 272 hgk browse the repository in a graphical way
273 273 highlight syntax highlighting for hgweb (requires Pygments)
274 274 histedit interactive history editing
275 275 keyword expand keywords in tracked files
276 276 largefiles track large binary files
277 277 mq manage a stack of patches
278 278 notify hooks for sending email push notifications
279 279 patchbomb command to send changesets as (a series of) patch emails
280 280 purge command to delete untracked files from the working
281 281 directory
282 282 relink recreates hardlinks between repository clones
283 283 schemes extend schemes with shortcuts to repository swarms
284 284 share share a common history between several working directories
285 285 shelve save and restore changes to the working directory
286 286 strip strip changesets and their descendants from history
287 287 transplant command to transplant changesets from another branch
288 288 win32mbcs allow the use of MBCS paths with problematic encodings
289 289 zeroconf discover and advertise repositories on the local network
290 290
291 291 #endif
292 292
293 293 Verify that deprecated extensions are included if --verbose:
294 294
295 295 $ hg -v help extensions | grep children
296 296 children command to display child changesets (DEPRECATED)
297 297
298 298 Verify that extension keywords appear in help templates
299 299
300 300 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
301 301
302 302 Test short command list with verbose option
303 303
304 304 $ hg -v help shortlist
305 305 Mercurial Distributed SCM
306 306
307 307 basic commands:
308 308
309 309 add add the specified files on the next commit
310 310 annotate, blame
311 311 show changeset information by line for each file
312 312 clone make a copy of an existing repository
313 313 commit, ci commit the specified files or all outstanding changes
314 314 diff diff repository (or selected files)
315 315 export dump the header and diffs for one or more changesets
316 316 forget forget the specified files on the next commit
317 317 init create a new repository in the given directory
318 318 log, history show revision history of entire repository or files
319 319 merge merge another revision into working directory
320 320 pull pull changes from the specified source
321 321 push push changes to the specified destination
322 322 remove, rm remove the specified files on the next commit
323 323 serve start stand-alone webserver
324 324 status, st show changed files in the working directory
325 325 summary, sum summarize working directory state
326 326 update, up, checkout, co
327 327 update working directory (or switch revisions)
328 328
329 329 global options ([+] can be repeated):
330 330
331 331 -R --repository REPO repository root directory or name of overlay bundle
332 332 file
333 333 --cwd DIR change working directory
334 334 -y --noninteractive do not prompt, automatically pick the first choice for
335 335 all prompts
336 336 -q --quiet suppress output
337 337 -v --verbose enable additional output
338 338 --color TYPE when to colorize (boolean, always, auto, never, or
339 339 debug)
340 340 --config CONFIG [+] set/override config option (use 'section.name=value')
341 341 --debug enable debugging output
342 342 --debugger start debugger
343 343 --encoding ENCODE set the charset encoding (default: ascii)
344 344 --encodingmode MODE set the charset encoding mode (default: strict)
345 345 --traceback always print a traceback on exception
346 346 --time time how long the command takes
347 347 --profile print command execution profile
348 348 --version output version information and exit
349 349 -h --help display help and exit
350 350 --hidden consider hidden changesets
351 351 --pager TYPE when to paginate (boolean, always, auto, or never)
352 352 (default: auto)
353 353
354 354 (use 'hg help' for the full list of commands)
355 355
356 356 $ hg add -h
357 357 hg add [OPTION]... [FILE]...
358 358
359 359 add the specified files on the next commit
360 360
361 361 Schedule files to be version controlled and added to the repository.
362 362
363 363 The files will be added to the repository at the next commit. To undo an
364 364 add before that, see 'hg forget'.
365 365
366 366 If no names are given, add all files to the repository (except files
367 367 matching ".hgignore").
368 368
369 369 Returns 0 if all files are successfully added.
370 370
371 371 options ([+] can be repeated):
372 372
373 373 -I --include PATTERN [+] include names matching the given patterns
374 374 -X --exclude PATTERN [+] exclude names matching the given patterns
375 375 -S --subrepos recurse into subrepositories
376 376 -n --dry-run do not perform actions, just print output
377 377
378 378 (some details hidden, use --verbose to show complete help)
379 379
380 380 Verbose help for add
381 381
382 382 $ hg add -hv
383 383 hg add [OPTION]... [FILE]...
384 384
385 385 add the specified files on the next commit
386 386
387 387 Schedule files to be version controlled and added to the repository.
388 388
389 389 The files will be added to the repository at the next commit. To undo an
390 390 add before that, see 'hg forget'.
391 391
392 392 If no names are given, add all files to the repository (except files
393 393 matching ".hgignore").
394 394
395 395 Examples:
396 396
397 397 - New (unknown) files are added automatically by 'hg add':
398 398
399 399 $ ls
400 400 foo.c
401 401 $ hg status
402 402 ? foo.c
403 403 $ hg add
404 404 adding foo.c
405 405 $ hg status
406 406 A foo.c
407 407
408 408 - Specific files to be added can be specified:
409 409
410 410 $ ls
411 411 bar.c foo.c
412 412 $ hg status
413 413 ? bar.c
414 414 ? foo.c
415 415 $ hg add bar.c
416 416 $ hg status
417 417 A bar.c
418 418 ? foo.c
419 419
420 420 Returns 0 if all files are successfully added.
421 421
422 422 options ([+] can be repeated):
423 423
424 424 -I --include PATTERN [+] include names matching the given patterns
425 425 -X --exclude PATTERN [+] exclude names matching the given patterns
426 426 -S --subrepos recurse into subrepositories
427 427 -n --dry-run do not perform actions, just print output
428 428
429 429 global options ([+] can be repeated):
430 430
431 431 -R --repository REPO repository root directory or name of overlay bundle
432 432 file
433 433 --cwd DIR change working directory
434 434 -y --noninteractive do not prompt, automatically pick the first choice for
435 435 all prompts
436 436 -q --quiet suppress output
437 437 -v --verbose enable additional output
438 438 --color TYPE when to colorize (boolean, always, auto, never, or
439 439 debug)
440 440 --config CONFIG [+] set/override config option (use 'section.name=value')
441 441 --debug enable debugging output
442 442 --debugger start debugger
443 443 --encoding ENCODE set the charset encoding (default: ascii)
444 444 --encodingmode MODE set the charset encoding mode (default: strict)
445 445 --traceback always print a traceback on exception
446 446 --time time how long the command takes
447 447 --profile print command execution profile
448 448 --version output version information and exit
449 449 -h --help display help and exit
450 450 --hidden consider hidden changesets
451 451 --pager TYPE when to paginate (boolean, always, auto, or never)
452 452 (default: auto)
453 453
454 454 Test the textwidth config option
455 455
456 456 $ hg root -h --config ui.textwidth=50
457 457 hg root
458 458
459 459 print the root (top) of the current working
460 460 directory
461 461
462 462 Print the root directory of the current
463 463 repository.
464 464
465 465 Returns 0 on success.
466 466
467 467 (some details hidden, use --verbose to show
468 468 complete help)
469 469
470 470 Test help option with version option
471 471
472 472 $ hg add -h --version
473 473 Mercurial Distributed SCM (version *) (glob)
474 474 (see https://mercurial-scm.org for more information)
475 475
476 476 Copyright (C) 2005-* Matt Mackall and others (glob)
477 477 This is free software; see the source for copying conditions. There is NO
478 478 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
479 479
480 480 $ hg add --skjdfks
481 481 hg add: option --skjdfks not recognized
482 482 hg add [OPTION]... [FILE]...
483 483
484 484 add the specified files on the next commit
485 485
486 486 options ([+] can be repeated):
487 487
488 488 -I --include PATTERN [+] include names matching the given patterns
489 489 -X --exclude PATTERN [+] exclude names matching the given patterns
490 490 -S --subrepos recurse into subrepositories
491 491 -n --dry-run do not perform actions, just print output
492 492
493 493 (use 'hg add -h' to show more help)
494 494 [255]
495 495
496 496 Test ambiguous command help
497 497
498 498 $ hg help ad
499 499 list of commands:
500 500
501 501 add add the specified files on the next commit
502 502 addremove add all new files, delete all missing files
503 503
504 504 (use 'hg help -v ad' to show built-in aliases and global options)
505 505
506 506 Test command without options
507 507
508 508 $ hg help verify
509 509 hg verify
510 510
511 511 verify the integrity of the repository
512 512
513 513 Verify the integrity of the current repository.
514 514
515 515 This will perform an extensive check of the repository's integrity,
516 516 validating the hashes and checksums of each entry in the changelog,
517 517 manifest, and tracked files, as well as the integrity of their crosslinks
518 518 and indices.
519 519
520 520 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
521 521 information about recovery from corruption of the repository.
522 522
523 523 Returns 0 on success, 1 if errors are encountered.
524 524
525 525 (some details hidden, use --verbose to show complete help)
526 526
527 527 $ hg help diff
528 528 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
529 529
530 530 diff repository (or selected files)
531 531
532 532 Show differences between revisions for the specified files.
533 533
534 534 Differences between files are shown using the unified diff format.
535 535
536 536 Note:
537 537 'hg diff' may generate unexpected results for merges, as it will
538 538 default to comparing against the working directory's first parent
539 539 changeset if no revisions are specified.
540 540
541 541 When two revision arguments are given, then changes are shown between
542 542 those revisions. If only one revision is specified then that revision is
543 543 compared to the working directory, and, when no revisions are specified,
544 544 the working directory files are compared to its first parent.
545 545
546 546 Alternatively you can specify -c/--change with a revision to see the
547 547 changes in that changeset relative to its first parent.
548 548
549 549 Without the -a/--text option, diff will avoid generating diffs of files it
550 550 detects as binary. With -a, diff will generate a diff anyway, probably
551 551 with undesirable results.
552 552
553 553 Use the -g/--git option to generate diffs in the git extended diff format.
554 554 For more information, read 'hg help diffs'.
555 555
556 556 Returns 0 on success.
557 557
558 558 options ([+] can be repeated):
559 559
560 560 -r --rev REV [+] revision
561 561 -c --change REV change made by revision
562 562 -a --text treat all files as text
563 563 -g --git use git extended diff format
564 564 --binary generate binary diffs in git mode (default)
565 565 --nodates omit dates from diff headers
566 566 --noprefix omit a/ and b/ prefixes from filenames
567 567 -p --show-function show which function each change is in
568 568 --reverse produce a diff that undoes the changes
569 569 -w --ignore-all-space ignore white space when comparing lines
570 570 -b --ignore-space-change ignore changes in the amount of white space
571 571 -B --ignore-blank-lines ignore changes whose lines are all blank
572 572 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
573 573 -U --unified NUM number of lines of context to show
574 574 --stat output diffstat-style summary of changes
575 575 --root DIR produce diffs relative to subdirectory
576 576 -I --include PATTERN [+] include names matching the given patterns
577 577 -X --exclude PATTERN [+] exclude names matching the given patterns
578 578 -S --subrepos recurse into subrepositories
579 579
580 580 (some details hidden, use --verbose to show complete help)
581 581
582 582 $ hg help status
583 583 hg status [OPTION]... [FILE]...
584 584
585 585 aliases: st
586 586
587 587 show changed files in the working directory
588 588
589 589 Show status of files in the repository. If names are given, only files
590 590 that match are shown. Files that are clean or ignored or the source of a
591 591 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
592 592 -C/--copies or -A/--all are given. Unless options described with "show
593 593 only ..." are given, the options -mardu are used.
594 594
595 595 Option -q/--quiet hides untracked (unknown and ignored) files unless
596 596 explicitly requested with -u/--unknown or -i/--ignored.
597 597
598 598 Note:
599 599 'hg status' may appear to disagree with diff if permissions have
600 600 changed or a merge has occurred. The standard diff format does not
601 601 report permission changes and diff only reports changes relative to one
602 602 merge parent.
603 603
604 604 If one revision is given, it is used as the base revision. If two
605 605 revisions are given, the differences between them are shown. The --change
606 606 option can also be used as a shortcut to list the changed files of a
607 607 revision from its first parent.
608 608
609 609 The codes used to show the status of files are:
610 610
611 611 M = modified
612 612 A = added
613 613 R = removed
614 614 C = clean
615 615 ! = missing (deleted by non-hg command, but still tracked)
616 616 ? = not tracked
617 617 I = ignored
618 618 = origin of the previous file (with --copies)
619 619
620 620 Returns 0 on success.
621 621
622 622 options ([+] can be repeated):
623 623
624 624 -A --all show status of all files
625 625 -m --modified show only modified files
626 626 -a --added show only added files
627 627 -r --removed show only removed files
628 628 -d --deleted show only deleted (but tracked) files
629 629 -c --clean show only files without changes
630 630 -u --unknown show only unknown (not tracked) files
631 631 -i --ignored show only ignored files
632 632 -n --no-status hide status prefix
633 633 -C --copies show source of copied files
634 634 -0 --print0 end filenames with NUL, for use with xargs
635 635 --rev REV [+] show difference from revision
636 636 --change REV list the changed files of a revision
637 637 -I --include PATTERN [+] include names matching the given patterns
638 638 -X --exclude PATTERN [+] exclude names matching the given patterns
639 639 -S --subrepos recurse into subrepositories
640 -T --template TEMPLATE display with template
640 641
641 642 (some details hidden, use --verbose to show complete help)
642 643
643 644 $ hg -q help status
644 645 hg status [OPTION]... [FILE]...
645 646
646 647 show changed files in the working directory
647 648
648 649 $ hg help foo
649 650 abort: no such help topic: foo
650 651 (try 'hg help --keyword foo')
651 652 [255]
652 653
653 654 $ hg skjdfks
654 655 hg: unknown command 'skjdfks'
655 656 (use 'hg help' for a list of commands)
656 657 [255]
657 658
658 659 Typoed command gives suggestion
659 660 $ hg puls
660 661 hg: unknown command 'puls'
661 662 (did you mean one of pull, push?)
662 663 [255]
663 664
664 665 Not enabled extension gets suggested
665 666
666 667 $ hg rebase
667 668 hg: unknown command 'rebase'
668 669 'rebase' is provided by the following extension:
669 670
670 671 rebase command to move sets of revisions to a different ancestor
671 672
672 673 (use 'hg help extensions' for information on enabling extensions)
673 674 [255]
674 675
675 676 Disabled extension gets suggested
676 677 $ hg --config extensions.rebase=! rebase
677 678 hg: unknown command 'rebase'
678 679 'rebase' is provided by the following extension:
679 680
680 681 rebase command to move sets of revisions to a different ancestor
681 682
682 683 (use 'hg help extensions' for information on enabling extensions)
683 684 [255]
684 685
685 686 Make sure that we don't run afoul of the help system thinking that
686 687 this is a section and erroring out weirdly.
687 688
688 689 $ hg .log
689 690 hg: unknown command '.log'
690 691 (did you mean log?)
691 692 [255]
692 693
693 694 $ hg log.
694 695 hg: unknown command 'log.'
695 696 (did you mean log?)
696 697 [255]
697 698 $ hg pu.lh
698 699 hg: unknown command 'pu.lh'
699 700 (did you mean one of pull, push?)
700 701 [255]
701 702
702 703 $ cat > helpext.py <<EOF
703 704 > import os
704 705 > from mercurial import commands, fancyopts, registrar
705 706 >
706 707 > def func(arg):
707 708 > return '%sfoo' % arg
708 709 > class customopt(fancyopts.customopt):
709 710 > def newstate(self, oldstate, newparam, abort):
710 711 > return '%sbar' % oldstate
711 712 > cmdtable = {}
712 713 > command = registrar.command(cmdtable)
713 714 >
714 715 > @command(b'nohelp',
715 716 > [(b'', b'longdesc', 3, b'x'*67),
716 717 > (b'n', b'', None, b'normal desc'),
717 718 > (b'', b'newline', b'', b'line1\nline2'),
718 719 > (b'', b'callableopt', func, b'adds foo'),
719 720 > (b'', b'customopt', customopt(''), b'adds bar'),
720 721 > (b'', b'customopt-withdefault', customopt('foo'), b'adds bar')],
721 722 > b'hg nohelp',
722 723 > norepo=True)
723 724 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
724 725 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
725 726 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
726 727 > def nohelp(ui, *args, **kwargs):
727 728 > pass
728 729 >
729 730 > def uisetup(ui):
730 731 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
731 732 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
732 733 >
733 734 > EOF
734 735 $ echo '[extensions]' >> $HGRCPATH
735 736 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
736 737
737 738 Test for aliases
738 739
739 740 $ hg help hgalias
740 741 hg hgalias [--remote]
741 742
742 743 alias for: hg summary
743 744
744 745 summarize working directory state
745 746
746 747 This generates a brief summary of the working directory state, including
747 748 parents, branch, commit status, phase and available updates.
748 749
749 750 With the --remote option, this will check the default paths for incoming
750 751 and outgoing changes. This can be time-consuming.
751 752
752 753 Returns 0 on success.
753 754
754 755 defined by: helpext
755 756
756 757 options:
757 758
758 759 --remote check for push and pull
759 760
760 761 (some details hidden, use --verbose to show complete help)
761 762
762 763 $ hg help shellalias
763 764 hg shellalias
764 765
765 766 shell alias for: echo hi
766 767
767 768 (no help text available)
768 769
769 770 defined by: helpext
770 771
771 772 (some details hidden, use --verbose to show complete help)
772 773
773 774 Test command with no help text
774 775
775 776 $ hg help nohelp
776 777 hg nohelp
777 778
778 779 (no help text available)
779 780
780 781 options:
781 782
782 783 --longdesc VALUE
783 784 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
784 785 xxxxxxxxxxxxxxxxxxxxxxx (default: 3)
785 786 -n -- normal desc
786 787 --newline VALUE line1 line2
787 788 --callableopt VALUE adds foo
788 789 --customopt VALUE adds bar
789 790 --customopt-withdefault VALUE adds bar (default: foo)
790 791
791 792 (some details hidden, use --verbose to show complete help)
792 793
793 794 $ hg help -k nohelp
794 795 Commands:
795 796
796 797 nohelp hg nohelp
797 798
798 799 Extension Commands:
799 800
800 801 nohelp (no help text available)
801 802
802 803 Test that default list of commands omits extension commands
803 804
804 805 #if no-extraextensions
805 806
806 807 $ hg help
807 808 Mercurial Distributed SCM
808 809
809 810 list of commands:
810 811
811 812 add add the specified files on the next commit
812 813 addremove add all new files, delete all missing files
813 814 annotate show changeset information by line for each file
814 815 archive create an unversioned archive of a repository revision
815 816 backout reverse effect of earlier changeset
816 817 bisect subdivision search of changesets
817 818 bookmarks create a new bookmark or list existing bookmarks
818 819 branch set or show the current branch name
819 820 branches list repository named branches
820 821 bundle create a bundle file
821 822 cat output the current or given revision of files
822 823 clone make a copy of an existing repository
823 824 commit commit the specified files or all outstanding changes
824 825 config show combined config settings from all hgrc files
825 826 copy mark files as copied for the next commit
826 827 diff diff repository (or selected files)
827 828 export dump the header and diffs for one or more changesets
828 829 files list tracked files
829 830 forget forget the specified files on the next commit
830 831 graft copy changes from other branches onto the current branch
831 832 grep search revision history for a pattern in specified files
832 833 heads show branch heads
833 834 help show help for a given topic or a help overview
834 835 identify identify the working directory or specified revision
835 836 import import an ordered set of patches
836 837 incoming show new changesets found in source
837 838 init create a new repository in the given directory
838 839 log show revision history of entire repository or files
839 840 manifest output the current or given revision of the project manifest
840 841 merge merge another revision into working directory
841 842 outgoing show changesets not found in the destination
842 843 paths show aliases for remote repositories
843 844 phase set or show the current phase name
844 845 pull pull changes from the specified source
845 846 push push changes to the specified destination
846 847 recover roll back an interrupted transaction
847 848 remove remove the specified files on the next commit
848 849 rename rename files; equivalent of copy + remove
849 850 resolve redo merges or set/view the merge status of files
850 851 revert restore files to their checkout state
851 852 root print the root (top) of the current working directory
852 853 serve start stand-alone webserver
853 854 status show changed files in the working directory
854 855 summary summarize working directory state
855 856 tag add one or more tags for the current or given revision
856 857 tags list repository tags
857 858 unbundle apply one or more bundle files
858 859 update update working directory (or switch revisions)
859 860 verify verify the integrity of the repository
860 861 version output version and copyright information
861 862
862 863 enabled extensions:
863 864
864 865 helpext (no help text available)
865 866
866 867 additional help topics:
867 868
868 869 bundlespec Bundle File Formats
869 870 color Colorizing Outputs
870 871 config Configuration Files
871 872 dates Date Formats
872 873 deprecated Deprecated Features
873 874 diffs Diff Formats
874 875 environment Environment Variables
875 876 extensions Using Additional Features
876 877 filesets Specifying File Sets
877 878 flags Command-line flags
878 879 glossary Glossary
879 880 hgignore Syntax for Mercurial Ignore Files
880 881 hgweb Configuring hgweb
881 882 internals Technical implementation topics
882 883 merge-tools Merge Tools
883 884 pager Pager Support
884 885 patterns File Name Patterns
885 886 phases Working with Phases
886 887 revisions Specifying Revisions
887 888 scripting Using Mercurial from scripts and automation
888 889 subrepos Subrepositories
889 890 templating Template Usage
890 891 urls URL Paths
891 892
892 893 (use 'hg help -v' to show built-in aliases and global options)
893 894
894 895 #endif
895 896
896 897 Test list of internal help commands
897 898
898 899 $ hg help debug
899 900 debug commands (internal and unsupported):
900 901
901 902 debugancestor
902 903 find the ancestor revision of two revisions in a given index
903 904 debugapplystreamclonebundle
904 905 apply a stream clone bundle file
905 906 debugbuilddag
906 907 builds a repo with a given DAG from scratch in the current
907 908 empty repo
908 909 debugbundle lists the contents of a bundle
909 910 debugcapabilities
910 911 lists the capabilities of a remote peer
911 912 debugcheckstate
912 913 validate the correctness of the current dirstate
913 914 debugcolor show available color, effects or style
914 915 debugcommands
915 916 list all available commands and options
916 917 debugcomplete
917 918 returns the completion list associated with the given command
918 919 debugcreatestreamclonebundle
919 920 create a stream clone bundle file
920 921 debugdag format the changelog or an index DAG as a concise textual
921 922 description
922 923 debugdata dump the contents of a data file revision
923 924 debugdate parse and display a date
924 925 debugdeltachain
925 926 dump information about delta chains in a revlog
926 927 debugdirstate
927 928 show the contents of the current dirstate
928 929 debugdiscovery
929 930 runs the changeset discovery protocol in isolation
930 931 debugdownload
931 932 download a resource using Mercurial logic and config
932 933 debugextensions
933 934 show information about active extensions
934 935 debugfileset parse and apply a fileset specification
935 936 debugformat display format information about the current repository
936 937 debugfsinfo show information detected about current filesystem
937 938 debuggetbundle
938 939 retrieves a bundle from a repo
939 940 debugignore display the combined ignore pattern and information about
940 941 ignored files
941 942 debugindex dump index data for a storage primitive
942 943 debugindexdot
943 944 dump an index DAG as a graphviz dot file
944 945 debuginstall test Mercurial installation
945 946 debugknown test whether node ids are known to a repo
946 947 debuglocks show or modify state of locks
947 948 debugmanifestfulltextcache
948 949 show, clear or amend the contents of the manifest fulltext
949 950 cache
950 951 debugmergestate
951 952 print merge state
952 953 debugnamecomplete
953 954 complete "names" - tags, open branch names, bookmark names
954 955 debugobsolete
955 956 create arbitrary obsolete marker
956 957 debugoptADV (no help text available)
957 958 debugoptDEP (no help text available)
958 959 debugoptEXP (no help text available)
959 960 debugpathcomplete
960 961 complete part or all of a tracked path
961 962 debugpeer establish a connection to a peer repository
962 963 debugpickmergetool
963 964 examine which merge tool is chosen for specified file
964 965 debugpushkey access the pushkey key/value protocol
965 966 debugpvec (no help text available)
966 967 debugrebuilddirstate
967 968 rebuild the dirstate as it would look like for the given
968 969 revision
969 970 debugrebuildfncache
970 971 rebuild the fncache file
971 972 debugrename dump rename information
972 973 debugrevlog show data and statistics about a revlog
973 974 debugrevlogindex
974 975 dump the contents of a revlog index
975 976 debugrevspec parse and apply a revision specification
976 977 debugserve run a server with advanced settings
977 978 debugsetparents
978 979 manually set the parents of the current working directory
979 980 debugssl test a secure connection to a server
980 981 debugsub (no help text available)
981 982 debugsuccessorssets
982 983 show set of successors for revision
983 984 debugtemplate
984 985 parse and apply a template
985 986 debuguigetpass
986 987 show prompt to type password
987 988 debuguiprompt
988 989 show plain prompt
989 990 debugupdatecaches
990 991 warm all known caches in the repository
991 992 debugupgraderepo
992 993 upgrade a repository to use different features
993 994 debugwalk show how files match on given patterns
994 995 debugwhyunstable
995 996 explain instabilities of a changeset
996 997 debugwireargs
997 998 (no help text available)
998 999 debugwireproto
999 1000 send wire protocol commands to a server
1000 1001
1001 1002 (use 'hg help -v debug' to show built-in aliases and global options)
1002 1003
1003 1004 internals topic renders index of available sub-topics
1004 1005
1005 1006 $ hg help internals
1006 1007 Technical implementation topics
1007 1008 """""""""""""""""""""""""""""""
1008 1009
1009 1010 To access a subtopic, use "hg help internals.{subtopic-name}"
1010 1011
1011 1012 bundle2 Bundle2
1012 1013 bundles Bundles
1013 1014 cbor CBOR
1014 1015 censor Censor
1015 1016 changegroups Changegroups
1016 1017 config Config Registrar
1017 1018 requirements Repository Requirements
1018 1019 revlogs Revision Logs
1019 1020 wireprotocol Wire Protocol
1020 1021 wireprotocolrpc
1021 1022 Wire Protocol RPC
1022 1023 wireprotocolv2
1023 1024 Wire Protocol Version 2
1024 1025
1025 1026 sub-topics can be accessed
1026 1027
1027 1028 $ hg help internals.changegroups
1028 1029 Changegroups
1029 1030 """"""""""""
1030 1031
1031 1032 Changegroups are representations of repository revlog data, specifically
1032 1033 the changelog data, root/flat manifest data, treemanifest data, and
1033 1034 filelogs.
1034 1035
1035 1036 There are 3 versions of changegroups: "1", "2", and "3". From a high-
1036 1037 level, versions "1" and "2" are almost exactly the same, with the only
1037 1038 difference being an additional item in the *delta header*. Version "3"
1038 1039 adds support for revlog flags in the *delta header* and optionally
1039 1040 exchanging treemanifests (enabled by setting an option on the
1040 1041 "changegroup" part in the bundle2).
1041 1042
1042 1043 Changegroups when not exchanging treemanifests consist of 3 logical
1043 1044 segments:
1044 1045
1045 1046 +---------------------------------+
1046 1047 | | | |
1047 1048 | changeset | manifest | filelogs |
1048 1049 | | | |
1049 1050 | | | |
1050 1051 +---------------------------------+
1051 1052
1052 1053 When exchanging treemanifests, there are 4 logical segments:
1053 1054
1054 1055 +-------------------------------------------------+
1055 1056 | | | | |
1056 1057 | changeset | root | treemanifests | filelogs |
1057 1058 | | manifest | | |
1058 1059 | | | | |
1059 1060 +-------------------------------------------------+
1060 1061
1061 1062 The principle building block of each segment is a *chunk*. A *chunk* is a
1062 1063 framed piece of data:
1063 1064
1064 1065 +---------------------------------------+
1065 1066 | | |
1066 1067 | length | data |
1067 1068 | (4 bytes) | (<length - 4> bytes) |
1068 1069 | | |
1069 1070 +---------------------------------------+
1070 1071
1071 1072 All integers are big-endian signed integers. Each chunk starts with a
1072 1073 32-bit integer indicating the length of the entire chunk (including the
1073 1074 length field itself).
1074 1075
1075 1076 There is a special case chunk that has a value of 0 for the length
1076 1077 ("0x00000000"). We call this an *empty chunk*.
1077 1078
1078 1079 Delta Groups
1079 1080 ============
1080 1081
1081 1082 A *delta group* expresses the content of a revlog as a series of deltas,
1082 1083 or patches against previous revisions.
1083 1084
1084 1085 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1085 1086 to signal the end of the delta group:
1086 1087
1087 1088 +------------------------------------------------------------------------+
1088 1089 | | | | | |
1089 1090 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1090 1091 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1091 1092 | | | | | |
1092 1093 +------------------------------------------------------------------------+
1093 1094
1094 1095 Each *chunk*'s data consists of the following:
1095 1096
1096 1097 +---------------------------------------+
1097 1098 | | |
1098 1099 | delta header | delta data |
1099 1100 | (various by version) | (various) |
1100 1101 | | |
1101 1102 +---------------------------------------+
1102 1103
1103 1104 The *delta data* is a series of *delta*s that describe a diff from an
1104 1105 existing entry (either that the recipient already has, or previously
1105 1106 specified in the bundle/changegroup).
1106 1107
1107 1108 The *delta header* is different between versions "1", "2", and "3" of the
1108 1109 changegroup format.
1109 1110
1110 1111 Version 1 (headerlen=80):
1111 1112
1112 1113 +------------------------------------------------------+
1113 1114 | | | | |
1114 1115 | node | p1 node | p2 node | link node |
1115 1116 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1116 1117 | | | | |
1117 1118 +------------------------------------------------------+
1118 1119
1119 1120 Version 2 (headerlen=100):
1120 1121
1121 1122 +------------------------------------------------------------------+
1122 1123 | | | | | |
1123 1124 | node | p1 node | p2 node | base node | link node |
1124 1125 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1125 1126 | | | | | |
1126 1127 +------------------------------------------------------------------+
1127 1128
1128 1129 Version 3 (headerlen=102):
1129 1130
1130 1131 +------------------------------------------------------------------------------+
1131 1132 | | | | | | |
1132 1133 | node | p1 node | p2 node | base node | link node | flags |
1133 1134 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1134 1135 | | | | | | |
1135 1136 +------------------------------------------------------------------------------+
1136 1137
1137 1138 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1138 1139 contain a series of *delta*s, densely packed (no separators). These deltas
1139 1140 describe a diff from an existing entry (either that the recipient already
1140 1141 has, or previously specified in the bundle/changegroup). The format is
1141 1142 described more fully in "hg help internals.bdiff", but briefly:
1142 1143
1143 1144 +---------------------------------------------------------------+
1144 1145 | | | | |
1145 1146 | start offset | end offset | new length | content |
1146 1147 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1147 1148 | | | | |
1148 1149 +---------------------------------------------------------------+
1149 1150
1150 1151 Please note that the length field in the delta data does *not* include
1151 1152 itself.
1152 1153
1153 1154 In version 1, the delta is always applied against the previous node from
1154 1155 the changegroup or the first parent if this is the first entry in the
1155 1156 changegroup.
1156 1157
1157 1158 In version 2 and up, the delta base node is encoded in the entry in the
1158 1159 changegroup. This allows the delta to be expressed against any parent,
1159 1160 which can result in smaller deltas and more efficient encoding of data.
1160 1161
1161 1162 Changeset Segment
1162 1163 =================
1163 1164
1164 1165 The *changeset segment* consists of a single *delta group* holding
1165 1166 changelog data. The *empty chunk* at the end of the *delta group* denotes
1166 1167 the boundary to the *manifest segment*.
1167 1168
1168 1169 Manifest Segment
1169 1170 ================
1170 1171
1171 1172 The *manifest segment* consists of a single *delta group* holding manifest
1172 1173 data. If treemanifests are in use, it contains only the manifest for the
1173 1174 root directory of the repository. Otherwise, it contains the entire
1174 1175 manifest data. The *empty chunk* at the end of the *delta group* denotes
1175 1176 the boundary to the next segment (either the *treemanifests segment* or
1176 1177 the *filelogs segment*, depending on version and the request options).
1177 1178
1178 1179 Treemanifests Segment
1179 1180 ---------------------
1180 1181
1181 1182 The *treemanifests segment* only exists in changegroup version "3", and
1182 1183 only if the 'treemanifest' param is part of the bundle2 changegroup part
1183 1184 (it is not possible to use changegroup version 3 outside of bundle2).
1184 1185 Aside from the filenames in the *treemanifests segment* containing a
1185 1186 trailing "/" character, it behaves identically to the *filelogs segment*
1186 1187 (see below). The final sub-segment is followed by an *empty chunk*
1187 1188 (logically, a sub-segment with filename size 0). This denotes the boundary
1188 1189 to the *filelogs segment*.
1189 1190
1190 1191 Filelogs Segment
1191 1192 ================
1192 1193
1193 1194 The *filelogs segment* consists of multiple sub-segments, each
1194 1195 corresponding to an individual file whose data is being described:
1195 1196
1196 1197 +--------------------------------------------------+
1197 1198 | | | | | |
1198 1199 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1199 1200 | | | | | (4 bytes) |
1200 1201 | | | | | |
1201 1202 +--------------------------------------------------+
1202 1203
1203 1204 The final filelog sub-segment is followed by an *empty chunk* (logically,
1204 1205 a sub-segment with filename size 0). This denotes the end of the segment
1205 1206 and of the overall changegroup.
1206 1207
1207 1208 Each filelog sub-segment consists of the following:
1208 1209
1209 1210 +------------------------------------------------------+
1210 1211 | | | |
1211 1212 | filename length | filename | delta group |
1212 1213 | (4 bytes) | (<length - 4> bytes) | (various) |
1213 1214 | | | |
1214 1215 +------------------------------------------------------+
1215 1216
1216 1217 That is, a *chunk* consisting of the filename (not terminated or padded)
1217 1218 followed by N chunks constituting the *delta group* for this file. The
1218 1219 *empty chunk* at the end of each *delta group* denotes the boundary to the
1219 1220 next filelog sub-segment.
1220 1221
1221 1222 Test list of commands with command with no help text
1222 1223
1223 1224 $ hg help helpext
1224 1225 helpext extension - no help text available
1225 1226
1226 1227 list of commands:
1227 1228
1228 1229 nohelp (no help text available)
1229 1230
1230 1231 (use 'hg help -v helpext' to show built-in aliases and global options)
1231 1232
1232 1233
1233 1234 test advanced, deprecated and experimental options are hidden in command help
1234 1235 $ hg help debugoptADV
1235 1236 hg debugoptADV
1236 1237
1237 1238 (no help text available)
1238 1239
1239 1240 options:
1240 1241
1241 1242 (some details hidden, use --verbose to show complete help)
1242 1243 $ hg help debugoptDEP
1243 1244 hg debugoptDEP
1244 1245
1245 1246 (no help text available)
1246 1247
1247 1248 options:
1248 1249
1249 1250 (some details hidden, use --verbose to show complete help)
1250 1251
1251 1252 $ hg help debugoptEXP
1252 1253 hg debugoptEXP
1253 1254
1254 1255 (no help text available)
1255 1256
1256 1257 options:
1257 1258
1258 1259 (some details hidden, use --verbose to show complete help)
1259 1260
1260 1261 test advanced, deprecated and experimental options are shown with -v
1261 1262 $ hg help -v debugoptADV | grep aopt
1262 1263 --aopt option is (ADVANCED)
1263 1264 $ hg help -v debugoptDEP | grep dopt
1264 1265 --dopt option is (DEPRECATED)
1265 1266 $ hg help -v debugoptEXP | grep eopt
1266 1267 --eopt option is (EXPERIMENTAL)
1267 1268
1268 1269 #if gettext
1269 1270 test deprecated option is hidden with translation with untranslated description
1270 1271 (use many globy for not failing on changed transaction)
1271 1272 $ LANGUAGE=sv hg help debugoptDEP
1272 1273 hg debugoptDEP
1273 1274
1274 1275 (*) (glob)
1275 1276
1276 1277 options:
1277 1278
1278 1279 (some details hidden, use --verbose to show complete help)
1279 1280 #endif
1280 1281
1281 1282 Test commands that collide with topics (issue4240)
1282 1283
1283 1284 $ hg config -hq
1284 1285 hg config [-u] [NAME]...
1285 1286
1286 1287 show combined config settings from all hgrc files
1287 1288 $ hg showconfig -hq
1288 1289 hg config [-u] [NAME]...
1289 1290
1290 1291 show combined config settings from all hgrc files
1291 1292
1292 1293 Test a help topic
1293 1294
1294 1295 $ hg help dates
1295 1296 Date Formats
1296 1297 """"""""""""
1297 1298
1298 1299 Some commands allow the user to specify a date, e.g.:
1299 1300
1300 1301 - backout, commit, import, tag: Specify the commit date.
1301 1302 - log, revert, update: Select revision(s) by date.
1302 1303
1303 1304 Many date formats are valid. Here are some examples:
1304 1305
1305 1306 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1306 1307 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1307 1308 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1308 1309 - "Dec 6" (midnight)
1309 1310 - "13:18" (today assumed)
1310 1311 - "3:39" (3:39AM assumed)
1311 1312 - "3:39pm" (15:39)
1312 1313 - "2006-12-06 13:18:29" (ISO 8601 format)
1313 1314 - "2006-12-6 13:18"
1314 1315 - "2006-12-6"
1315 1316 - "12-6"
1316 1317 - "12/6"
1317 1318 - "12/6/6" (Dec 6 2006)
1318 1319 - "today" (midnight)
1319 1320 - "yesterday" (midnight)
1320 1321 - "now" - right now
1321 1322
1322 1323 Lastly, there is Mercurial's internal format:
1323 1324
1324 1325 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1325 1326
1326 1327 This is the internal representation format for dates. The first number is
1327 1328 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1328 1329 is the offset of the local timezone, in seconds west of UTC (negative if
1329 1330 the timezone is east of UTC).
1330 1331
1331 1332 The log command also accepts date ranges:
1332 1333
1333 1334 - "<DATE" - at or before a given date/time
1334 1335 - ">DATE" - on or after a given date/time
1335 1336 - "DATE to DATE" - a date range, inclusive
1336 1337 - "-DAYS" - within a given number of days of today
1337 1338
1338 1339 Test repeated config section name
1339 1340
1340 1341 $ hg help config.host
1341 1342 "http_proxy.host"
1342 1343 Host name and (optional) port of the proxy server, for example
1343 1344 "myproxy:8000".
1344 1345
1345 1346 "smtp.host"
1346 1347 Host name of mail server, e.g. "mail.example.com".
1347 1348
1348 1349
1349 1350 Test section name with dot
1350 1351
1351 1352 $ hg help config.ui.username
1352 1353 "ui.username"
1353 1354 The committer of a changeset created when running "commit". Typically
1354 1355 a person's name and email address, e.g. "Fred Widget
1355 1356 <fred@example.com>". Environment variables in the username are
1356 1357 expanded.
1357 1358
1358 1359 (default: "$EMAIL" or "username@hostname". If the username in hgrc is
1359 1360 empty, e.g. if the system admin set "username =" in the system hgrc,
1360 1361 it has to be specified manually or in a different hgrc file)
1361 1362
1362 1363
1363 1364 $ hg help config.annotate.git
1364 1365 abort: help section not found: config.annotate.git
1365 1366 [255]
1366 1367
1367 1368 $ hg help config.update.check
1368 1369 "commands.update.check"
1369 1370 Determines what level of checking 'hg update' will perform before
1370 1371 moving to a destination revision. Valid values are "abort", "none",
1371 1372 "linear", and "noconflict". "abort" always fails if the working
1372 1373 directory has uncommitted changes. "none" performs no checking, and
1373 1374 may result in a merge with uncommitted changes. "linear" allows any
1374 1375 update as long as it follows a straight line in the revision history,
1375 1376 and may trigger a merge with uncommitted changes. "noconflict" will
1376 1377 allow any update which would not trigger a merge with uncommitted
1377 1378 changes, if any are present. (default: "linear")
1378 1379
1379 1380
1380 1381 $ hg help config.commands.update.check
1381 1382 "commands.update.check"
1382 1383 Determines what level of checking 'hg update' will perform before
1383 1384 moving to a destination revision. Valid values are "abort", "none",
1384 1385 "linear", and "noconflict". "abort" always fails if the working
1385 1386 directory has uncommitted changes. "none" performs no checking, and
1386 1387 may result in a merge with uncommitted changes. "linear" allows any
1387 1388 update as long as it follows a straight line in the revision history,
1388 1389 and may trigger a merge with uncommitted changes. "noconflict" will
1389 1390 allow any update which would not trigger a merge with uncommitted
1390 1391 changes, if any are present. (default: "linear")
1391 1392
1392 1393
1393 1394 $ hg help config.ommands.update.check
1394 1395 abort: help section not found: config.ommands.update.check
1395 1396 [255]
1396 1397
1397 1398 Unrelated trailing paragraphs shouldn't be included
1398 1399
1399 1400 $ hg help config.extramsg | grep '^$'
1400 1401
1401 1402
1402 1403 Test capitalized section name
1403 1404
1404 1405 $ hg help scripting.HGPLAIN > /dev/null
1405 1406
1406 1407 Help subsection:
1407 1408
1408 1409 $ hg help config.charsets |grep "Email example:" > /dev/null
1409 1410 [1]
1410 1411
1411 1412 Show nested definitions
1412 1413 ("profiling.type"[break]"ls"[break]"stat"[break])
1413 1414
1414 1415 $ hg help config.type | egrep '^$'|wc -l
1415 1416 \s*3 (re)
1416 1417
1417 1418 $ hg help config.profiling.type.ls
1418 1419 "profiling.type.ls"
1419 1420 Use Python's built-in instrumenting profiler. This profiler works on
1420 1421 all platforms, but each line number it reports is the first line of
1421 1422 a function. This restriction makes it difficult to identify the
1422 1423 expensive parts of a non-trivial function.
1423 1424
1424 1425
1425 1426 Separate sections from subsections
1426 1427
1427 1428 $ hg help config.format | egrep '^ ("|-)|^\s*$' | uniq
1428 1429 "format"
1429 1430 --------
1430 1431
1431 1432 "usegeneraldelta"
1432 1433
1433 1434 "dotencode"
1434 1435
1435 1436 "usefncache"
1436 1437
1437 1438 "usestore"
1438 1439
1439 1440 "profiling"
1440 1441 -----------
1441 1442
1442 1443 "format"
1443 1444
1444 1445 "progress"
1445 1446 ----------
1446 1447
1447 1448 "format"
1448 1449
1449 1450
1450 1451 Last item in help config.*:
1451 1452
1452 1453 $ hg help config.`hg help config|grep '^ "'| \
1453 1454 > tail -1|sed 's![ "]*!!g'`| \
1454 1455 > grep 'hg help -c config' > /dev/null
1455 1456 [1]
1456 1457
1457 1458 note to use help -c for general hg help config:
1458 1459
1459 1460 $ hg help config |grep 'hg help -c config' > /dev/null
1460 1461
1461 1462 Test templating help
1462 1463
1463 1464 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
1464 1465 desc String. The text of the changeset description.
1465 1466 diffstat String. Statistics of changes with the following format:
1466 1467 firstline Any text. Returns the first line of text.
1467 1468 nonempty Any text. Returns '(none)' if the string is empty.
1468 1469
1469 1470 Test deprecated items
1470 1471
1471 1472 $ hg help -v templating | grep currentbookmark
1472 1473 currentbookmark
1473 1474 $ hg help templating | (grep currentbookmark || true)
1474 1475
1475 1476 Test help hooks
1476 1477
1477 1478 $ cat > helphook1.py <<EOF
1478 1479 > from mercurial import help
1479 1480 >
1480 1481 > def rewrite(ui, topic, doc):
1481 1482 > return doc + '\nhelphook1\n'
1482 1483 >
1483 1484 > def extsetup(ui):
1484 1485 > help.addtopichook('revisions', rewrite)
1485 1486 > EOF
1486 1487 $ cat > helphook2.py <<EOF
1487 1488 > from mercurial import help
1488 1489 >
1489 1490 > def rewrite(ui, topic, doc):
1490 1491 > return doc + '\nhelphook2\n'
1491 1492 >
1492 1493 > def extsetup(ui):
1493 1494 > help.addtopichook('revisions', rewrite)
1494 1495 > EOF
1495 1496 $ echo '[extensions]' >> $HGRCPATH
1496 1497 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1497 1498 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1498 1499 $ hg help revsets | grep helphook
1499 1500 helphook1
1500 1501 helphook2
1501 1502
1502 1503 help -c should only show debug --debug
1503 1504
1504 1505 $ hg help -c --debug|egrep debug|wc -l|egrep '^\s*0\s*$'
1505 1506 [1]
1506 1507
1507 1508 help -c should only show deprecated for -v
1508 1509
1509 1510 $ hg help -c -v|egrep DEPRECATED|wc -l|egrep '^\s*0\s*$'
1510 1511 [1]
1511 1512
1512 1513 Test -s / --system
1513 1514
1514 1515 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1515 1516 > wc -l | sed -e 's/ //g'
1516 1517 0
1517 1518 $ hg help config.files --system unix | grep 'USER' | \
1518 1519 > wc -l | sed -e 's/ //g'
1519 1520 0
1520 1521
1521 1522 Test -e / -c / -k combinations
1522 1523
1523 1524 $ hg help -c|egrep '^[A-Z].*:|^ debug'
1524 1525 Commands:
1525 1526 $ hg help -e|egrep '^[A-Z].*:|^ debug'
1526 1527 Extensions:
1527 1528 $ hg help -k|egrep '^[A-Z].*:|^ debug'
1528 1529 Topics:
1529 1530 Commands:
1530 1531 Extensions:
1531 1532 Extension Commands:
1532 1533 $ hg help -c schemes
1533 1534 abort: no such help topic: schemes
1534 1535 (try 'hg help --keyword schemes')
1535 1536 [255]
1536 1537 $ hg help -e schemes |head -1
1537 1538 schemes extension - extend schemes with shortcuts to repository swarms
1538 1539 $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
1539 1540 Commands:
1540 1541 $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
1541 1542 Extensions:
1542 1543 $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
1543 1544 Extensions:
1544 1545 Commands:
1545 1546 $ hg help -c commit > /dev/null
1546 1547 $ hg help -e -c commit > /dev/null
1547 1548 $ hg help -e commit
1548 1549 abort: no such help topic: commit
1549 1550 (try 'hg help --keyword commit')
1550 1551 [255]
1551 1552
1552 1553 Test keyword search help
1553 1554
1554 1555 $ cat > prefixedname.py <<EOF
1555 1556 > '''matched against word "clone"
1556 1557 > '''
1557 1558 > EOF
1558 1559 $ echo '[extensions]' >> $HGRCPATH
1559 1560 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1560 1561 $ hg help -k clone
1561 1562 Topics:
1562 1563
1563 1564 config Configuration Files
1564 1565 extensions Using Additional Features
1565 1566 glossary Glossary
1566 1567 phases Working with Phases
1567 1568 subrepos Subrepositories
1568 1569 urls URL Paths
1569 1570
1570 1571 Commands:
1571 1572
1572 1573 bookmarks create a new bookmark or list existing bookmarks
1573 1574 clone make a copy of an existing repository
1574 1575 paths show aliases for remote repositories
1575 1576 pull pull changes from the specified source
1576 1577 update update working directory (or switch revisions)
1577 1578
1578 1579 Extensions:
1579 1580
1580 1581 clonebundles advertise pre-generated bundles to seed clones
1581 1582 narrow create clones which fetch history data for subset of files
1582 1583 (EXPERIMENTAL)
1583 1584 prefixedname matched against word "clone"
1584 1585 relink recreates hardlinks between repository clones
1585 1586
1586 1587 Extension Commands:
1587 1588
1588 1589 qclone clone main and patch repository at same time
1589 1590
1590 1591 Test unfound topic
1591 1592
1592 1593 $ hg help nonexistingtopicthatwillneverexisteverever
1593 1594 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1594 1595 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1595 1596 [255]
1596 1597
1597 1598 Test unfound keyword
1598 1599
1599 1600 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1600 1601 abort: no matches
1601 1602 (try 'hg help' for a list of topics)
1602 1603 [255]
1603 1604
1604 1605 Test omit indicating for help
1605 1606
1606 1607 $ cat > addverboseitems.py <<EOF
1607 1608 > '''extension to test omit indicating.
1608 1609 >
1609 1610 > This paragraph is never omitted (for extension)
1610 1611 >
1611 1612 > .. container:: verbose
1612 1613 >
1613 1614 > This paragraph is omitted,
1614 1615 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1615 1616 >
1616 1617 > This paragraph is never omitted, too (for extension)
1617 1618 > '''
1618 1619 > from __future__ import absolute_import
1619 1620 > from mercurial import commands, help
1620 1621 > testtopic = """This paragraph is never omitted (for topic).
1621 1622 >
1622 1623 > .. container:: verbose
1623 1624 >
1624 1625 > This paragraph is omitted,
1625 1626 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1626 1627 >
1627 1628 > This paragraph is never omitted, too (for topic)
1628 1629 > """
1629 1630 > def extsetup(ui):
1630 1631 > help.helptable.append((["topic-containing-verbose"],
1631 1632 > "This is the topic to test omit indicating.",
1632 1633 > lambda ui: testtopic))
1633 1634 > EOF
1634 1635 $ echo '[extensions]' >> $HGRCPATH
1635 1636 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1636 1637 $ hg help addverboseitems
1637 1638 addverboseitems extension - extension to test omit indicating.
1638 1639
1639 1640 This paragraph is never omitted (for extension)
1640 1641
1641 1642 This paragraph is never omitted, too (for extension)
1642 1643
1643 1644 (some details hidden, use --verbose to show complete help)
1644 1645
1645 1646 no commands defined
1646 1647 $ hg help -v addverboseitems
1647 1648 addverboseitems extension - extension to test omit indicating.
1648 1649
1649 1650 This paragraph is never omitted (for extension)
1650 1651
1651 1652 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1652 1653 extension)
1653 1654
1654 1655 This paragraph is never omitted, too (for extension)
1655 1656
1656 1657 no commands defined
1657 1658 $ hg help topic-containing-verbose
1658 1659 This is the topic to test omit indicating.
1659 1660 """"""""""""""""""""""""""""""""""""""""""
1660 1661
1661 1662 This paragraph is never omitted (for topic).
1662 1663
1663 1664 This paragraph is never omitted, too (for topic)
1664 1665
1665 1666 (some details hidden, use --verbose to show complete help)
1666 1667 $ hg help -v topic-containing-verbose
1667 1668 This is the topic to test omit indicating.
1668 1669 """"""""""""""""""""""""""""""""""""""""""
1669 1670
1670 1671 This paragraph is never omitted (for topic).
1671 1672
1672 1673 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1673 1674 topic)
1674 1675
1675 1676 This paragraph is never omitted, too (for topic)
1676 1677
1677 1678 Test section lookup
1678 1679
1679 1680 $ hg help revset.merge
1680 1681 "merge()"
1681 1682 Changeset is a merge changeset.
1682 1683
1683 1684 $ hg help glossary.dag
1684 1685 DAG
1685 1686 The repository of changesets of a distributed version control system
1686 1687 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1687 1688 of nodes and edges, where nodes correspond to changesets and edges
1688 1689 imply a parent -> child relation. This graph can be visualized by
1689 1690 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1690 1691 limited by the requirement for children to have at most two parents.
1691 1692
1692 1693
1693 1694 $ hg help hgrc.paths
1694 1695 "paths"
1695 1696 -------
1696 1697
1697 1698 Assigns symbolic names and behavior to repositories.
1698 1699
1699 1700 Options are symbolic names defining the URL or directory that is the
1700 1701 location of the repository. Example:
1701 1702
1702 1703 [paths]
1703 1704 my_server = https://example.com/my_repo
1704 1705 local_path = /home/me/repo
1705 1706
1706 1707 These symbolic names can be used from the command line. To pull from
1707 1708 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1708 1709 local_path'.
1709 1710
1710 1711 Options containing colons (":") denote sub-options that can influence
1711 1712 behavior for that specific path. Example:
1712 1713
1713 1714 [paths]
1714 1715 my_server = https://example.com/my_path
1715 1716 my_server:pushurl = ssh://example.com/my_path
1716 1717
1717 1718 The following sub-options can be defined:
1718 1719
1719 1720 "pushurl"
1720 1721 The URL to use for push operations. If not defined, the location
1721 1722 defined by the path's main entry is used.
1722 1723
1723 1724 "pushrev"
1724 1725 A revset defining which revisions to push by default.
1725 1726
1726 1727 When 'hg push' is executed without a "-r" argument, the revset defined
1727 1728 by this sub-option is evaluated to determine what to push.
1728 1729
1729 1730 For example, a value of "." will push the working directory's revision
1730 1731 by default.
1731 1732
1732 1733 Revsets specifying bookmarks will not result in the bookmark being
1733 1734 pushed.
1734 1735
1735 1736 The following special named paths exist:
1736 1737
1737 1738 "default"
1738 1739 The URL or directory to use when no source or remote is specified.
1739 1740
1740 1741 'hg clone' will automatically define this path to the location the
1741 1742 repository was cloned from.
1742 1743
1743 1744 "default-push"
1744 1745 (deprecated) The URL or directory for the default 'hg push' location.
1745 1746 "default:pushurl" should be used instead.
1746 1747
1747 1748 $ hg help glossary.mcguffin
1748 1749 abort: help section not found: glossary.mcguffin
1749 1750 [255]
1750 1751
1751 1752 $ hg help glossary.mc.guffin
1752 1753 abort: help section not found: glossary.mc.guffin
1753 1754 [255]
1754 1755
1755 1756 $ hg help template.files
1756 1757 files List of strings. All files modified, added, or removed by
1757 1758 this changeset.
1758 1759 files(pattern)
1759 1760 All files of the current changeset matching the pattern. See
1760 1761 'hg help patterns'.
1761 1762
1762 1763 Test section lookup by translated message
1763 1764
1764 1765 str.lower() instead of encoding.lower(str) on translated message might
1765 1766 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
1766 1767 as the second or later byte of multi-byte character.
1767 1768
1768 1769 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
1769 1770 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
1770 1771 replacement makes message meaningless.
1771 1772
1772 1773 This tests that section lookup by translated string isn't broken by
1773 1774 such str.lower().
1774 1775
1775 1776 $ "$PYTHON" <<EOF
1776 1777 > def escape(s):
1777 1778 > return ''.join('\u%x' % ord(uc) for uc in s.decode('cp932'))
1778 1779 > # translation of "record" in ja_JP.cp932
1779 1780 > upper = "\x8bL\x98^"
1780 1781 > # str.lower()-ed section name should be treated as different one
1781 1782 > lower = "\x8bl\x98^"
1782 1783 > with open('ambiguous.py', 'w') as fp:
1783 1784 > fp.write("""# ambiguous section names in ja_JP.cp932
1784 1785 > u'''summary of extension
1785 1786 >
1786 1787 > %s
1787 1788 > ----
1788 1789 >
1789 1790 > Upper name should show only this message
1790 1791 >
1791 1792 > %s
1792 1793 > ----
1793 1794 >
1794 1795 > Lower name should show only this message
1795 1796 >
1796 1797 > subsequent section
1797 1798 > ------------------
1798 1799 >
1799 1800 > This should be hidden at 'hg help ambiguous' with section name.
1800 1801 > '''
1801 1802 > """ % (escape(upper), escape(lower)))
1802 1803 > EOF
1803 1804
1804 1805 $ cat >> $HGRCPATH <<EOF
1805 1806 > [extensions]
1806 1807 > ambiguous = ./ambiguous.py
1807 1808 > EOF
1808 1809
1809 1810 $ "$PYTHON" <<EOF | sh
1810 1811 > upper = "\x8bL\x98^"
1811 1812 > print("hg --encoding cp932 help -e ambiguous.%s" % upper)
1812 1813 > EOF
1813 1814 \x8bL\x98^ (esc)
1814 1815 ----
1815 1816
1816 1817 Upper name should show only this message
1817 1818
1818 1819
1819 1820 $ "$PYTHON" <<EOF | sh
1820 1821 > lower = "\x8bl\x98^"
1821 1822 > print("hg --encoding cp932 help -e ambiguous.%s" % lower)
1822 1823 > EOF
1823 1824 \x8bl\x98^ (esc)
1824 1825 ----
1825 1826
1826 1827 Lower name should show only this message
1827 1828
1828 1829
1829 1830 $ cat >> $HGRCPATH <<EOF
1830 1831 > [extensions]
1831 1832 > ambiguous = !
1832 1833 > EOF
1833 1834
1834 1835 Show help content of disabled extensions
1835 1836
1836 1837 $ cat >> $HGRCPATH <<EOF
1837 1838 > [extensions]
1838 1839 > ambiguous = !./ambiguous.py
1839 1840 > EOF
1840 1841 $ hg help -e ambiguous
1841 1842 ambiguous extension - (no help text available)
1842 1843
1843 1844 (use 'hg help extensions' for information on enabling extensions)
1844 1845
1845 1846 Test dynamic list of merge tools only shows up once
1846 1847 $ hg help merge-tools
1847 1848 Merge Tools
1848 1849 """""""""""
1849 1850
1850 1851 To merge files Mercurial uses merge tools.
1851 1852
1852 1853 A merge tool combines two different versions of a file into a merged file.
1853 1854 Merge tools are given the two files and the greatest common ancestor of
1854 1855 the two file versions, so they can determine the changes made on both
1855 1856 branches.
1856 1857
1857 1858 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
1858 1859 backout' and in several extensions.
1859 1860
1860 1861 Usually, the merge tool tries to automatically reconcile the files by
1861 1862 combining all non-overlapping changes that occurred separately in the two
1862 1863 different evolutions of the same initial base file. Furthermore, some
1863 1864 interactive merge programs make it easier to manually resolve conflicting
1864 1865 merges, either in a graphical way, or by inserting some conflict markers.
1865 1866 Mercurial does not include any interactive merge programs but relies on
1866 1867 external tools for that.
1867 1868
1868 1869 Available merge tools
1869 1870 =====================
1870 1871
1871 1872 External merge tools and their properties are configured in the merge-
1872 1873 tools configuration section - see hgrc(5) - but they can often just be
1873 1874 named by their executable.
1874 1875
1875 1876 A merge tool is generally usable if its executable can be found on the
1876 1877 system and if it can handle the merge. The executable is found if it is an
1877 1878 absolute or relative executable path or the name of an application in the
1878 1879 executable search path. The tool is assumed to be able to handle the merge
1879 1880 if it can handle symlinks if the file is a symlink, if it can handle
1880 1881 binary files if the file is binary, and if a GUI is available if the tool
1881 1882 requires a GUI.
1882 1883
1883 1884 There are some internal merge tools which can be used. The internal merge
1884 1885 tools are:
1885 1886
1886 1887 ":dump"
1887 1888 Creates three versions of the files to merge, containing the contents of
1888 1889 local, other and base. These files can then be used to perform a merge
1889 1890 manually. If the file to be merged is named "a.txt", these files will
1890 1891 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
1891 1892 they will be placed in the same directory as "a.txt".
1892 1893
1893 1894 This implies premerge. Therefore, files aren't dumped, if premerge runs
1894 1895 successfully. Use :forcedump to forcibly write files out.
1895 1896
1896 1897 (actual capabilities: binary, symlink)
1897 1898
1898 1899 ":fail"
1899 1900 Rather than attempting to merge files that were modified on both
1900 1901 branches, it marks them as unresolved. The resolve command must be used
1901 1902 to resolve these conflicts.
1902 1903
1903 1904 (actual capabilities: binary, symlink)
1904 1905
1905 1906 ":forcedump"
1906 1907 Creates three versions of the files as same as :dump, but omits
1907 1908 premerge.
1908 1909
1909 1910 (actual capabilities: binary, symlink)
1910 1911
1911 1912 ":local"
1912 1913 Uses the local 'p1()' version of files as the merged version.
1913 1914
1914 1915 (actual capabilities: binary, symlink)
1915 1916
1916 1917 ":merge"
1917 1918 Uses the internal non-interactive simple merge algorithm for merging
1918 1919 files. It will fail if there are any conflicts and leave markers in the
1919 1920 partially merged file. Markers will have two sections, one for each side
1920 1921 of merge.
1921 1922
1922 1923 ":merge-local"
1923 1924 Like :merge, but resolve all conflicts non-interactively in favor of the
1924 1925 local 'p1()' changes.
1925 1926
1926 1927 ":merge-other"
1927 1928 Like :merge, but resolve all conflicts non-interactively in favor of the
1928 1929 other 'p2()' changes.
1929 1930
1930 1931 ":merge3"
1931 1932 Uses the internal non-interactive simple merge algorithm for merging
1932 1933 files. It will fail if there are any conflicts and leave markers in the
1933 1934 partially merged file. Marker will have three sections, one from each
1934 1935 side of the merge and one for the base content.
1935 1936
1936 1937 ":other"
1937 1938 Uses the other 'p2()' version of files as the merged version.
1938 1939
1939 1940 (actual capabilities: binary, symlink)
1940 1941
1941 1942 ":prompt"
1942 1943 Asks the user which of the local 'p1()' or the other 'p2()' version to
1943 1944 keep as the merged version.
1944 1945
1945 1946 (actual capabilities: binary, symlink)
1946 1947
1947 1948 ":tagmerge"
1948 1949 Uses the internal tag merge algorithm (experimental).
1949 1950
1950 1951 ":union"
1951 1952 Uses the internal non-interactive simple merge algorithm for merging
1952 1953 files. It will use both left and right sides for conflict regions. No
1953 1954 markers are inserted.
1954 1955
1955 1956 Internal tools are always available and do not require a GUI but will by
1956 1957 default not handle symlinks or binary files. See next section for detail
1957 1958 about "actual capabilities" described above.
1958 1959
1959 1960 Choosing a merge tool
1960 1961 =====================
1961 1962
1962 1963 Mercurial uses these rules when deciding which merge tool to use:
1963 1964
1964 1965 1. If a tool has been specified with the --tool option to merge or
1965 1966 resolve, it is used. If it is the name of a tool in the merge-tools
1966 1967 configuration, its configuration is used. Otherwise the specified tool
1967 1968 must be executable by the shell.
1968 1969 2. If the "HGMERGE" environment variable is present, its value is used and
1969 1970 must be executable by the shell.
1970 1971 3. If the filename of the file to be merged matches any of the patterns in
1971 1972 the merge-patterns configuration section, the first usable merge tool
1972 1973 corresponding to a matching pattern is used.
1973 1974 4. If ui.merge is set it will be considered next. If the value is not the
1974 1975 name of a configured tool, the specified value is used and must be
1975 1976 executable by the shell. Otherwise the named tool is used if it is
1976 1977 usable.
1977 1978 5. If any usable merge tools are present in the merge-tools configuration
1978 1979 section, the one with the highest priority is used.
1979 1980 6. If a program named "hgmerge" can be found on the system, it is used -
1980 1981 but it will by default not be used for symlinks and binary files.
1981 1982 7. If the file to be merged is not binary and is not a symlink, then
1982 1983 internal ":merge" is used.
1983 1984 8. Otherwise, ":prompt" is used.
1984 1985
1985 1986 For historical reason, Mercurial treats merge tools as below while
1986 1987 examining rules above.
1987 1988
1988 1989 step specified via binary symlink
1989 1990 ----------------------------------
1990 1991 1. --tool o/o o/o
1991 1992 2. HGMERGE o/o o/o
1992 1993 3. merge-patterns o/o(*) x/?(*)
1993 1994 4. ui.merge x/?(*) x/?(*)
1994 1995
1995 1996 Each capability column indicates Mercurial behavior for internal/external
1996 1997 merge tools at examining each rule.
1997 1998
1998 1999 - "o": "assume that a tool has capability"
1999 2000 - "x": "assume that a tool does not have capability"
2000 2001 - "?": "check actual capability of a tool"
2001 2002
2002 2003 If "merge.strict-capability-check" configuration is true, Mercurial checks
2003 2004 capabilities of merge tools strictly in (*) cases above (= each capability
2004 2005 column becomes "?/?"). It is false by default for backward compatibility.
2005 2006
2006 2007 Note:
2007 2008 After selecting a merge program, Mercurial will by default attempt to
2008 2009 merge the files using a simple merge algorithm first. Only if it
2009 2010 doesn't succeed because of conflicting changes will Mercurial actually
2010 2011 execute the merge program. Whether to use the simple merge algorithm
2011 2012 first can be controlled by the premerge setting of the merge tool.
2012 2013 Premerge is enabled by default unless the file is binary or a symlink.
2013 2014
2014 2015 See the merge-tools and ui sections of hgrc(5) for details on the
2015 2016 configuration of merge tools.
2016 2017
2017 2018 Compression engines listed in `hg help bundlespec`
2018 2019
2019 2020 $ hg help bundlespec | grep gzip
2020 2021 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
2021 2022 An algorithm that produces smaller bundles than "gzip".
2022 2023 This engine will likely produce smaller bundles than "gzip" but will be
2023 2024 "gzip"
2024 2025 better compression than "gzip". It also frequently yields better (?)
2025 2026
2026 2027 Test usage of section marks in help documents
2027 2028
2028 2029 $ cd "$TESTDIR"/../doc
2029 2030 $ "$PYTHON" check-seclevel.py
2030 2031 $ cd $TESTTMP
2031 2032
2032 2033 #if serve
2033 2034
2034 2035 Test the help pages in hgweb.
2035 2036
2036 2037 Dish up an empty repo; serve it cold.
2037 2038
2038 2039 $ hg init "$TESTTMP/test"
2039 2040 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
2040 2041 $ cat hg.pid >> $DAEMON_PIDS
2041 2042
2042 2043 $ get-with-headers.py $LOCALIP:$HGPORT "help"
2043 2044 200 Script output follows
2044 2045
2045 2046 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2046 2047 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2047 2048 <head>
2048 2049 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2049 2050 <meta name="robots" content="index, nofollow" />
2050 2051 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2051 2052 <script type="text/javascript" src="/static/mercurial.js"></script>
2052 2053
2053 2054 <title>Help: Index</title>
2054 2055 </head>
2055 2056 <body>
2056 2057
2057 2058 <div class="container">
2058 2059 <div class="menu">
2059 2060 <div class="logo">
2060 2061 <a href="https://mercurial-scm.org/">
2061 2062 <img src="/static/hglogo.png" alt="mercurial" /></a>
2062 2063 </div>
2063 2064 <ul>
2064 2065 <li><a href="/shortlog">log</a></li>
2065 2066 <li><a href="/graph">graph</a></li>
2066 2067 <li><a href="/tags">tags</a></li>
2067 2068 <li><a href="/bookmarks">bookmarks</a></li>
2068 2069 <li><a href="/branches">branches</a></li>
2069 2070 </ul>
2070 2071 <ul>
2071 2072 <li class="active">help</li>
2072 2073 </ul>
2073 2074 </div>
2074 2075
2075 2076 <div class="main">
2076 2077 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2077 2078
2078 2079 <form class="search" action="/log">
2079 2080
2080 2081 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2081 2082 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2082 2083 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2083 2084 </form>
2084 2085 <table class="bigtable">
2085 2086 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
2086 2087
2087 2088 <tr><td>
2088 2089 <a href="/help/bundlespec">
2089 2090 bundlespec
2090 2091 </a>
2091 2092 </td><td>
2092 2093 Bundle File Formats
2093 2094 </td></tr>
2094 2095 <tr><td>
2095 2096 <a href="/help/color">
2096 2097 color
2097 2098 </a>
2098 2099 </td><td>
2099 2100 Colorizing Outputs
2100 2101 </td></tr>
2101 2102 <tr><td>
2102 2103 <a href="/help/config">
2103 2104 config
2104 2105 </a>
2105 2106 </td><td>
2106 2107 Configuration Files
2107 2108 </td></tr>
2108 2109 <tr><td>
2109 2110 <a href="/help/dates">
2110 2111 dates
2111 2112 </a>
2112 2113 </td><td>
2113 2114 Date Formats
2114 2115 </td></tr>
2115 2116 <tr><td>
2116 2117 <a href="/help/deprecated">
2117 2118 deprecated
2118 2119 </a>
2119 2120 </td><td>
2120 2121 Deprecated Features
2121 2122 </td></tr>
2122 2123 <tr><td>
2123 2124 <a href="/help/diffs">
2124 2125 diffs
2125 2126 </a>
2126 2127 </td><td>
2127 2128 Diff Formats
2128 2129 </td></tr>
2129 2130 <tr><td>
2130 2131 <a href="/help/environment">
2131 2132 environment
2132 2133 </a>
2133 2134 </td><td>
2134 2135 Environment Variables
2135 2136 </td></tr>
2136 2137 <tr><td>
2137 2138 <a href="/help/extensions">
2138 2139 extensions
2139 2140 </a>
2140 2141 </td><td>
2141 2142 Using Additional Features
2142 2143 </td></tr>
2143 2144 <tr><td>
2144 2145 <a href="/help/filesets">
2145 2146 filesets
2146 2147 </a>
2147 2148 </td><td>
2148 2149 Specifying File Sets
2149 2150 </td></tr>
2150 2151 <tr><td>
2151 2152 <a href="/help/flags">
2152 2153 flags
2153 2154 </a>
2154 2155 </td><td>
2155 2156 Command-line flags
2156 2157 </td></tr>
2157 2158 <tr><td>
2158 2159 <a href="/help/glossary">
2159 2160 glossary
2160 2161 </a>
2161 2162 </td><td>
2162 2163 Glossary
2163 2164 </td></tr>
2164 2165 <tr><td>
2165 2166 <a href="/help/hgignore">
2166 2167 hgignore
2167 2168 </a>
2168 2169 </td><td>
2169 2170 Syntax for Mercurial Ignore Files
2170 2171 </td></tr>
2171 2172 <tr><td>
2172 2173 <a href="/help/hgweb">
2173 2174 hgweb
2174 2175 </a>
2175 2176 </td><td>
2176 2177 Configuring hgweb
2177 2178 </td></tr>
2178 2179 <tr><td>
2179 2180 <a href="/help/internals">
2180 2181 internals
2181 2182 </a>
2182 2183 </td><td>
2183 2184 Technical implementation topics
2184 2185 </td></tr>
2185 2186 <tr><td>
2186 2187 <a href="/help/merge-tools">
2187 2188 merge-tools
2188 2189 </a>
2189 2190 </td><td>
2190 2191 Merge Tools
2191 2192 </td></tr>
2192 2193 <tr><td>
2193 2194 <a href="/help/pager">
2194 2195 pager
2195 2196 </a>
2196 2197 </td><td>
2197 2198 Pager Support
2198 2199 </td></tr>
2199 2200 <tr><td>
2200 2201 <a href="/help/patterns">
2201 2202 patterns
2202 2203 </a>
2203 2204 </td><td>
2204 2205 File Name Patterns
2205 2206 </td></tr>
2206 2207 <tr><td>
2207 2208 <a href="/help/phases">
2208 2209 phases
2209 2210 </a>
2210 2211 </td><td>
2211 2212 Working with Phases
2212 2213 </td></tr>
2213 2214 <tr><td>
2214 2215 <a href="/help/revisions">
2215 2216 revisions
2216 2217 </a>
2217 2218 </td><td>
2218 2219 Specifying Revisions
2219 2220 </td></tr>
2220 2221 <tr><td>
2221 2222 <a href="/help/scripting">
2222 2223 scripting
2223 2224 </a>
2224 2225 </td><td>
2225 2226 Using Mercurial from scripts and automation
2226 2227 </td></tr>
2227 2228 <tr><td>
2228 2229 <a href="/help/subrepos">
2229 2230 subrepos
2230 2231 </a>
2231 2232 </td><td>
2232 2233 Subrepositories
2233 2234 </td></tr>
2234 2235 <tr><td>
2235 2236 <a href="/help/templating">
2236 2237 templating
2237 2238 </a>
2238 2239 </td><td>
2239 2240 Template Usage
2240 2241 </td></tr>
2241 2242 <tr><td>
2242 2243 <a href="/help/urls">
2243 2244 urls
2244 2245 </a>
2245 2246 </td><td>
2246 2247 URL Paths
2247 2248 </td></tr>
2248 2249 <tr><td>
2249 2250 <a href="/help/topic-containing-verbose">
2250 2251 topic-containing-verbose
2251 2252 </a>
2252 2253 </td><td>
2253 2254 This is the topic to test omit indicating.
2254 2255 </td></tr>
2255 2256
2256 2257
2257 2258 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2258 2259
2259 2260 <tr><td>
2260 2261 <a href="/help/add">
2261 2262 add
2262 2263 </a>
2263 2264 </td><td>
2264 2265 add the specified files on the next commit
2265 2266 </td></tr>
2266 2267 <tr><td>
2267 2268 <a href="/help/annotate">
2268 2269 annotate
2269 2270 </a>
2270 2271 </td><td>
2271 2272 show changeset information by line for each file
2272 2273 </td></tr>
2273 2274 <tr><td>
2274 2275 <a href="/help/clone">
2275 2276 clone
2276 2277 </a>
2277 2278 </td><td>
2278 2279 make a copy of an existing repository
2279 2280 </td></tr>
2280 2281 <tr><td>
2281 2282 <a href="/help/commit">
2282 2283 commit
2283 2284 </a>
2284 2285 </td><td>
2285 2286 commit the specified files or all outstanding changes
2286 2287 </td></tr>
2287 2288 <tr><td>
2288 2289 <a href="/help/diff">
2289 2290 diff
2290 2291 </a>
2291 2292 </td><td>
2292 2293 diff repository (or selected files)
2293 2294 </td></tr>
2294 2295 <tr><td>
2295 2296 <a href="/help/export">
2296 2297 export
2297 2298 </a>
2298 2299 </td><td>
2299 2300 dump the header and diffs for one or more changesets
2300 2301 </td></tr>
2301 2302 <tr><td>
2302 2303 <a href="/help/forget">
2303 2304 forget
2304 2305 </a>
2305 2306 </td><td>
2306 2307 forget the specified files on the next commit
2307 2308 </td></tr>
2308 2309 <tr><td>
2309 2310 <a href="/help/init">
2310 2311 init
2311 2312 </a>
2312 2313 </td><td>
2313 2314 create a new repository in the given directory
2314 2315 </td></tr>
2315 2316 <tr><td>
2316 2317 <a href="/help/log">
2317 2318 log
2318 2319 </a>
2319 2320 </td><td>
2320 2321 show revision history of entire repository or files
2321 2322 </td></tr>
2322 2323 <tr><td>
2323 2324 <a href="/help/merge">
2324 2325 merge
2325 2326 </a>
2326 2327 </td><td>
2327 2328 merge another revision into working directory
2328 2329 </td></tr>
2329 2330 <tr><td>
2330 2331 <a href="/help/pull">
2331 2332 pull
2332 2333 </a>
2333 2334 </td><td>
2334 2335 pull changes from the specified source
2335 2336 </td></tr>
2336 2337 <tr><td>
2337 2338 <a href="/help/push">
2338 2339 push
2339 2340 </a>
2340 2341 </td><td>
2341 2342 push changes to the specified destination
2342 2343 </td></tr>
2343 2344 <tr><td>
2344 2345 <a href="/help/remove">
2345 2346 remove
2346 2347 </a>
2347 2348 </td><td>
2348 2349 remove the specified files on the next commit
2349 2350 </td></tr>
2350 2351 <tr><td>
2351 2352 <a href="/help/serve">
2352 2353 serve
2353 2354 </a>
2354 2355 </td><td>
2355 2356 start stand-alone webserver
2356 2357 </td></tr>
2357 2358 <tr><td>
2358 2359 <a href="/help/status">
2359 2360 status
2360 2361 </a>
2361 2362 </td><td>
2362 2363 show changed files in the working directory
2363 2364 </td></tr>
2364 2365 <tr><td>
2365 2366 <a href="/help/summary">
2366 2367 summary
2367 2368 </a>
2368 2369 </td><td>
2369 2370 summarize working directory state
2370 2371 </td></tr>
2371 2372 <tr><td>
2372 2373 <a href="/help/update">
2373 2374 update
2374 2375 </a>
2375 2376 </td><td>
2376 2377 update working directory (or switch revisions)
2377 2378 </td></tr>
2378 2379
2379 2380
2380 2381
2381 2382 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2382 2383
2383 2384 <tr><td>
2384 2385 <a href="/help/addremove">
2385 2386 addremove
2386 2387 </a>
2387 2388 </td><td>
2388 2389 add all new files, delete all missing files
2389 2390 </td></tr>
2390 2391 <tr><td>
2391 2392 <a href="/help/archive">
2392 2393 archive
2393 2394 </a>
2394 2395 </td><td>
2395 2396 create an unversioned archive of a repository revision
2396 2397 </td></tr>
2397 2398 <tr><td>
2398 2399 <a href="/help/backout">
2399 2400 backout
2400 2401 </a>
2401 2402 </td><td>
2402 2403 reverse effect of earlier changeset
2403 2404 </td></tr>
2404 2405 <tr><td>
2405 2406 <a href="/help/bisect">
2406 2407 bisect
2407 2408 </a>
2408 2409 </td><td>
2409 2410 subdivision search of changesets
2410 2411 </td></tr>
2411 2412 <tr><td>
2412 2413 <a href="/help/bookmarks">
2413 2414 bookmarks
2414 2415 </a>
2415 2416 </td><td>
2416 2417 create a new bookmark or list existing bookmarks
2417 2418 </td></tr>
2418 2419 <tr><td>
2419 2420 <a href="/help/branch">
2420 2421 branch
2421 2422 </a>
2422 2423 </td><td>
2423 2424 set or show the current branch name
2424 2425 </td></tr>
2425 2426 <tr><td>
2426 2427 <a href="/help/branches">
2427 2428 branches
2428 2429 </a>
2429 2430 </td><td>
2430 2431 list repository named branches
2431 2432 </td></tr>
2432 2433 <tr><td>
2433 2434 <a href="/help/bundle">
2434 2435 bundle
2435 2436 </a>
2436 2437 </td><td>
2437 2438 create a bundle file
2438 2439 </td></tr>
2439 2440 <tr><td>
2440 2441 <a href="/help/cat">
2441 2442 cat
2442 2443 </a>
2443 2444 </td><td>
2444 2445 output the current or given revision of files
2445 2446 </td></tr>
2446 2447 <tr><td>
2447 2448 <a href="/help/config">
2448 2449 config
2449 2450 </a>
2450 2451 </td><td>
2451 2452 show combined config settings from all hgrc files
2452 2453 </td></tr>
2453 2454 <tr><td>
2454 2455 <a href="/help/copy">
2455 2456 copy
2456 2457 </a>
2457 2458 </td><td>
2458 2459 mark files as copied for the next commit
2459 2460 </td></tr>
2460 2461 <tr><td>
2461 2462 <a href="/help/files">
2462 2463 files
2463 2464 </a>
2464 2465 </td><td>
2465 2466 list tracked files
2466 2467 </td></tr>
2467 2468 <tr><td>
2468 2469 <a href="/help/graft">
2469 2470 graft
2470 2471 </a>
2471 2472 </td><td>
2472 2473 copy changes from other branches onto the current branch
2473 2474 </td></tr>
2474 2475 <tr><td>
2475 2476 <a href="/help/grep">
2476 2477 grep
2477 2478 </a>
2478 2479 </td><td>
2479 2480 search revision history for a pattern in specified files
2480 2481 </td></tr>
2481 2482 <tr><td>
2482 2483 <a href="/help/heads">
2483 2484 heads
2484 2485 </a>
2485 2486 </td><td>
2486 2487 show branch heads
2487 2488 </td></tr>
2488 2489 <tr><td>
2489 2490 <a href="/help/help">
2490 2491 help
2491 2492 </a>
2492 2493 </td><td>
2493 2494 show help for a given topic or a help overview
2494 2495 </td></tr>
2495 2496 <tr><td>
2496 2497 <a href="/help/hgalias">
2497 2498 hgalias
2498 2499 </a>
2499 2500 </td><td>
2500 2501 summarize working directory state
2501 2502 </td></tr>
2502 2503 <tr><td>
2503 2504 <a href="/help/identify">
2504 2505 identify
2505 2506 </a>
2506 2507 </td><td>
2507 2508 identify the working directory or specified revision
2508 2509 </td></tr>
2509 2510 <tr><td>
2510 2511 <a href="/help/import">
2511 2512 import
2512 2513 </a>
2513 2514 </td><td>
2514 2515 import an ordered set of patches
2515 2516 </td></tr>
2516 2517 <tr><td>
2517 2518 <a href="/help/incoming">
2518 2519 incoming
2519 2520 </a>
2520 2521 </td><td>
2521 2522 show new changesets found in source
2522 2523 </td></tr>
2523 2524 <tr><td>
2524 2525 <a href="/help/manifest">
2525 2526 manifest
2526 2527 </a>
2527 2528 </td><td>
2528 2529 output the current or given revision of the project manifest
2529 2530 </td></tr>
2530 2531 <tr><td>
2531 2532 <a href="/help/nohelp">
2532 2533 nohelp
2533 2534 </a>
2534 2535 </td><td>
2535 2536 (no help text available)
2536 2537 </td></tr>
2537 2538 <tr><td>
2538 2539 <a href="/help/outgoing">
2539 2540 outgoing
2540 2541 </a>
2541 2542 </td><td>
2542 2543 show changesets not found in the destination
2543 2544 </td></tr>
2544 2545 <tr><td>
2545 2546 <a href="/help/paths">
2546 2547 paths
2547 2548 </a>
2548 2549 </td><td>
2549 2550 show aliases for remote repositories
2550 2551 </td></tr>
2551 2552 <tr><td>
2552 2553 <a href="/help/phase">
2553 2554 phase
2554 2555 </a>
2555 2556 </td><td>
2556 2557 set or show the current phase name
2557 2558 </td></tr>
2558 2559 <tr><td>
2559 2560 <a href="/help/recover">
2560 2561 recover
2561 2562 </a>
2562 2563 </td><td>
2563 2564 roll back an interrupted transaction
2564 2565 </td></tr>
2565 2566 <tr><td>
2566 2567 <a href="/help/rename">
2567 2568 rename
2568 2569 </a>
2569 2570 </td><td>
2570 2571 rename files; equivalent of copy + remove
2571 2572 </td></tr>
2572 2573 <tr><td>
2573 2574 <a href="/help/resolve">
2574 2575 resolve
2575 2576 </a>
2576 2577 </td><td>
2577 2578 redo merges or set/view the merge status of files
2578 2579 </td></tr>
2579 2580 <tr><td>
2580 2581 <a href="/help/revert">
2581 2582 revert
2582 2583 </a>
2583 2584 </td><td>
2584 2585 restore files to their checkout state
2585 2586 </td></tr>
2586 2587 <tr><td>
2587 2588 <a href="/help/root">
2588 2589 root
2589 2590 </a>
2590 2591 </td><td>
2591 2592 print the root (top) of the current working directory
2592 2593 </td></tr>
2593 2594 <tr><td>
2594 2595 <a href="/help/shellalias">
2595 2596 shellalias
2596 2597 </a>
2597 2598 </td><td>
2598 2599 (no help text available)
2599 2600 </td></tr>
2600 2601 <tr><td>
2601 2602 <a href="/help/tag">
2602 2603 tag
2603 2604 </a>
2604 2605 </td><td>
2605 2606 add one or more tags for the current or given revision
2606 2607 </td></tr>
2607 2608 <tr><td>
2608 2609 <a href="/help/tags">
2609 2610 tags
2610 2611 </a>
2611 2612 </td><td>
2612 2613 list repository tags
2613 2614 </td></tr>
2614 2615 <tr><td>
2615 2616 <a href="/help/unbundle">
2616 2617 unbundle
2617 2618 </a>
2618 2619 </td><td>
2619 2620 apply one or more bundle files
2620 2621 </td></tr>
2621 2622 <tr><td>
2622 2623 <a href="/help/verify">
2623 2624 verify
2624 2625 </a>
2625 2626 </td><td>
2626 2627 verify the integrity of the repository
2627 2628 </td></tr>
2628 2629 <tr><td>
2629 2630 <a href="/help/version">
2630 2631 version
2631 2632 </a>
2632 2633 </td><td>
2633 2634 output version and copyright information
2634 2635 </td></tr>
2635 2636
2636 2637
2637 2638 </table>
2638 2639 </div>
2639 2640 </div>
2640 2641
2641 2642
2642 2643
2643 2644 </body>
2644 2645 </html>
2645 2646
2646 2647
2647 2648 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2648 2649 200 Script output follows
2649 2650
2650 2651 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2651 2652 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2652 2653 <head>
2653 2654 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2654 2655 <meta name="robots" content="index, nofollow" />
2655 2656 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2656 2657 <script type="text/javascript" src="/static/mercurial.js"></script>
2657 2658
2658 2659 <title>Help: add</title>
2659 2660 </head>
2660 2661 <body>
2661 2662
2662 2663 <div class="container">
2663 2664 <div class="menu">
2664 2665 <div class="logo">
2665 2666 <a href="https://mercurial-scm.org/">
2666 2667 <img src="/static/hglogo.png" alt="mercurial" /></a>
2667 2668 </div>
2668 2669 <ul>
2669 2670 <li><a href="/shortlog">log</a></li>
2670 2671 <li><a href="/graph">graph</a></li>
2671 2672 <li><a href="/tags">tags</a></li>
2672 2673 <li><a href="/bookmarks">bookmarks</a></li>
2673 2674 <li><a href="/branches">branches</a></li>
2674 2675 </ul>
2675 2676 <ul>
2676 2677 <li class="active"><a href="/help">help</a></li>
2677 2678 </ul>
2678 2679 </div>
2679 2680
2680 2681 <div class="main">
2681 2682 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2682 2683 <h3>Help: add</h3>
2683 2684
2684 2685 <form class="search" action="/log">
2685 2686
2686 2687 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2687 2688 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2688 2689 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2689 2690 </form>
2690 2691 <div id="doc">
2691 2692 <p>
2692 2693 hg add [OPTION]... [FILE]...
2693 2694 </p>
2694 2695 <p>
2695 2696 add the specified files on the next commit
2696 2697 </p>
2697 2698 <p>
2698 2699 Schedule files to be version controlled and added to the
2699 2700 repository.
2700 2701 </p>
2701 2702 <p>
2702 2703 The files will be added to the repository at the next commit. To
2703 2704 undo an add before that, see 'hg forget'.
2704 2705 </p>
2705 2706 <p>
2706 2707 If no names are given, add all files to the repository (except
2707 2708 files matching &quot;.hgignore&quot;).
2708 2709 </p>
2709 2710 <p>
2710 2711 Examples:
2711 2712 </p>
2712 2713 <ul>
2713 2714 <li> New (unknown) files are added automatically by 'hg add':
2714 2715 <pre>
2715 2716 \$ ls (re)
2716 2717 foo.c
2717 2718 \$ hg status (re)
2718 2719 ? foo.c
2719 2720 \$ hg add (re)
2720 2721 adding foo.c
2721 2722 \$ hg status (re)
2722 2723 A foo.c
2723 2724 </pre>
2724 2725 <li> Specific files to be added can be specified:
2725 2726 <pre>
2726 2727 \$ ls (re)
2727 2728 bar.c foo.c
2728 2729 \$ hg status (re)
2729 2730 ? bar.c
2730 2731 ? foo.c
2731 2732 \$ hg add bar.c (re)
2732 2733 \$ hg status (re)
2733 2734 A bar.c
2734 2735 ? foo.c
2735 2736 </pre>
2736 2737 </ul>
2737 2738 <p>
2738 2739 Returns 0 if all files are successfully added.
2739 2740 </p>
2740 2741 <p>
2741 2742 options ([+] can be repeated):
2742 2743 </p>
2743 2744 <table>
2744 2745 <tr><td>-I</td>
2745 2746 <td>--include PATTERN [+]</td>
2746 2747 <td>include names matching the given patterns</td></tr>
2747 2748 <tr><td>-X</td>
2748 2749 <td>--exclude PATTERN [+]</td>
2749 2750 <td>exclude names matching the given patterns</td></tr>
2750 2751 <tr><td>-S</td>
2751 2752 <td>--subrepos</td>
2752 2753 <td>recurse into subrepositories</td></tr>
2753 2754 <tr><td>-n</td>
2754 2755 <td>--dry-run</td>
2755 2756 <td>do not perform actions, just print output</td></tr>
2756 2757 </table>
2757 2758 <p>
2758 2759 global options ([+] can be repeated):
2759 2760 </p>
2760 2761 <table>
2761 2762 <tr><td>-R</td>
2762 2763 <td>--repository REPO</td>
2763 2764 <td>repository root directory or name of overlay bundle file</td></tr>
2764 2765 <tr><td></td>
2765 2766 <td>--cwd DIR</td>
2766 2767 <td>change working directory</td></tr>
2767 2768 <tr><td>-y</td>
2768 2769 <td>--noninteractive</td>
2769 2770 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2770 2771 <tr><td>-q</td>
2771 2772 <td>--quiet</td>
2772 2773 <td>suppress output</td></tr>
2773 2774 <tr><td>-v</td>
2774 2775 <td>--verbose</td>
2775 2776 <td>enable additional output</td></tr>
2776 2777 <tr><td></td>
2777 2778 <td>--color TYPE</td>
2778 2779 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2779 2780 <tr><td></td>
2780 2781 <td>--config CONFIG [+]</td>
2781 2782 <td>set/override config option (use 'section.name=value')</td></tr>
2782 2783 <tr><td></td>
2783 2784 <td>--debug</td>
2784 2785 <td>enable debugging output</td></tr>
2785 2786 <tr><td></td>
2786 2787 <td>--debugger</td>
2787 2788 <td>start debugger</td></tr>
2788 2789 <tr><td></td>
2789 2790 <td>--encoding ENCODE</td>
2790 2791 <td>set the charset encoding (default: ascii)</td></tr>
2791 2792 <tr><td></td>
2792 2793 <td>--encodingmode MODE</td>
2793 2794 <td>set the charset encoding mode (default: strict)</td></tr>
2794 2795 <tr><td></td>
2795 2796 <td>--traceback</td>
2796 2797 <td>always print a traceback on exception</td></tr>
2797 2798 <tr><td></td>
2798 2799 <td>--time</td>
2799 2800 <td>time how long the command takes</td></tr>
2800 2801 <tr><td></td>
2801 2802 <td>--profile</td>
2802 2803 <td>print command execution profile</td></tr>
2803 2804 <tr><td></td>
2804 2805 <td>--version</td>
2805 2806 <td>output version information and exit</td></tr>
2806 2807 <tr><td>-h</td>
2807 2808 <td>--help</td>
2808 2809 <td>display help and exit</td></tr>
2809 2810 <tr><td></td>
2810 2811 <td>--hidden</td>
2811 2812 <td>consider hidden changesets</td></tr>
2812 2813 <tr><td></td>
2813 2814 <td>--pager TYPE</td>
2814 2815 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2815 2816 </table>
2816 2817
2817 2818 </div>
2818 2819 </div>
2819 2820 </div>
2820 2821
2821 2822
2822 2823
2823 2824 </body>
2824 2825 </html>
2825 2826
2826 2827
2827 2828 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
2828 2829 200 Script output follows
2829 2830
2830 2831 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2831 2832 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2832 2833 <head>
2833 2834 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2834 2835 <meta name="robots" content="index, nofollow" />
2835 2836 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2836 2837 <script type="text/javascript" src="/static/mercurial.js"></script>
2837 2838
2838 2839 <title>Help: remove</title>
2839 2840 </head>
2840 2841 <body>
2841 2842
2842 2843 <div class="container">
2843 2844 <div class="menu">
2844 2845 <div class="logo">
2845 2846 <a href="https://mercurial-scm.org/">
2846 2847 <img src="/static/hglogo.png" alt="mercurial" /></a>
2847 2848 </div>
2848 2849 <ul>
2849 2850 <li><a href="/shortlog">log</a></li>
2850 2851 <li><a href="/graph">graph</a></li>
2851 2852 <li><a href="/tags">tags</a></li>
2852 2853 <li><a href="/bookmarks">bookmarks</a></li>
2853 2854 <li><a href="/branches">branches</a></li>
2854 2855 </ul>
2855 2856 <ul>
2856 2857 <li class="active"><a href="/help">help</a></li>
2857 2858 </ul>
2858 2859 </div>
2859 2860
2860 2861 <div class="main">
2861 2862 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2862 2863 <h3>Help: remove</h3>
2863 2864
2864 2865 <form class="search" action="/log">
2865 2866
2866 2867 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2867 2868 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2868 2869 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2869 2870 </form>
2870 2871 <div id="doc">
2871 2872 <p>
2872 2873 hg remove [OPTION]... FILE...
2873 2874 </p>
2874 2875 <p>
2875 2876 aliases: rm
2876 2877 </p>
2877 2878 <p>
2878 2879 remove the specified files on the next commit
2879 2880 </p>
2880 2881 <p>
2881 2882 Schedule the indicated files for removal from the current branch.
2882 2883 </p>
2883 2884 <p>
2884 2885 This command schedules the files to be removed at the next commit.
2885 2886 To undo a remove before that, see 'hg revert'. To undo added
2886 2887 files, see 'hg forget'.
2887 2888 </p>
2888 2889 <p>
2889 2890 -A/--after can be used to remove only files that have already
2890 2891 been deleted, -f/--force can be used to force deletion, and -Af
2891 2892 can be used to remove files from the next revision without
2892 2893 deleting them from the working directory.
2893 2894 </p>
2894 2895 <p>
2895 2896 The following table details the behavior of remove for different
2896 2897 file states (columns) and option combinations (rows). The file
2897 2898 states are Added [A], Clean [C], Modified [M] and Missing [!]
2898 2899 (as reported by 'hg status'). The actions are Warn, Remove
2899 2900 (from branch) and Delete (from disk):
2900 2901 </p>
2901 2902 <table>
2902 2903 <tr><td>opt/state</td>
2903 2904 <td>A</td>
2904 2905 <td>C</td>
2905 2906 <td>M</td>
2906 2907 <td>!</td></tr>
2907 2908 <tr><td>none</td>
2908 2909 <td>W</td>
2909 2910 <td>RD</td>
2910 2911 <td>W</td>
2911 2912 <td>R</td></tr>
2912 2913 <tr><td>-f</td>
2913 2914 <td>R</td>
2914 2915 <td>RD</td>
2915 2916 <td>RD</td>
2916 2917 <td>R</td></tr>
2917 2918 <tr><td>-A</td>
2918 2919 <td>W</td>
2919 2920 <td>W</td>
2920 2921 <td>W</td>
2921 2922 <td>R</td></tr>
2922 2923 <tr><td>-Af</td>
2923 2924 <td>R</td>
2924 2925 <td>R</td>
2925 2926 <td>R</td>
2926 2927 <td>R</td></tr>
2927 2928 </table>
2928 2929 <p>
2929 2930 <b>Note:</b>
2930 2931 </p>
2931 2932 <p>
2932 2933 'hg remove' never deletes files in Added [A] state from the
2933 2934 working directory, not even if &quot;--force&quot; is specified.
2934 2935 </p>
2935 2936 <p>
2936 2937 Returns 0 on success, 1 if any warnings encountered.
2937 2938 </p>
2938 2939 <p>
2939 2940 options ([+] can be repeated):
2940 2941 </p>
2941 2942 <table>
2942 2943 <tr><td>-A</td>
2943 2944 <td>--after</td>
2944 2945 <td>record delete for missing files</td></tr>
2945 2946 <tr><td>-f</td>
2946 2947 <td>--force</td>
2947 2948 <td>forget added files, delete modified files</td></tr>
2948 2949 <tr><td>-S</td>
2949 2950 <td>--subrepos</td>
2950 2951 <td>recurse into subrepositories</td></tr>
2951 2952 <tr><td>-I</td>
2952 2953 <td>--include PATTERN [+]</td>
2953 2954 <td>include names matching the given patterns</td></tr>
2954 2955 <tr><td>-X</td>
2955 2956 <td>--exclude PATTERN [+]</td>
2956 2957 <td>exclude names matching the given patterns</td></tr>
2957 2958 <tr><td>-n</td>
2958 2959 <td>--dry-run</td>
2959 2960 <td>do not perform actions, just print output</td></tr>
2960 2961 </table>
2961 2962 <p>
2962 2963 global options ([+] can be repeated):
2963 2964 </p>
2964 2965 <table>
2965 2966 <tr><td>-R</td>
2966 2967 <td>--repository REPO</td>
2967 2968 <td>repository root directory or name of overlay bundle file</td></tr>
2968 2969 <tr><td></td>
2969 2970 <td>--cwd DIR</td>
2970 2971 <td>change working directory</td></tr>
2971 2972 <tr><td>-y</td>
2972 2973 <td>--noninteractive</td>
2973 2974 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2974 2975 <tr><td>-q</td>
2975 2976 <td>--quiet</td>
2976 2977 <td>suppress output</td></tr>
2977 2978 <tr><td>-v</td>
2978 2979 <td>--verbose</td>
2979 2980 <td>enable additional output</td></tr>
2980 2981 <tr><td></td>
2981 2982 <td>--color TYPE</td>
2982 2983 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2983 2984 <tr><td></td>
2984 2985 <td>--config CONFIG [+]</td>
2985 2986 <td>set/override config option (use 'section.name=value')</td></tr>
2986 2987 <tr><td></td>
2987 2988 <td>--debug</td>
2988 2989 <td>enable debugging output</td></tr>
2989 2990 <tr><td></td>
2990 2991 <td>--debugger</td>
2991 2992 <td>start debugger</td></tr>
2992 2993 <tr><td></td>
2993 2994 <td>--encoding ENCODE</td>
2994 2995 <td>set the charset encoding (default: ascii)</td></tr>
2995 2996 <tr><td></td>
2996 2997 <td>--encodingmode MODE</td>
2997 2998 <td>set the charset encoding mode (default: strict)</td></tr>
2998 2999 <tr><td></td>
2999 3000 <td>--traceback</td>
3000 3001 <td>always print a traceback on exception</td></tr>
3001 3002 <tr><td></td>
3002 3003 <td>--time</td>
3003 3004 <td>time how long the command takes</td></tr>
3004 3005 <tr><td></td>
3005 3006 <td>--profile</td>
3006 3007 <td>print command execution profile</td></tr>
3007 3008 <tr><td></td>
3008 3009 <td>--version</td>
3009 3010 <td>output version information and exit</td></tr>
3010 3011 <tr><td>-h</td>
3011 3012 <td>--help</td>
3012 3013 <td>display help and exit</td></tr>
3013 3014 <tr><td></td>
3014 3015 <td>--hidden</td>
3015 3016 <td>consider hidden changesets</td></tr>
3016 3017 <tr><td></td>
3017 3018 <td>--pager TYPE</td>
3018 3019 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
3019 3020 </table>
3020 3021
3021 3022 </div>
3022 3023 </div>
3023 3024 </div>
3024 3025
3025 3026
3026 3027
3027 3028 </body>
3028 3029 </html>
3029 3030
3030 3031
3031 3032 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
3032 3033 200 Script output follows
3033 3034
3034 3035 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3035 3036 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3036 3037 <head>
3037 3038 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3038 3039 <meta name="robots" content="index, nofollow" />
3039 3040 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3040 3041 <script type="text/javascript" src="/static/mercurial.js"></script>
3041 3042
3042 3043 <title>Help: dates</title>
3043 3044 </head>
3044 3045 <body>
3045 3046
3046 3047 <div class="container">
3047 3048 <div class="menu">
3048 3049 <div class="logo">
3049 3050 <a href="https://mercurial-scm.org/">
3050 3051 <img src="/static/hglogo.png" alt="mercurial" /></a>
3051 3052 </div>
3052 3053 <ul>
3053 3054 <li><a href="/shortlog">log</a></li>
3054 3055 <li><a href="/graph">graph</a></li>
3055 3056 <li><a href="/tags">tags</a></li>
3056 3057 <li><a href="/bookmarks">bookmarks</a></li>
3057 3058 <li><a href="/branches">branches</a></li>
3058 3059 </ul>
3059 3060 <ul>
3060 3061 <li class="active"><a href="/help">help</a></li>
3061 3062 </ul>
3062 3063 </div>
3063 3064
3064 3065 <div class="main">
3065 3066 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3066 3067 <h3>Help: dates</h3>
3067 3068
3068 3069 <form class="search" action="/log">
3069 3070
3070 3071 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3071 3072 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3072 3073 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3073 3074 </form>
3074 3075 <div id="doc">
3075 3076 <h1>Date Formats</h1>
3076 3077 <p>
3077 3078 Some commands allow the user to specify a date, e.g.:
3078 3079 </p>
3079 3080 <ul>
3080 3081 <li> backout, commit, import, tag: Specify the commit date.
3081 3082 <li> log, revert, update: Select revision(s) by date.
3082 3083 </ul>
3083 3084 <p>
3084 3085 Many date formats are valid. Here are some examples:
3085 3086 </p>
3086 3087 <ul>
3087 3088 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
3088 3089 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
3089 3090 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
3090 3091 <li> &quot;Dec 6&quot; (midnight)
3091 3092 <li> &quot;13:18&quot; (today assumed)
3092 3093 <li> &quot;3:39&quot; (3:39AM assumed)
3093 3094 <li> &quot;3:39pm&quot; (15:39)
3094 3095 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
3095 3096 <li> &quot;2006-12-6 13:18&quot;
3096 3097 <li> &quot;2006-12-6&quot;
3097 3098 <li> &quot;12-6&quot;
3098 3099 <li> &quot;12/6&quot;
3099 3100 <li> &quot;12/6/6&quot; (Dec 6 2006)
3100 3101 <li> &quot;today&quot; (midnight)
3101 3102 <li> &quot;yesterday&quot; (midnight)
3102 3103 <li> &quot;now&quot; - right now
3103 3104 </ul>
3104 3105 <p>
3105 3106 Lastly, there is Mercurial's internal format:
3106 3107 </p>
3107 3108 <ul>
3108 3109 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
3109 3110 </ul>
3110 3111 <p>
3111 3112 This is the internal representation format for dates. The first number
3112 3113 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
3113 3114 second is the offset of the local timezone, in seconds west of UTC
3114 3115 (negative if the timezone is east of UTC).
3115 3116 </p>
3116 3117 <p>
3117 3118 The log command also accepts date ranges:
3118 3119 </p>
3119 3120 <ul>
3120 3121 <li> &quot;&lt;DATE&quot; - at or before a given date/time
3121 3122 <li> &quot;&gt;DATE&quot; - on or after a given date/time
3122 3123 <li> &quot;DATE to DATE&quot; - a date range, inclusive
3123 3124 <li> &quot;-DAYS&quot; - within a given number of days of today
3124 3125 </ul>
3125 3126
3126 3127 </div>
3127 3128 </div>
3128 3129 </div>
3129 3130
3130 3131
3131 3132
3132 3133 </body>
3133 3134 </html>
3134 3135
3135 3136
3136 3137 $ get-with-headers.py $LOCALIP:$HGPORT "help/pager"
3137 3138 200 Script output follows
3138 3139
3139 3140 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3140 3141 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3141 3142 <head>
3142 3143 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3143 3144 <meta name="robots" content="index, nofollow" />
3144 3145 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3145 3146 <script type="text/javascript" src="/static/mercurial.js"></script>
3146 3147
3147 3148 <title>Help: pager</title>
3148 3149 </head>
3149 3150 <body>
3150 3151
3151 3152 <div class="container">
3152 3153 <div class="menu">
3153 3154 <div class="logo">
3154 3155 <a href="https://mercurial-scm.org/">
3155 3156 <img src="/static/hglogo.png" alt="mercurial" /></a>
3156 3157 </div>
3157 3158 <ul>
3158 3159 <li><a href="/shortlog">log</a></li>
3159 3160 <li><a href="/graph">graph</a></li>
3160 3161 <li><a href="/tags">tags</a></li>
3161 3162 <li><a href="/bookmarks">bookmarks</a></li>
3162 3163 <li><a href="/branches">branches</a></li>
3163 3164 </ul>
3164 3165 <ul>
3165 3166 <li class="active"><a href="/help">help</a></li>
3166 3167 </ul>
3167 3168 </div>
3168 3169
3169 3170 <div class="main">
3170 3171 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3171 3172 <h3>Help: pager</h3>
3172 3173
3173 3174 <form class="search" action="/log">
3174 3175
3175 3176 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3176 3177 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3177 3178 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3178 3179 </form>
3179 3180 <div id="doc">
3180 3181 <h1>Pager Support</h1>
3181 3182 <p>
3182 3183 Some Mercurial commands can produce a lot of output, and Mercurial will
3183 3184 attempt to use a pager to make those commands more pleasant.
3184 3185 </p>
3185 3186 <p>
3186 3187 To set the pager that should be used, set the application variable:
3187 3188 </p>
3188 3189 <pre>
3189 3190 [pager]
3190 3191 pager = less -FRX
3191 3192 </pre>
3192 3193 <p>
3193 3194 If no pager is set in the user or repository configuration, Mercurial uses the
3194 3195 environment variable $PAGER. If $PAGER is not set, pager.pager from the default
3195 3196 or system configuration is used. If none of these are set, a default pager will
3196 3197 be used, typically 'less' on Unix and 'more' on Windows.
3197 3198 </p>
3198 3199 <p>
3199 3200 You can disable the pager for certain commands by adding them to the
3200 3201 pager.ignore list:
3201 3202 </p>
3202 3203 <pre>
3203 3204 [pager]
3204 3205 ignore = version, help, update
3205 3206 </pre>
3206 3207 <p>
3207 3208 To ignore global commands like 'hg version' or 'hg help', you have
3208 3209 to specify them in your user configuration file.
3209 3210 </p>
3210 3211 <p>
3211 3212 To control whether the pager is used at all for an individual command,
3212 3213 you can use --pager=&lt;value&gt;:
3213 3214 </p>
3214 3215 <ul>
3215 3216 <li> use as needed: 'auto'.
3216 3217 <li> require the pager: 'yes' or 'on'.
3217 3218 <li> suppress the pager: 'no' or 'off' (any unrecognized value will also work).
3218 3219 </ul>
3219 3220 <p>
3220 3221 To globally turn off all attempts to use a pager, set:
3221 3222 </p>
3222 3223 <pre>
3223 3224 [ui]
3224 3225 paginate = never
3225 3226 </pre>
3226 3227 <p>
3227 3228 which will prevent the pager from running.
3228 3229 </p>
3229 3230
3230 3231 </div>
3231 3232 </div>
3232 3233 </div>
3233 3234
3234 3235
3235 3236
3236 3237 </body>
3237 3238 </html>
3238 3239
3239 3240
3240 3241 Sub-topic indexes rendered properly
3241 3242
3242 3243 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3243 3244 200 Script output follows
3244 3245
3245 3246 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3246 3247 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3247 3248 <head>
3248 3249 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3249 3250 <meta name="robots" content="index, nofollow" />
3250 3251 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3251 3252 <script type="text/javascript" src="/static/mercurial.js"></script>
3252 3253
3253 3254 <title>Help: internals</title>
3254 3255 </head>
3255 3256 <body>
3256 3257
3257 3258 <div class="container">
3258 3259 <div class="menu">
3259 3260 <div class="logo">
3260 3261 <a href="https://mercurial-scm.org/">
3261 3262 <img src="/static/hglogo.png" alt="mercurial" /></a>
3262 3263 </div>
3263 3264 <ul>
3264 3265 <li><a href="/shortlog">log</a></li>
3265 3266 <li><a href="/graph">graph</a></li>
3266 3267 <li><a href="/tags">tags</a></li>
3267 3268 <li><a href="/bookmarks">bookmarks</a></li>
3268 3269 <li><a href="/branches">branches</a></li>
3269 3270 </ul>
3270 3271 <ul>
3271 3272 <li><a href="/help">help</a></li>
3272 3273 </ul>
3273 3274 </div>
3274 3275
3275 3276 <div class="main">
3276 3277 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3277 3278
3278 3279 <form class="search" action="/log">
3279 3280
3280 3281 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3281 3282 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3282 3283 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3283 3284 </form>
3284 3285 <table class="bigtable">
3285 3286 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3286 3287
3287 3288 <tr><td>
3288 3289 <a href="/help/internals.bundle2">
3289 3290 bundle2
3290 3291 </a>
3291 3292 </td><td>
3292 3293 Bundle2
3293 3294 </td></tr>
3294 3295 <tr><td>
3295 3296 <a href="/help/internals.bundles">
3296 3297 bundles
3297 3298 </a>
3298 3299 </td><td>
3299 3300 Bundles
3300 3301 </td></tr>
3301 3302 <tr><td>
3302 3303 <a href="/help/internals.cbor">
3303 3304 cbor
3304 3305 </a>
3305 3306 </td><td>
3306 3307 CBOR
3307 3308 </td></tr>
3308 3309 <tr><td>
3309 3310 <a href="/help/internals.censor">
3310 3311 censor
3311 3312 </a>
3312 3313 </td><td>
3313 3314 Censor
3314 3315 </td></tr>
3315 3316 <tr><td>
3316 3317 <a href="/help/internals.changegroups">
3317 3318 changegroups
3318 3319 </a>
3319 3320 </td><td>
3320 3321 Changegroups
3321 3322 </td></tr>
3322 3323 <tr><td>
3323 3324 <a href="/help/internals.config">
3324 3325 config
3325 3326 </a>
3326 3327 </td><td>
3327 3328 Config Registrar
3328 3329 </td></tr>
3329 3330 <tr><td>
3330 3331 <a href="/help/internals.requirements">
3331 3332 requirements
3332 3333 </a>
3333 3334 </td><td>
3334 3335 Repository Requirements
3335 3336 </td></tr>
3336 3337 <tr><td>
3337 3338 <a href="/help/internals.revlogs">
3338 3339 revlogs
3339 3340 </a>
3340 3341 </td><td>
3341 3342 Revision Logs
3342 3343 </td></tr>
3343 3344 <tr><td>
3344 3345 <a href="/help/internals.wireprotocol">
3345 3346 wireprotocol
3346 3347 </a>
3347 3348 </td><td>
3348 3349 Wire Protocol
3349 3350 </td></tr>
3350 3351 <tr><td>
3351 3352 <a href="/help/internals.wireprotocolrpc">
3352 3353 wireprotocolrpc
3353 3354 </a>
3354 3355 </td><td>
3355 3356 Wire Protocol RPC
3356 3357 </td></tr>
3357 3358 <tr><td>
3358 3359 <a href="/help/internals.wireprotocolv2">
3359 3360 wireprotocolv2
3360 3361 </a>
3361 3362 </td><td>
3362 3363 Wire Protocol Version 2
3363 3364 </td></tr>
3364 3365
3365 3366
3366 3367
3367 3368
3368 3369
3369 3370 </table>
3370 3371 </div>
3371 3372 </div>
3372 3373
3373 3374
3374 3375
3375 3376 </body>
3376 3377 </html>
3377 3378
3378 3379
3379 3380 Sub-topic topics rendered properly
3380 3381
3381 3382 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3382 3383 200 Script output follows
3383 3384
3384 3385 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3385 3386 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3386 3387 <head>
3387 3388 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3388 3389 <meta name="robots" content="index, nofollow" />
3389 3390 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3390 3391 <script type="text/javascript" src="/static/mercurial.js"></script>
3391 3392
3392 3393 <title>Help: internals.changegroups</title>
3393 3394 </head>
3394 3395 <body>
3395 3396
3396 3397 <div class="container">
3397 3398 <div class="menu">
3398 3399 <div class="logo">
3399 3400 <a href="https://mercurial-scm.org/">
3400 3401 <img src="/static/hglogo.png" alt="mercurial" /></a>
3401 3402 </div>
3402 3403 <ul>
3403 3404 <li><a href="/shortlog">log</a></li>
3404 3405 <li><a href="/graph">graph</a></li>
3405 3406 <li><a href="/tags">tags</a></li>
3406 3407 <li><a href="/bookmarks">bookmarks</a></li>
3407 3408 <li><a href="/branches">branches</a></li>
3408 3409 </ul>
3409 3410 <ul>
3410 3411 <li class="active"><a href="/help">help</a></li>
3411 3412 </ul>
3412 3413 </div>
3413 3414
3414 3415 <div class="main">
3415 3416 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3416 3417 <h3>Help: internals.changegroups</h3>
3417 3418
3418 3419 <form class="search" action="/log">
3419 3420
3420 3421 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3421 3422 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3422 3423 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3423 3424 </form>
3424 3425 <div id="doc">
3425 3426 <h1>Changegroups</h1>
3426 3427 <p>
3427 3428 Changegroups are representations of repository revlog data, specifically
3428 3429 the changelog data, root/flat manifest data, treemanifest data, and
3429 3430 filelogs.
3430 3431 </p>
3431 3432 <p>
3432 3433 There are 3 versions of changegroups: &quot;1&quot;, &quot;2&quot;, and &quot;3&quot;. From a
3433 3434 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3434 3435 only difference being an additional item in the *delta header*. Version
3435 3436 &quot;3&quot; adds support for revlog flags in the *delta header* and optionally
3436 3437 exchanging treemanifests (enabled by setting an option on the
3437 3438 &quot;changegroup&quot; part in the bundle2).
3438 3439 </p>
3439 3440 <p>
3440 3441 Changegroups when not exchanging treemanifests consist of 3 logical
3441 3442 segments:
3442 3443 </p>
3443 3444 <pre>
3444 3445 +---------------------------------+
3445 3446 | | | |
3446 3447 | changeset | manifest | filelogs |
3447 3448 | | | |
3448 3449 | | | |
3449 3450 +---------------------------------+
3450 3451 </pre>
3451 3452 <p>
3452 3453 When exchanging treemanifests, there are 4 logical segments:
3453 3454 </p>
3454 3455 <pre>
3455 3456 +-------------------------------------------------+
3456 3457 | | | | |
3457 3458 | changeset | root | treemanifests | filelogs |
3458 3459 | | manifest | | |
3459 3460 | | | | |
3460 3461 +-------------------------------------------------+
3461 3462 </pre>
3462 3463 <p>
3463 3464 The principle building block of each segment is a *chunk*. A *chunk*
3464 3465 is a framed piece of data:
3465 3466 </p>
3466 3467 <pre>
3467 3468 +---------------------------------------+
3468 3469 | | |
3469 3470 | length | data |
3470 3471 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3471 3472 | | |
3472 3473 +---------------------------------------+
3473 3474 </pre>
3474 3475 <p>
3475 3476 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3476 3477 integer indicating the length of the entire chunk (including the length field
3477 3478 itself).
3478 3479 </p>
3479 3480 <p>
3480 3481 There is a special case chunk that has a value of 0 for the length
3481 3482 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3482 3483 </p>
3483 3484 <h2>Delta Groups</h2>
3484 3485 <p>
3485 3486 A *delta group* expresses the content of a revlog as a series of deltas,
3486 3487 or patches against previous revisions.
3487 3488 </p>
3488 3489 <p>
3489 3490 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3490 3491 to signal the end of the delta group:
3491 3492 </p>
3492 3493 <pre>
3493 3494 +------------------------------------------------------------------------+
3494 3495 | | | | | |
3495 3496 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3496 3497 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3497 3498 | | | | | |
3498 3499 +------------------------------------------------------------------------+
3499 3500 </pre>
3500 3501 <p>
3501 3502 Each *chunk*'s data consists of the following:
3502 3503 </p>
3503 3504 <pre>
3504 3505 +---------------------------------------+
3505 3506 | | |
3506 3507 | delta header | delta data |
3507 3508 | (various by version) | (various) |
3508 3509 | | |
3509 3510 +---------------------------------------+
3510 3511 </pre>
3511 3512 <p>
3512 3513 The *delta data* is a series of *delta*s that describe a diff from an existing
3513 3514 entry (either that the recipient already has, or previously specified in the
3514 3515 bundle/changegroup).
3515 3516 </p>
3516 3517 <p>
3517 3518 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, and
3518 3519 &quot;3&quot; of the changegroup format.
3519 3520 </p>
3520 3521 <p>
3521 3522 Version 1 (headerlen=80):
3522 3523 </p>
3523 3524 <pre>
3524 3525 +------------------------------------------------------+
3525 3526 | | | | |
3526 3527 | node | p1 node | p2 node | link node |
3527 3528 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3528 3529 | | | | |
3529 3530 +------------------------------------------------------+
3530 3531 </pre>
3531 3532 <p>
3532 3533 Version 2 (headerlen=100):
3533 3534 </p>
3534 3535 <pre>
3535 3536 +------------------------------------------------------------------+
3536 3537 | | | | | |
3537 3538 | node | p1 node | p2 node | base node | link node |
3538 3539 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3539 3540 | | | | | |
3540 3541 +------------------------------------------------------------------+
3541 3542 </pre>
3542 3543 <p>
3543 3544 Version 3 (headerlen=102):
3544 3545 </p>
3545 3546 <pre>
3546 3547 +------------------------------------------------------------------------------+
3547 3548 | | | | | | |
3548 3549 | node | p1 node | p2 node | base node | link node | flags |
3549 3550 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3550 3551 | | | | | | |
3551 3552 +------------------------------------------------------------------------------+
3552 3553 </pre>
3553 3554 <p>
3554 3555 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3555 3556 series of *delta*s, densely packed (no separators). These deltas describe a diff
3556 3557 from an existing entry (either that the recipient already has, or previously
3557 3558 specified in the bundle/changegroup). The format is described more fully in
3558 3559 &quot;hg help internals.bdiff&quot;, but briefly:
3559 3560 </p>
3560 3561 <pre>
3561 3562 +---------------------------------------------------------------+
3562 3563 | | | | |
3563 3564 | start offset | end offset | new length | content |
3564 3565 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3565 3566 | | | | |
3566 3567 +---------------------------------------------------------------+
3567 3568 </pre>
3568 3569 <p>
3569 3570 Please note that the length field in the delta data does *not* include itself.
3570 3571 </p>
3571 3572 <p>
3572 3573 In version 1, the delta is always applied against the previous node from
3573 3574 the changegroup or the first parent if this is the first entry in the
3574 3575 changegroup.
3575 3576 </p>
3576 3577 <p>
3577 3578 In version 2 and up, the delta base node is encoded in the entry in the
3578 3579 changegroup. This allows the delta to be expressed against any parent,
3579 3580 which can result in smaller deltas and more efficient encoding of data.
3580 3581 </p>
3581 3582 <h2>Changeset Segment</h2>
3582 3583 <p>
3583 3584 The *changeset segment* consists of a single *delta group* holding
3584 3585 changelog data. The *empty chunk* at the end of the *delta group* denotes
3585 3586 the boundary to the *manifest segment*.
3586 3587 </p>
3587 3588 <h2>Manifest Segment</h2>
3588 3589 <p>
3589 3590 The *manifest segment* consists of a single *delta group* holding manifest
3590 3591 data. If treemanifests are in use, it contains only the manifest for the
3591 3592 root directory of the repository. Otherwise, it contains the entire
3592 3593 manifest data. The *empty chunk* at the end of the *delta group* denotes
3593 3594 the boundary to the next segment (either the *treemanifests segment* or the
3594 3595 *filelogs segment*, depending on version and the request options).
3595 3596 </p>
3596 3597 <h3>Treemanifests Segment</h3>
3597 3598 <p>
3598 3599 The *treemanifests segment* only exists in changegroup version &quot;3&quot;, and
3599 3600 only if the 'treemanifest' param is part of the bundle2 changegroup part
3600 3601 (it is not possible to use changegroup version 3 outside of bundle2).
3601 3602 Aside from the filenames in the *treemanifests segment* containing a
3602 3603 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3603 3604 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3604 3605 a sub-segment with filename size 0). This denotes the boundary to the
3605 3606 *filelogs segment*.
3606 3607 </p>
3607 3608 <h2>Filelogs Segment</h2>
3608 3609 <p>
3609 3610 The *filelogs segment* consists of multiple sub-segments, each
3610 3611 corresponding to an individual file whose data is being described:
3611 3612 </p>
3612 3613 <pre>
3613 3614 +--------------------------------------------------+
3614 3615 | | | | | |
3615 3616 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
3616 3617 | | | | | (4 bytes) |
3617 3618 | | | | | |
3618 3619 +--------------------------------------------------+
3619 3620 </pre>
3620 3621 <p>
3621 3622 The final filelog sub-segment is followed by an *empty chunk* (logically,
3622 3623 a sub-segment with filename size 0). This denotes the end of the segment
3623 3624 and of the overall changegroup.
3624 3625 </p>
3625 3626 <p>
3626 3627 Each filelog sub-segment consists of the following:
3627 3628 </p>
3628 3629 <pre>
3629 3630 +------------------------------------------------------+
3630 3631 | | | |
3631 3632 | filename length | filename | delta group |
3632 3633 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
3633 3634 | | | |
3634 3635 +------------------------------------------------------+
3635 3636 </pre>
3636 3637 <p>
3637 3638 That is, a *chunk* consisting of the filename (not terminated or padded)
3638 3639 followed by N chunks constituting the *delta group* for this file. The
3639 3640 *empty chunk* at the end of each *delta group* denotes the boundary to the
3640 3641 next filelog sub-segment.
3641 3642 </p>
3642 3643
3643 3644 </div>
3644 3645 </div>
3645 3646 </div>
3646 3647
3647 3648
3648 3649
3649 3650 </body>
3650 3651 </html>
3651 3652
3652 3653
3653 3654 $ get-with-headers.py 127.0.0.1:$HGPORT "help/unknowntopic"
3654 3655 404 Not Found
3655 3656
3656 3657 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3657 3658 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3658 3659 <head>
3659 3660 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3660 3661 <meta name="robots" content="index, nofollow" />
3661 3662 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3662 3663 <script type="text/javascript" src="/static/mercurial.js"></script>
3663 3664
3664 3665 <title>test: error</title>
3665 3666 </head>
3666 3667 <body>
3667 3668
3668 3669 <div class="container">
3669 3670 <div class="menu">
3670 3671 <div class="logo">
3671 3672 <a href="https://mercurial-scm.org/">
3672 3673 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
3673 3674 </div>
3674 3675 <ul>
3675 3676 <li><a href="/shortlog">log</a></li>
3676 3677 <li><a href="/graph">graph</a></li>
3677 3678 <li><a href="/tags">tags</a></li>
3678 3679 <li><a href="/bookmarks">bookmarks</a></li>
3679 3680 <li><a href="/branches">branches</a></li>
3680 3681 </ul>
3681 3682 <ul>
3682 3683 <li><a href="/help">help</a></li>
3683 3684 </ul>
3684 3685 </div>
3685 3686
3686 3687 <div class="main">
3687 3688
3688 3689 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3689 3690 <h3>error</h3>
3690 3691
3691 3692
3692 3693 <form class="search" action="/log">
3693 3694
3694 3695 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3695 3696 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3696 3697 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3697 3698 </form>
3698 3699
3699 3700 <div class="description">
3700 3701 <p>
3701 3702 An error occurred while processing your request:
3702 3703 </p>
3703 3704 <p>
3704 3705 Not Found
3705 3706 </p>
3706 3707 </div>
3707 3708 </div>
3708 3709 </div>
3709 3710
3710 3711
3711 3712
3712 3713 </body>
3713 3714 </html>
3714 3715
3715 3716 [1]
3716 3717
3717 3718 $ killdaemons.py
3718 3719
3719 3720 #endif
General Comments 0
You need to be logged in to leave comments. Login now