##// END OF EJS Templates
command: creation of obsolete marker...
Pierre-Yves.David@ens-lyon.org -
r17071:11f26e26 default
parent child Browse files
Show More
@@ -0,0 +1,49 b''
1
2 $ mkcommit() {
3 > echo "$1" > "$1"
4 > hg add "$1"
5 > hg ci -m "add $1"
6 > }
7 $ getid() {
8 > hg id --debug -ir "desc('$1')"
9 > }
10
11
12 $ hg init tmpa
13 $ cd tmpa
14
15 Killing a single changeset without replacement
16
17 $ mkcommit kill_me
18 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
19 $ cd ..
20
21 Killing a single changeset with replacement
22
23 $ hg init tmpb
24 $ cd tmpb
25 $ mkcommit a
26 $ mkcommit b
27 $ mkcommit original_c
28 $ hg up "desc('b')"
29 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
30 $ mkcommit new_c
31 created new head
32 $ hg debugobsolete `getid original_c` `getid new_c` -d '56 12'
33
34 do it again (it read the obsstore before adding new changeset)
35
36 $ hg up '.^'
37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
38 $ mkcommit new_2_c
39 created new head
40 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
41
42 Register two markers with a missing node
43
44 $ hg up '.^'
45 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
46 $ mkcommit new_3_c
47 created new head
48 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
49 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
@@ -1,5783 +1,5798 b''
1 1 # commands.py - command processing for 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 node import hex, bin, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _, gettext
11 11 import os, re, difflib, time, tempfile, errno
12 12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 13 import patch, help, url, encoding, templatekw, discovery
14 14 import archival, changegroup, cmdutil, hbisect
15 15 import sshserver, hgweb, hgweb.server, commandserver
16 16 import merge as mergemod
17 17 import minirst, revset, fileset
18 18 import dagparser, context, simplemerge
19 19 import random, setdiscovery, treediscovery, dagutil, pvec
20 20 import phases
21 21
22 22 table = {}
23 23
24 24 command = cmdutil.command(table)
25 25
26 26 # common command options
27 27
28 28 globalopts = [
29 29 ('R', 'repository', '',
30 30 _('repository root directory or name of overlay bundle file'),
31 31 _('REPO')),
32 32 ('', 'cwd', '',
33 33 _('change working directory'), _('DIR')),
34 34 ('y', 'noninteractive', None,
35 35 _('do not prompt, automatically pick the first choice for all prompts')),
36 36 ('q', 'quiet', None, _('suppress output')),
37 37 ('v', 'verbose', None, _('enable additional output')),
38 38 ('', 'config', [],
39 39 _('set/override config option (use \'section.name=value\')'),
40 40 _('CONFIG')),
41 41 ('', 'debug', None, _('enable debugging output')),
42 42 ('', 'debugger', None, _('start debugger')),
43 43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 44 _('ENCODE')),
45 45 ('', 'encodingmode', encoding.encodingmode,
46 46 _('set the charset encoding mode'), _('MODE')),
47 47 ('', 'traceback', None, _('always print a traceback on exception')),
48 48 ('', 'time', None, _('time how long the command takes')),
49 49 ('', 'profile', None, _('print command execution profile')),
50 50 ('', 'version', None, _('output version information and exit')),
51 51 ('h', 'help', None, _('display help and exit')),
52 52 ]
53 53
54 54 dryrunopts = [('n', 'dry-run', None,
55 55 _('do not perform actions, just print output'))]
56 56
57 57 remoteopts = [
58 58 ('e', 'ssh', '',
59 59 _('specify ssh command to use'), _('CMD')),
60 60 ('', 'remotecmd', '',
61 61 _('specify hg command to run on the remote side'), _('CMD')),
62 62 ('', 'insecure', None,
63 63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 64 ]
65 65
66 66 walkopts = [
67 67 ('I', 'include', [],
68 68 _('include names matching the given patterns'), _('PATTERN')),
69 69 ('X', 'exclude', [],
70 70 _('exclude names matching the given patterns'), _('PATTERN')),
71 71 ]
72 72
73 73 commitopts = [
74 74 ('m', 'message', '',
75 75 _('use text as commit message'), _('TEXT')),
76 76 ('l', 'logfile', '',
77 77 _('read commit message from file'), _('FILE')),
78 78 ]
79 79
80 80 commitopts2 = [
81 81 ('d', 'date', '',
82 82 _('record the specified date as commit date'), _('DATE')),
83 83 ('u', 'user', '',
84 84 _('record the specified user as committer'), _('USER')),
85 85 ]
86 86
87 87 templateopts = [
88 88 ('', 'style', '',
89 89 _('display using template map file'), _('STYLE')),
90 90 ('', 'template', '',
91 91 _('display with template'), _('TEMPLATE')),
92 92 ]
93 93
94 94 logopts = [
95 95 ('p', 'patch', None, _('show patch')),
96 96 ('g', 'git', None, _('use git extended diff format')),
97 97 ('l', 'limit', '',
98 98 _('limit number of changes displayed'), _('NUM')),
99 99 ('M', 'no-merges', None, _('do not show merges')),
100 100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 101 ] + templateopts
102 102
103 103 diffopts = [
104 104 ('a', 'text', None, _('treat all files as text')),
105 105 ('g', 'git', None, _('use git extended diff format')),
106 106 ('', 'nodates', None, _('omit dates from diff headers'))
107 107 ]
108 108
109 109 diffwsopts = [
110 110 ('w', 'ignore-all-space', None,
111 111 _('ignore white space when comparing lines')),
112 112 ('b', 'ignore-space-change', None,
113 113 _('ignore changes in the amount of white space')),
114 114 ('B', 'ignore-blank-lines', None,
115 115 _('ignore changes whose lines are all blank')),
116 116 ]
117 117
118 118 diffopts2 = [
119 119 ('p', 'show-function', None, _('show which function each change is in')),
120 120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 121 ] + diffwsopts + [
122 122 ('U', 'unified', '',
123 123 _('number of lines of context to show'), _('NUM')),
124 124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 125 ]
126 126
127 127 mergetoolopts = [
128 128 ('t', 'tool', '', _('specify merge tool')),
129 129 ]
130 130
131 131 similarityopts = [
132 132 ('s', 'similarity', '',
133 133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 134 ]
135 135
136 136 subrepoopts = [
137 137 ('S', 'subrepos', None,
138 138 _('recurse into subrepositories'))
139 139 ]
140 140
141 141 # Commands start here, listed alphabetically
142 142
143 143 @command('^add',
144 144 walkopts + subrepoopts + dryrunopts,
145 145 _('[OPTION]... [FILE]...'))
146 146 def add(ui, repo, *pats, **opts):
147 147 """add the specified files on the next commit
148 148
149 149 Schedule files to be version controlled and added to the
150 150 repository.
151 151
152 152 The files will be added to the repository at the next commit. To
153 153 undo an add before that, see :hg:`forget`.
154 154
155 155 If no names are given, add all files to the repository.
156 156
157 157 .. container:: verbose
158 158
159 159 An example showing how new (unknown) files are added
160 160 automatically by :hg:`add`::
161 161
162 162 $ ls
163 163 foo.c
164 164 $ hg status
165 165 ? foo.c
166 166 $ hg add
167 167 adding foo.c
168 168 $ hg status
169 169 A foo.c
170 170
171 171 Returns 0 if all files are successfully added.
172 172 """
173 173
174 174 m = scmutil.match(repo[None], pats, opts)
175 175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 176 opts.get('subrepos'), prefix="", explicitonly=False)
177 177 return rejected and 1 or 0
178 178
179 179 @command('addremove',
180 180 similarityopts + walkopts + dryrunopts,
181 181 _('[OPTION]... [FILE]...'))
182 182 def addremove(ui, repo, *pats, **opts):
183 183 """add all new files, delete all missing files
184 184
185 185 Add all new files and remove all missing files from the
186 186 repository.
187 187
188 188 New files are ignored if they match any of the patterns in
189 189 ``.hgignore``. As with add, these changes take effect at the next
190 190 commit.
191 191
192 192 Use the -s/--similarity option to detect renamed files. With a
193 193 parameter greater than 0, this compares every removed file with
194 194 every added file and records those similar enough as renames. This
195 195 option takes a percentage between 0 (disabled) and 100 (files must
196 196 be identical) as its parameter. Detecting renamed files this way
197 197 can be expensive. After using this option, :hg:`status -C` can be
198 198 used to check which files were identified as moved or renamed.
199 199 If this option is not specified, only renames of identical files
200 200 are detected.
201 201
202 202 Returns 0 if all files are successfully added.
203 203 """
204 204 try:
205 205 sim = float(opts.get('similarity') or 100)
206 206 except ValueError:
207 207 raise util.Abort(_('similarity must be a number'))
208 208 if sim < 0 or sim > 100:
209 209 raise util.Abort(_('similarity must be between 0 and 100'))
210 210 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 211
212 212 @command('^annotate|blame',
213 213 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 214 ('', 'follow', None,
215 215 _('follow copies/renames and list the filename (DEPRECATED)')),
216 216 ('', 'no-follow', None, _("don't follow copies and renames")),
217 217 ('a', 'text', None, _('treat all files as text')),
218 218 ('u', 'user', None, _('list the author (long with -v)')),
219 219 ('f', 'file', None, _('list the filename')),
220 220 ('d', 'date', None, _('list the date (short with -q)')),
221 221 ('n', 'number', None, _('list the revision number (default)')),
222 222 ('c', 'changeset', None, _('list the changeset')),
223 223 ('l', 'line-number', None, _('show line number at the first appearance'))
224 224 ] + diffwsopts + walkopts,
225 225 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 226 def annotate(ui, repo, *pats, **opts):
227 227 """show changeset information by line for each file
228 228
229 229 List changes in files, showing the revision id responsible for
230 230 each line
231 231
232 232 This command is useful for discovering when a change was made and
233 233 by whom.
234 234
235 235 Without the -a/--text option, annotate will avoid processing files
236 236 it detects as binary. With -a, annotate will annotate the file
237 237 anyway, although the results will probably be neither useful
238 238 nor desirable.
239 239
240 240 Returns 0 on success.
241 241 """
242 242 if opts.get('follow'):
243 243 # --follow is deprecated and now just an alias for -f/--file
244 244 # to mimic the behavior of Mercurial before version 1.5
245 245 opts['file'] = True
246 246
247 247 datefunc = ui.quiet and util.shortdate or util.datestr
248 248 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 249
250 250 if not pats:
251 251 raise util.Abort(_('at least one filename or pattern is required'))
252 252
253 253 hexfn = ui.debugflag and hex or short
254 254
255 255 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 256 ('number', ' ', lambda x: str(x[0].rev())),
257 257 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 258 ('date', ' ', getdate),
259 259 ('file', ' ', lambda x: x[0].path()),
260 260 ('line_number', ':', lambda x: str(x[1])),
261 261 ]
262 262
263 263 if (not opts.get('user') and not opts.get('changeset')
264 264 and not opts.get('date') and not opts.get('file')):
265 265 opts['number'] = True
266 266
267 267 linenumber = opts.get('line_number') is not None
268 268 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 269 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 270
271 271 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 272 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 273
274 274 def bad(x, y):
275 275 raise util.Abort("%s: %s" % (x, y))
276 276
277 277 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 278 m = scmutil.match(ctx, pats, opts)
279 279 m.bad = bad
280 280 follow = not opts.get('no_follow')
281 281 diffopts = patch.diffopts(ui, opts, section='annotate')
282 282 for abs in ctx.walk(m):
283 283 fctx = ctx[abs]
284 284 if not opts.get('text') and util.binary(fctx.data()):
285 285 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 286 continue
287 287
288 288 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 289 diffopts=diffopts)
290 290 pieces = []
291 291
292 292 for f, sep in funcmap:
293 293 l = [f(n) for n, dummy in lines]
294 294 if l:
295 295 sized = [(x, encoding.colwidth(x)) for x in l]
296 296 ml = max([w for x, w in sized])
297 297 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 298 for x, w in sized])
299 299
300 300 if pieces:
301 301 for p, l in zip(zip(*pieces), lines):
302 302 ui.write("%s: %s" % ("".join(p), l[1]))
303 303
304 304 if lines and not lines[-1][1].endswith('\n'):
305 305 ui.write('\n')
306 306
307 307 @command('archive',
308 308 [('', 'no-decode', None, _('do not pass files through decoders')),
309 309 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 310 _('PREFIX')),
311 311 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 312 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 313 ] + subrepoopts + walkopts,
314 314 _('[OPTION]... DEST'))
315 315 def archive(ui, repo, dest, **opts):
316 316 '''create an unversioned archive of a repository revision
317 317
318 318 By default, the revision used is the parent of the working
319 319 directory; use -r/--rev to specify a different revision.
320 320
321 321 The archive type is automatically detected based on file
322 322 extension (or override using -t/--type).
323 323
324 324 .. container:: verbose
325 325
326 326 Examples:
327 327
328 328 - create a zip file containing the 1.0 release::
329 329
330 330 hg archive -r 1.0 project-1.0.zip
331 331
332 332 - create a tarball excluding .hg files::
333 333
334 334 hg archive project.tar.gz -X ".hg*"
335 335
336 336 Valid types are:
337 337
338 338 :``files``: a directory full of files (default)
339 339 :``tar``: tar archive, uncompressed
340 340 :``tbz2``: tar archive, compressed using bzip2
341 341 :``tgz``: tar archive, compressed using gzip
342 342 :``uzip``: zip archive, uncompressed
343 343 :``zip``: zip archive, compressed using deflate
344 344
345 345 The exact name of the destination archive or directory is given
346 346 using a format string; see :hg:`help export` for details.
347 347
348 348 Each member added to an archive file has a directory prefix
349 349 prepended. Use -p/--prefix to specify a format string for the
350 350 prefix. The default is the basename of the archive, with suffixes
351 351 removed.
352 352
353 353 Returns 0 on success.
354 354 '''
355 355
356 356 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 357 if not ctx:
358 358 raise util.Abort(_('no working directory: please specify a revision'))
359 359 node = ctx.node()
360 360 dest = cmdutil.makefilename(repo, dest, node)
361 361 if os.path.realpath(dest) == repo.root:
362 362 raise util.Abort(_('repository root cannot be destination'))
363 363
364 364 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 365 prefix = opts.get('prefix')
366 366
367 367 if dest == '-':
368 368 if kind == 'files':
369 369 raise util.Abort(_('cannot archive plain files to stdout'))
370 370 dest = cmdutil.makefileobj(repo, dest)
371 371 if not prefix:
372 372 prefix = os.path.basename(repo.root) + '-%h'
373 373
374 374 prefix = cmdutil.makefilename(repo, prefix, node)
375 375 matchfn = scmutil.match(ctx, [], opts)
376 376 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 377 matchfn, prefix, subrepos=opts.get('subrepos'))
378 378
379 379 @command('backout',
380 380 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 381 ('', 'parent', '',
382 382 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 383 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 384 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 385 _('[OPTION]... [-r] REV'))
386 386 def backout(ui, repo, node=None, rev=None, **opts):
387 387 '''reverse effect of earlier changeset
388 388
389 389 Prepare a new changeset with the effect of REV undone in the
390 390 current working directory.
391 391
392 392 If REV is the parent of the working directory, then this new changeset
393 393 is committed automatically. Otherwise, hg needs to merge the
394 394 changes and the merged result is left uncommitted.
395 395
396 396 .. note::
397 397 backout cannot be used to fix either an unwanted or
398 398 incorrect merge.
399 399
400 400 .. container:: verbose
401 401
402 402 By default, the pending changeset will have one parent,
403 403 maintaining a linear history. With --merge, the pending
404 404 changeset will instead have two parents: the old parent of the
405 405 working directory and a new child of REV that simply undoes REV.
406 406
407 407 Before version 1.7, the behavior without --merge was equivalent
408 408 to specifying --merge followed by :hg:`update --clean .` to
409 409 cancel the merge and leave the child of REV as a head to be
410 410 merged separately.
411 411
412 412 See :hg:`help dates` for a list of formats valid for -d/--date.
413 413
414 414 Returns 0 on success.
415 415 '''
416 416 if rev and node:
417 417 raise util.Abort(_("please specify just one revision"))
418 418
419 419 if not rev:
420 420 rev = node
421 421
422 422 if not rev:
423 423 raise util.Abort(_("please specify a revision to backout"))
424 424
425 425 date = opts.get('date')
426 426 if date:
427 427 opts['date'] = util.parsedate(date)
428 428
429 429 cmdutil.bailifchanged(repo)
430 430 node = scmutil.revsingle(repo, rev).node()
431 431
432 432 op1, op2 = repo.dirstate.parents()
433 433 a = repo.changelog.ancestor(op1, node)
434 434 if a != node:
435 435 raise util.Abort(_('cannot backout change on a different branch'))
436 436
437 437 p1, p2 = repo.changelog.parents(node)
438 438 if p1 == nullid:
439 439 raise util.Abort(_('cannot backout a change with no parents'))
440 440 if p2 != nullid:
441 441 if not opts.get('parent'):
442 442 raise util.Abort(_('cannot backout a merge changeset'))
443 443 p = repo.lookup(opts['parent'])
444 444 if p not in (p1, p2):
445 445 raise util.Abort(_('%s is not a parent of %s') %
446 446 (short(p), short(node)))
447 447 parent = p
448 448 else:
449 449 if opts.get('parent'):
450 450 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 451 parent = p1
452 452
453 453 # the backout should appear on the same branch
454 454 wlock = repo.wlock()
455 455 try:
456 456 branch = repo.dirstate.branch()
457 457 hg.clean(repo, node, show_stats=False)
458 458 repo.dirstate.setbranch(branch)
459 459 revert_opts = opts.copy()
460 460 revert_opts['date'] = None
461 461 revert_opts['all'] = True
462 462 revert_opts['rev'] = hex(parent)
463 463 revert_opts['no_backup'] = None
464 464 revert(ui, repo, **revert_opts)
465 465 if not opts.get('merge') and op1 != node:
466 466 try:
467 467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 468 return hg.update(repo, op1)
469 469 finally:
470 470 ui.setconfig('ui', 'forcemerge', '')
471 471
472 472 commit_opts = opts.copy()
473 473 commit_opts['addremove'] = False
474 474 if not commit_opts['message'] and not commit_opts['logfile']:
475 475 # we don't translate commit messages
476 476 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 477 commit_opts['force_editor'] = True
478 478 commit(ui, repo, **commit_opts)
479 479 def nice(node):
480 480 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 481 ui.status(_('changeset %s backs out changeset %s\n') %
482 482 (nice(repo.changelog.tip()), nice(node)))
483 483 if opts.get('merge') and op1 != node:
484 484 hg.clean(repo, op1, show_stats=False)
485 485 ui.status(_('merging with changeset %s\n')
486 486 % nice(repo.changelog.tip()))
487 487 try:
488 488 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 489 return hg.merge(repo, hex(repo.changelog.tip()))
490 490 finally:
491 491 ui.setconfig('ui', 'forcemerge', '')
492 492 finally:
493 493 wlock.release()
494 494 return 0
495 495
496 496 @command('bisect',
497 497 [('r', 'reset', False, _('reset bisect state')),
498 498 ('g', 'good', False, _('mark changeset good')),
499 499 ('b', 'bad', False, _('mark changeset bad')),
500 500 ('s', 'skip', False, _('skip testing changeset')),
501 501 ('e', 'extend', False, _('extend the bisect range')),
502 502 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 503 ('U', 'noupdate', False, _('do not update to target'))],
504 504 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 505 def bisect(ui, repo, rev=None, extra=None, command=None,
506 506 reset=None, good=None, bad=None, skip=None, extend=None,
507 507 noupdate=None):
508 508 """subdivision search of changesets
509 509
510 510 This command helps to find changesets which introduce problems. To
511 511 use, mark the earliest changeset you know exhibits the problem as
512 512 bad, then mark the latest changeset which is free from the problem
513 513 as good. Bisect will update your working directory to a revision
514 514 for testing (unless the -U/--noupdate option is specified). Once
515 515 you have performed tests, mark the working directory as good or
516 516 bad, and bisect will either update to another candidate changeset
517 517 or announce that it has found the bad revision.
518 518
519 519 As a shortcut, you can also use the revision argument to mark a
520 520 revision as good or bad without checking it out first.
521 521
522 522 If you supply a command, it will be used for automatic bisection.
523 523 The environment variable HG_NODE will contain the ID of the
524 524 changeset being tested. The exit status of the command will be
525 525 used to mark revisions as good or bad: status 0 means good, 125
526 526 means to skip the revision, 127 (command not found) will abort the
527 527 bisection, and any other non-zero exit status means the revision
528 528 is bad.
529 529
530 530 .. container:: verbose
531 531
532 532 Some examples:
533 533
534 534 - start a bisection with known bad revision 12, and good revision 34::
535 535
536 536 hg bisect --bad 34
537 537 hg bisect --good 12
538 538
539 539 - advance the current bisection by marking current revision as good or
540 540 bad::
541 541
542 542 hg bisect --good
543 543 hg bisect --bad
544 544
545 545 - mark the current revision, or a known revision, to be skipped (eg. if
546 546 that revision is not usable because of another issue)::
547 547
548 548 hg bisect --skip
549 549 hg bisect --skip 23
550 550
551 551 - forget the current bisection::
552 552
553 553 hg bisect --reset
554 554
555 555 - use 'make && make tests' to automatically find the first broken
556 556 revision::
557 557
558 558 hg bisect --reset
559 559 hg bisect --bad 34
560 560 hg bisect --good 12
561 561 hg bisect --command 'make && make tests'
562 562
563 563 - see all changesets whose states are already known in the current
564 564 bisection::
565 565
566 566 hg log -r "bisect(pruned)"
567 567
568 568 - see the changeset currently being bisected (especially useful
569 569 if running with -U/--noupdate)::
570 570
571 571 hg log -r "bisect(current)"
572 572
573 573 - see all changesets that took part in the current bisection::
574 574
575 575 hg log -r "bisect(range)"
576 576
577 577 - with the graphlog extension, you can even get a nice graph::
578 578
579 579 hg log --graph -r "bisect(range)"
580 580
581 581 See :hg:`help revsets` for more about the `bisect()` keyword.
582 582
583 583 Returns 0 on success.
584 584 """
585 585 def extendbisectrange(nodes, good):
586 586 # bisect is incomplete when it ends on a merge node and
587 587 # one of the parent was not checked.
588 588 parents = repo[nodes[0]].parents()
589 589 if len(parents) > 1:
590 590 side = good and state['bad'] or state['good']
591 591 num = len(set(i.node() for i in parents) & set(side))
592 592 if num == 1:
593 593 return parents[0].ancestor(parents[1])
594 594 return None
595 595
596 596 def print_result(nodes, good):
597 597 displayer = cmdutil.show_changeset(ui, repo, {})
598 598 if len(nodes) == 1:
599 599 # narrowed it down to a single revision
600 600 if good:
601 601 ui.write(_("The first good revision is:\n"))
602 602 else:
603 603 ui.write(_("The first bad revision is:\n"))
604 604 displayer.show(repo[nodes[0]])
605 605 extendnode = extendbisectrange(nodes, good)
606 606 if extendnode is not None:
607 607 ui.write(_('Not all ancestors of this changeset have been'
608 608 ' checked.\nUse bisect --extend to continue the '
609 609 'bisection from\nthe common ancestor, %s.\n')
610 610 % extendnode)
611 611 else:
612 612 # multiple possible revisions
613 613 if good:
614 614 ui.write(_("Due to skipped revisions, the first "
615 615 "good revision could be any of:\n"))
616 616 else:
617 617 ui.write(_("Due to skipped revisions, the first "
618 618 "bad revision could be any of:\n"))
619 619 for n in nodes:
620 620 displayer.show(repo[n])
621 621 displayer.close()
622 622
623 623 def check_state(state, interactive=True):
624 624 if not state['good'] or not state['bad']:
625 625 if (good or bad or skip or reset) and interactive:
626 626 return
627 627 if not state['good']:
628 628 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 629 else:
630 630 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 631 return True
632 632
633 633 # backward compatibility
634 634 if rev in "good bad reset init".split():
635 635 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 636 cmd, rev, extra = rev, extra, None
637 637 if cmd == "good":
638 638 good = True
639 639 elif cmd == "bad":
640 640 bad = True
641 641 else:
642 642 reset = True
643 643 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 644 raise util.Abort(_('incompatible arguments'))
645 645
646 646 if reset:
647 647 p = repo.join("bisect.state")
648 648 if os.path.exists(p):
649 649 os.unlink(p)
650 650 return
651 651
652 652 state = hbisect.load_state(repo)
653 653
654 654 if command:
655 655 changesets = 1
656 656 try:
657 657 node = state['current'][0]
658 658 except LookupError:
659 659 if noupdate:
660 660 raise util.Abort(_('current bisect revision is unknown - '
661 661 'start a new bisect to fix'))
662 662 node, p2 = repo.dirstate.parents()
663 663 if p2 != nullid:
664 664 raise util.Abort(_('current bisect revision is a merge'))
665 665 try:
666 666 while changesets:
667 667 # update state
668 668 state['current'] = [node]
669 669 hbisect.save_state(repo, state)
670 670 status = util.system(command,
671 671 environ={'HG_NODE': hex(node)},
672 672 out=ui.fout)
673 673 if status == 125:
674 674 transition = "skip"
675 675 elif status == 0:
676 676 transition = "good"
677 677 # status < 0 means process was killed
678 678 elif status == 127:
679 679 raise util.Abort(_("failed to execute %s") % command)
680 680 elif status < 0:
681 681 raise util.Abort(_("%s killed") % command)
682 682 else:
683 683 transition = "bad"
684 684 ctx = scmutil.revsingle(repo, rev, node)
685 685 rev = None # clear for future iterations
686 686 state[transition].append(ctx.node())
687 687 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 688 check_state(state, interactive=False)
689 689 # bisect
690 690 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 691 # update to next check
692 692 node = nodes[0]
693 693 if not noupdate:
694 694 cmdutil.bailifchanged(repo)
695 695 hg.clean(repo, node, show_stats=False)
696 696 finally:
697 697 state['current'] = [node]
698 698 hbisect.save_state(repo, state)
699 699 print_result(nodes, good)
700 700 return
701 701
702 702 # update state
703 703
704 704 if rev:
705 705 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 706 else:
707 707 nodes = [repo.lookup('.')]
708 708
709 709 if good or bad or skip:
710 710 if good:
711 711 state['good'] += nodes
712 712 elif bad:
713 713 state['bad'] += nodes
714 714 elif skip:
715 715 state['skip'] += nodes
716 716 hbisect.save_state(repo, state)
717 717
718 718 if not check_state(state):
719 719 return
720 720
721 721 # actually bisect
722 722 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 723 if extend:
724 724 if not changesets:
725 725 extendnode = extendbisectrange(nodes, good)
726 726 if extendnode is not None:
727 727 ui.write(_("Extending search to changeset %d:%s\n"
728 728 % (extendnode.rev(), extendnode)))
729 729 state['current'] = [extendnode.node()]
730 730 hbisect.save_state(repo, state)
731 731 if noupdate:
732 732 return
733 733 cmdutil.bailifchanged(repo)
734 734 return hg.clean(repo, extendnode.node())
735 735 raise util.Abort(_("nothing to extend"))
736 736
737 737 if changesets == 0:
738 738 print_result(nodes, good)
739 739 else:
740 740 assert len(nodes) == 1 # only a single node can be tested next
741 741 node = nodes[0]
742 742 # compute the approximate number of remaining tests
743 743 tests, size = 0, 2
744 744 while size <= changesets:
745 745 tests, size = tests + 1, size * 2
746 746 rev = repo.changelog.rev(node)
747 747 ui.write(_("Testing changeset %d:%s "
748 748 "(%d changesets remaining, ~%d tests)\n")
749 749 % (rev, short(node), changesets, tests))
750 750 state['current'] = [node]
751 751 hbisect.save_state(repo, state)
752 752 if not noupdate:
753 753 cmdutil.bailifchanged(repo)
754 754 return hg.clean(repo, node)
755 755
756 756 @command('bookmarks',
757 757 [('f', 'force', False, _('force')),
758 758 ('r', 'rev', '', _('revision'), _('REV')),
759 759 ('d', 'delete', False, _('delete a given bookmark')),
760 760 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 761 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 762 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 763 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 764 rename=None, inactive=False):
765 765 '''track a line of development with movable markers
766 766
767 767 Bookmarks are pointers to certain commits that move when committing.
768 768 Bookmarks are local. They can be renamed, copied and deleted. It is
769 769 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 770 :hg:`update NAME` to update to a given bookmark.
771 771
772 772 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 773 directory's parent revision with the given name. If you specify
774 774 a revision using -r REV (where REV may be an existing bookmark),
775 775 the bookmark is assigned to that revision.
776 776
777 777 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 778 push` and :hg:`help pull`). This requires both the local and remote
779 779 repositories to support bookmarks. For versions prior to 1.8, this means
780 780 the bookmarks extension must be enabled.
781 781
782 782 With -i/--inactive, the new bookmark will not be made the active
783 783 bookmark. If -r/--rev is given, the new bookmark will not be made
784 784 active even if -i/--inactive is not given. If no NAME is given, the
785 785 current active bookmark will be marked inactive.
786 786 '''
787 787 hexfn = ui.debugflag and hex or short
788 788 marks = repo._bookmarks
789 789 cur = repo.changectx('.').node()
790 790
791 791 if delete:
792 792 if mark is None:
793 793 raise util.Abort(_("bookmark name required"))
794 794 if mark not in marks:
795 795 raise util.Abort(_("bookmark '%s' does not exist") % mark)
796 796 if mark == repo._bookmarkcurrent:
797 797 bookmarks.setcurrent(repo, None)
798 798 del marks[mark]
799 799 bookmarks.write(repo)
800 800 return
801 801
802 802 if rename:
803 803 if rename not in marks:
804 804 raise util.Abort(_("bookmark '%s' does not exist") % rename)
805 805 if mark in marks and not force:
806 806 raise util.Abort(_("bookmark '%s' already exists "
807 807 "(use -f to force)") % mark)
808 808 if mark is None:
809 809 raise util.Abort(_("new bookmark name required"))
810 810 marks[mark] = marks[rename]
811 811 if repo._bookmarkcurrent == rename and not inactive:
812 812 bookmarks.setcurrent(repo, mark)
813 813 del marks[rename]
814 814 bookmarks.write(repo)
815 815 return
816 816
817 817 if mark is not None:
818 818 if "\n" in mark:
819 819 raise util.Abort(_("bookmark name cannot contain newlines"))
820 820 mark = mark.strip()
821 821 if not mark:
822 822 raise util.Abort(_("bookmark names cannot consist entirely of "
823 823 "whitespace"))
824 824 if inactive and mark == repo._bookmarkcurrent:
825 825 bookmarks.setcurrent(repo, None)
826 826 return
827 827 if mark in marks and not force:
828 828 raise util.Abort(_("bookmark '%s' already exists "
829 829 "(use -f to force)") % mark)
830 830 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
831 831 and not force):
832 832 raise util.Abort(
833 833 _("a bookmark cannot have the name of an existing branch"))
834 834 if rev:
835 835 marks[mark] = repo.lookup(rev)
836 836 else:
837 837 marks[mark] = cur
838 838 if not inactive and cur == marks[mark]:
839 839 bookmarks.setcurrent(repo, mark)
840 840 bookmarks.write(repo)
841 841 return
842 842
843 843 if mark is None:
844 844 if rev:
845 845 raise util.Abort(_("bookmark name required"))
846 846 if len(marks) == 0:
847 847 ui.status(_("no bookmarks set\n"))
848 848 else:
849 849 for bmark, n in sorted(marks.iteritems()):
850 850 current = repo._bookmarkcurrent
851 851 if bmark == current and n == cur:
852 852 prefix, label = '*', 'bookmarks.current'
853 853 else:
854 854 prefix, label = ' ', ''
855 855
856 856 if ui.quiet:
857 857 ui.write("%s\n" % bmark, label=label)
858 858 else:
859 859 ui.write(" %s %-25s %d:%s\n" % (
860 860 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
861 861 label=label)
862 862 return
863 863
864 864 @command('branch',
865 865 [('f', 'force', None,
866 866 _('set branch name even if it shadows an existing branch')),
867 867 ('C', 'clean', None, _('reset branch name to parent branch name'))],
868 868 _('[-fC] [NAME]'))
869 869 def branch(ui, repo, label=None, **opts):
870 870 """set or show the current branch name
871 871
872 872 .. note::
873 873 Branch names are permanent and global. Use :hg:`bookmark` to create a
874 874 light-weight bookmark instead. See :hg:`help glossary` for more
875 875 information about named branches and bookmarks.
876 876
877 877 With no argument, show the current branch name. With one argument,
878 878 set the working directory branch name (the branch will not exist
879 879 in the repository until the next commit). Standard practice
880 880 recommends that primary development take place on the 'default'
881 881 branch.
882 882
883 883 Unless -f/--force is specified, branch will not let you set a
884 884 branch name that already exists, even if it's inactive.
885 885
886 886 Use -C/--clean to reset the working directory branch to that of
887 887 the parent of the working directory, negating a previous branch
888 888 change.
889 889
890 890 Use the command :hg:`update` to switch to an existing branch. Use
891 891 :hg:`commit --close-branch` to mark this branch as closed.
892 892
893 893 Returns 0 on success.
894 894 """
895 895 if not opts.get('clean') and not label:
896 896 ui.write("%s\n" % repo.dirstate.branch())
897 897 return
898 898
899 899 wlock = repo.wlock()
900 900 try:
901 901 if opts.get('clean'):
902 902 label = repo[None].p1().branch()
903 903 repo.dirstate.setbranch(label)
904 904 ui.status(_('reset working directory to branch %s\n') % label)
905 905 elif label:
906 906 if not opts.get('force') and label in repo.branchmap():
907 907 if label not in [p.branch() for p in repo.parents()]:
908 908 raise util.Abort(_('a branch of the same name already'
909 909 ' exists'),
910 910 # i18n: "it" refers to an existing branch
911 911 hint=_("use 'hg update' to switch to it"))
912 912 repo.dirstate.setbranch(label)
913 913 ui.status(_('marked working directory as branch %s\n') % label)
914 914 ui.status(_('(branches are permanent and global, '
915 915 'did you want a bookmark?)\n'))
916 916 finally:
917 917 wlock.release()
918 918
919 919 @command('branches',
920 920 [('a', 'active', False, _('show only branches that have unmerged heads')),
921 921 ('c', 'closed', False, _('show normal and closed branches'))],
922 922 _('[-ac]'))
923 923 def branches(ui, repo, active=False, closed=False):
924 924 """list repository named branches
925 925
926 926 List the repository's named branches, indicating which ones are
927 927 inactive. If -c/--closed is specified, also list branches which have
928 928 been marked closed (see :hg:`commit --close-branch`).
929 929
930 930 If -a/--active is specified, only show active branches. A branch
931 931 is considered active if it contains repository heads.
932 932
933 933 Use the command :hg:`update` to switch to an existing branch.
934 934
935 935 Returns 0.
936 936 """
937 937
938 938 hexfunc = ui.debugflag and hex or short
939 939
940 940 activebranches = set([repo[n].branch() for n in repo.heads()])
941 941 branches = []
942 942 for tag, heads in repo.branchmap().iteritems():
943 943 for h in reversed(heads):
944 944 ctx = repo[h]
945 945 isopen = not ctx.closesbranch()
946 946 if isopen:
947 947 tip = ctx
948 948 break
949 949 else:
950 950 tip = repo[heads[-1]]
951 951 isactive = tag in activebranches and isopen
952 952 branches.append((tip, isactive, isopen))
953 953 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
954 954 reverse=True)
955 955
956 956 for ctx, isactive, isopen in branches:
957 957 if (not active) or isactive:
958 958 if isactive:
959 959 label = 'branches.active'
960 960 notice = ''
961 961 elif not isopen:
962 962 if not closed:
963 963 continue
964 964 label = 'branches.closed'
965 965 notice = _(' (closed)')
966 966 else:
967 967 label = 'branches.inactive'
968 968 notice = _(' (inactive)')
969 969 if ctx.branch() == repo.dirstate.branch():
970 970 label = 'branches.current'
971 971 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
972 972 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
973 973 'log.changeset')
974 974 tag = ui.label(ctx.branch(), label)
975 975 if ui.quiet:
976 976 ui.write("%s\n" % tag)
977 977 else:
978 978 ui.write("%s %s%s\n" % (tag, rev, notice))
979 979
980 980 @command('bundle',
981 981 [('f', 'force', None, _('run even when the destination is unrelated')),
982 982 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
983 983 _('REV')),
984 984 ('b', 'branch', [], _('a specific branch you would like to bundle'),
985 985 _('BRANCH')),
986 986 ('', 'base', [],
987 987 _('a base changeset assumed to be available at the destination'),
988 988 _('REV')),
989 989 ('a', 'all', None, _('bundle all changesets in the repository')),
990 990 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
991 991 ] + remoteopts,
992 992 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
993 993 def bundle(ui, repo, fname, dest=None, **opts):
994 994 """create a changegroup file
995 995
996 996 Generate a compressed changegroup file collecting changesets not
997 997 known to be in another repository.
998 998
999 999 If you omit the destination repository, then hg assumes the
1000 1000 destination will have all the nodes you specify with --base
1001 1001 parameters. To create a bundle containing all changesets, use
1002 1002 -a/--all (or --base null).
1003 1003
1004 1004 You can change compression method with the -t/--type option.
1005 1005 The available compression methods are: none, bzip2, and
1006 1006 gzip (by default, bundles are compressed using bzip2).
1007 1007
1008 1008 The bundle file can then be transferred using conventional means
1009 1009 and applied to another repository with the unbundle or pull
1010 1010 command. This is useful when direct push and pull are not
1011 1011 available or when exporting an entire repository is undesirable.
1012 1012
1013 1013 Applying bundles preserves all changeset contents including
1014 1014 permissions, copy/rename information, and revision history.
1015 1015
1016 1016 Returns 0 on success, 1 if no changes found.
1017 1017 """
1018 1018 revs = None
1019 1019 if 'rev' in opts:
1020 1020 revs = scmutil.revrange(repo, opts['rev'])
1021 1021
1022 1022 bundletype = opts.get('type', 'bzip2').lower()
1023 1023 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1024 1024 bundletype = btypes.get(bundletype)
1025 1025 if bundletype not in changegroup.bundletypes:
1026 1026 raise util.Abort(_('unknown bundle type specified with --type'))
1027 1027
1028 1028 if opts.get('all'):
1029 1029 base = ['null']
1030 1030 else:
1031 1031 base = scmutil.revrange(repo, opts.get('base'))
1032 1032 if base:
1033 1033 if dest:
1034 1034 raise util.Abort(_("--base is incompatible with specifying "
1035 1035 "a destination"))
1036 1036 common = [repo.lookup(rev) for rev in base]
1037 1037 heads = revs and map(repo.lookup, revs) or revs
1038 1038 cg = repo.getbundle('bundle', heads=heads, common=common)
1039 1039 outgoing = None
1040 1040 else:
1041 1041 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1042 1042 dest, branches = hg.parseurl(dest, opts.get('branch'))
1043 1043 other = hg.peer(repo, opts, dest)
1044 1044 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1045 1045 heads = revs and map(repo.lookup, revs) or revs
1046 1046 outgoing = discovery.findcommonoutgoing(repo, other,
1047 1047 onlyheads=heads,
1048 1048 force=opts.get('force'),
1049 1049 portable=True)
1050 1050 cg = repo.getlocalbundle('bundle', outgoing)
1051 1051 if not cg:
1052 1052 scmutil.nochangesfound(ui, outgoing and outgoing.excluded)
1053 1053 return 1
1054 1054
1055 1055 changegroup.writebundle(cg, fname, bundletype)
1056 1056
1057 1057 @command('cat',
1058 1058 [('o', 'output', '',
1059 1059 _('print output to file with formatted name'), _('FORMAT')),
1060 1060 ('r', 'rev', '', _('print the given revision'), _('REV')),
1061 1061 ('', 'decode', None, _('apply any matching decode filter')),
1062 1062 ] + walkopts,
1063 1063 _('[OPTION]... FILE...'))
1064 1064 def cat(ui, repo, file1, *pats, **opts):
1065 1065 """output the current or given revision of files
1066 1066
1067 1067 Print the specified files as they were at the given revision. If
1068 1068 no revision is given, the parent of the working directory is used,
1069 1069 or tip if no revision is checked out.
1070 1070
1071 1071 Output may be to a file, in which case the name of the file is
1072 1072 given using a format string. The formatting rules are the same as
1073 1073 for the export command, with the following additions:
1074 1074
1075 1075 :``%s``: basename of file being printed
1076 1076 :``%d``: dirname of file being printed, or '.' if in repository root
1077 1077 :``%p``: root-relative path name of file being printed
1078 1078
1079 1079 Returns 0 on success.
1080 1080 """
1081 1081 ctx = scmutil.revsingle(repo, opts.get('rev'))
1082 1082 err = 1
1083 1083 m = scmutil.match(ctx, (file1,) + pats, opts)
1084 1084 for abs in ctx.walk(m):
1085 1085 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1086 1086 pathname=abs)
1087 1087 data = ctx[abs].data()
1088 1088 if opts.get('decode'):
1089 1089 data = repo.wwritedata(abs, data)
1090 1090 fp.write(data)
1091 1091 fp.close()
1092 1092 err = 0
1093 1093 return err
1094 1094
1095 1095 @command('^clone',
1096 1096 [('U', 'noupdate', None,
1097 1097 _('the clone will include an empty working copy (only a repository)')),
1098 1098 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1099 1099 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1100 1100 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1101 1101 ('', 'pull', None, _('use pull protocol to copy metadata')),
1102 1102 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1103 1103 ] + remoteopts,
1104 1104 _('[OPTION]... SOURCE [DEST]'))
1105 1105 def clone(ui, source, dest=None, **opts):
1106 1106 """make a copy of an existing repository
1107 1107
1108 1108 Create a copy of an existing repository in a new directory.
1109 1109
1110 1110 If no destination directory name is specified, it defaults to the
1111 1111 basename of the source.
1112 1112
1113 1113 The location of the source is added to the new repository's
1114 1114 ``.hg/hgrc`` file, as the default to be used for future pulls.
1115 1115
1116 1116 Only local paths and ``ssh://`` URLs are supported as
1117 1117 destinations. For ``ssh://`` destinations, no working directory or
1118 1118 ``.hg/hgrc`` will be created on the remote side.
1119 1119
1120 1120 To pull only a subset of changesets, specify one or more revisions
1121 1121 identifiers with -r/--rev or branches with -b/--branch. The
1122 1122 resulting clone will contain only the specified changesets and
1123 1123 their ancestors. These options (or 'clone src#rev dest') imply
1124 1124 --pull, even for local source repositories. Note that specifying a
1125 1125 tag will include the tagged changeset but not the changeset
1126 1126 containing the tag.
1127 1127
1128 1128 To check out a particular version, use -u/--update, or
1129 1129 -U/--noupdate to create a clone with no working directory.
1130 1130
1131 1131 .. container:: verbose
1132 1132
1133 1133 For efficiency, hardlinks are used for cloning whenever the
1134 1134 source and destination are on the same filesystem (note this
1135 1135 applies only to the repository data, not to the working
1136 1136 directory). Some filesystems, such as AFS, implement hardlinking
1137 1137 incorrectly, but do not report errors. In these cases, use the
1138 1138 --pull option to avoid hardlinking.
1139 1139
1140 1140 In some cases, you can clone repositories and the working
1141 1141 directory using full hardlinks with ::
1142 1142
1143 1143 $ cp -al REPO REPOCLONE
1144 1144
1145 1145 This is the fastest way to clone, but it is not always safe. The
1146 1146 operation is not atomic (making sure REPO is not modified during
1147 1147 the operation is up to you) and you have to make sure your
1148 1148 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1149 1149 so). Also, this is not compatible with certain extensions that
1150 1150 place their metadata under the .hg directory, such as mq.
1151 1151
1152 1152 Mercurial will update the working directory to the first applicable
1153 1153 revision from this list:
1154 1154
1155 1155 a) null if -U or the source repository has no changesets
1156 1156 b) if -u . and the source repository is local, the first parent of
1157 1157 the source repository's working directory
1158 1158 c) the changeset specified with -u (if a branch name, this means the
1159 1159 latest head of that branch)
1160 1160 d) the changeset specified with -r
1161 1161 e) the tipmost head specified with -b
1162 1162 f) the tipmost head specified with the url#branch source syntax
1163 1163 g) the tipmost head of the default branch
1164 1164 h) tip
1165 1165
1166 1166 Examples:
1167 1167
1168 1168 - clone a remote repository to a new directory named hg/::
1169 1169
1170 1170 hg clone http://selenic.com/hg
1171 1171
1172 1172 - create a lightweight local clone::
1173 1173
1174 1174 hg clone project/ project-feature/
1175 1175
1176 1176 - clone from an absolute path on an ssh server (note double-slash)::
1177 1177
1178 1178 hg clone ssh://user@server//home/projects/alpha/
1179 1179
1180 1180 - do a high-speed clone over a LAN while checking out a
1181 1181 specified version::
1182 1182
1183 1183 hg clone --uncompressed http://server/repo -u 1.5
1184 1184
1185 1185 - create a repository without changesets after a particular revision::
1186 1186
1187 1187 hg clone -r 04e544 experimental/ good/
1188 1188
1189 1189 - clone (and track) a particular named branch::
1190 1190
1191 1191 hg clone http://selenic.com/hg#stable
1192 1192
1193 1193 See :hg:`help urls` for details on specifying URLs.
1194 1194
1195 1195 Returns 0 on success.
1196 1196 """
1197 1197 if opts.get('noupdate') and opts.get('updaterev'):
1198 1198 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1199 1199
1200 1200 r = hg.clone(ui, opts, source, dest,
1201 1201 pull=opts.get('pull'),
1202 1202 stream=opts.get('uncompressed'),
1203 1203 rev=opts.get('rev'),
1204 1204 update=opts.get('updaterev') or not opts.get('noupdate'),
1205 1205 branch=opts.get('branch'))
1206 1206
1207 1207 return r is None
1208 1208
1209 1209 @command('^commit|ci',
1210 1210 [('A', 'addremove', None,
1211 1211 _('mark new/missing files as added/removed before committing')),
1212 1212 ('', 'close-branch', None,
1213 1213 _('mark a branch as closed, hiding it from the branch list')),
1214 1214 ('', 'amend', None, _('amend the parent of the working dir')),
1215 1215 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1216 1216 _('[OPTION]... [FILE]...'))
1217 1217 def commit(ui, repo, *pats, **opts):
1218 1218 """commit the specified files or all outstanding changes
1219 1219
1220 1220 Commit changes to the given files into the repository. Unlike a
1221 1221 centralized SCM, this operation is a local operation. See
1222 1222 :hg:`push` for a way to actively distribute your changes.
1223 1223
1224 1224 If a list of files is omitted, all changes reported by :hg:`status`
1225 1225 will be committed.
1226 1226
1227 1227 If you are committing the result of a merge, do not provide any
1228 1228 filenames or -I/-X filters.
1229 1229
1230 1230 If no commit message is specified, Mercurial starts your
1231 1231 configured editor where you can enter a message. In case your
1232 1232 commit fails, you will find a backup of your message in
1233 1233 ``.hg/last-message.txt``.
1234 1234
1235 1235 The --amend flag can be used to amend the parent of the
1236 1236 working directory with a new commit that contains the changes
1237 1237 in the parent in addition to those currently reported by :hg:`status`,
1238 1238 if there are any. The old commit is stored in a backup bundle in
1239 1239 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1240 1240 on how to restore it).
1241 1241
1242 1242 Message, user and date are taken from the amended commit unless
1243 1243 specified. When a message isn't specified on the command line,
1244 1244 the editor will open with the message of the amended commit.
1245 1245
1246 1246 It is not possible to amend public changesets (see :hg:`help phases`)
1247 1247 or changesets that have children.
1248 1248
1249 1249 See :hg:`help dates` for a list of formats valid for -d/--date.
1250 1250
1251 1251 Returns 0 on success, 1 if nothing changed.
1252 1252 """
1253 1253 if opts.get('subrepos'):
1254 1254 # Let --subrepos on the command line overide config setting.
1255 1255 ui.setconfig('ui', 'commitsubrepos', True)
1256 1256
1257 1257 extra = {}
1258 1258 if opts.get('close_branch'):
1259 1259 if repo['.'].node() not in repo.branchheads():
1260 1260 # The topo heads set is included in the branch heads set of the
1261 1261 # current branch, so it's sufficient to test branchheads
1262 1262 raise util.Abort(_('can only close branch heads'))
1263 1263 extra['close'] = 1
1264 1264
1265 1265 branch = repo[None].branch()
1266 1266 bheads = repo.branchheads(branch)
1267 1267
1268 1268 if opts.get('amend'):
1269 1269 if ui.configbool('ui', 'commitsubrepos'):
1270 1270 raise util.Abort(_('cannot amend recursively'))
1271 1271
1272 1272 old = repo['.']
1273 1273 if old.phase() == phases.public:
1274 1274 raise util.Abort(_('cannot amend public changesets'))
1275 1275 if len(old.parents()) > 1:
1276 1276 raise util.Abort(_('cannot amend merge changesets'))
1277 1277 if len(repo[None].parents()) > 1:
1278 1278 raise util.Abort(_('cannot amend while merging'))
1279 1279 if old.children():
1280 1280 raise util.Abort(_('cannot amend changeset with children'))
1281 1281
1282 1282 e = cmdutil.commiteditor
1283 1283 if opts.get('force_editor'):
1284 1284 e = cmdutil.commitforceeditor
1285 1285
1286 1286 def commitfunc(ui, repo, message, match, opts):
1287 1287 editor = e
1288 1288 # message contains text from -m or -l, if it's empty,
1289 1289 # open the editor with the old message
1290 1290 if not message:
1291 1291 message = old.description()
1292 1292 editor = cmdutil.commitforceeditor
1293 1293 return repo.commit(message,
1294 1294 opts.get('user') or old.user(),
1295 1295 opts.get('date') or old.date(),
1296 1296 match,
1297 1297 editor=editor,
1298 1298 extra=extra)
1299 1299
1300 1300 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1301 1301 if node == old.node():
1302 1302 ui.status(_("nothing changed\n"))
1303 1303 return 1
1304 1304 else:
1305 1305 e = cmdutil.commiteditor
1306 1306 if opts.get('force_editor'):
1307 1307 e = cmdutil.commitforceeditor
1308 1308
1309 1309 def commitfunc(ui, repo, message, match, opts):
1310 1310 return repo.commit(message, opts.get('user'), opts.get('date'),
1311 1311 match, editor=e, extra=extra)
1312 1312
1313 1313 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1314 1314
1315 1315 if not node:
1316 1316 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1317 1317 if stat[3]:
1318 1318 ui.status(_("nothing changed (%d missing files, see "
1319 1319 "'hg status')\n") % len(stat[3]))
1320 1320 else:
1321 1321 ui.status(_("nothing changed\n"))
1322 1322 return 1
1323 1323
1324 1324 ctx = repo[node]
1325 1325 parents = ctx.parents()
1326 1326
1327 1327 if (not opts.get('amend') and bheads and node not in bheads and not
1328 1328 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1329 1329 ui.status(_('created new head\n'))
1330 1330 # The message is not printed for initial roots. For the other
1331 1331 # changesets, it is printed in the following situations:
1332 1332 #
1333 1333 # Par column: for the 2 parents with ...
1334 1334 # N: null or no parent
1335 1335 # B: parent is on another named branch
1336 1336 # C: parent is a regular non head changeset
1337 1337 # H: parent was a branch head of the current branch
1338 1338 # Msg column: whether we print "created new head" message
1339 1339 # In the following, it is assumed that there already exists some
1340 1340 # initial branch heads of the current branch, otherwise nothing is
1341 1341 # printed anyway.
1342 1342 #
1343 1343 # Par Msg Comment
1344 1344 # NN y additional topo root
1345 1345 #
1346 1346 # BN y additional branch root
1347 1347 # CN y additional topo head
1348 1348 # HN n usual case
1349 1349 #
1350 1350 # BB y weird additional branch root
1351 1351 # CB y branch merge
1352 1352 # HB n merge with named branch
1353 1353 #
1354 1354 # CC y additional head from merge
1355 1355 # CH n merge with a head
1356 1356 #
1357 1357 # HH n head merge: head count decreases
1358 1358
1359 1359 if not opts.get('close_branch'):
1360 1360 for r in parents:
1361 1361 if r.closesbranch() and r.branch() == branch:
1362 1362 ui.status(_('reopening closed branch head %d\n') % r)
1363 1363
1364 1364 if ui.debugflag:
1365 1365 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1366 1366 elif ui.verbose:
1367 1367 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1368 1368
1369 1369 @command('copy|cp',
1370 1370 [('A', 'after', None, _('record a copy that has already occurred')),
1371 1371 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1372 1372 ] + walkopts + dryrunopts,
1373 1373 _('[OPTION]... [SOURCE]... DEST'))
1374 1374 def copy(ui, repo, *pats, **opts):
1375 1375 """mark files as copied for the next commit
1376 1376
1377 1377 Mark dest as having copies of source files. If dest is a
1378 1378 directory, copies are put in that directory. If dest is a file,
1379 1379 the source must be a single file.
1380 1380
1381 1381 By default, this command copies the contents of files as they
1382 1382 exist in the working directory. If invoked with -A/--after, the
1383 1383 operation is recorded, but no copying is performed.
1384 1384
1385 1385 This command takes effect with the next commit. To undo a copy
1386 1386 before that, see :hg:`revert`.
1387 1387
1388 1388 Returns 0 on success, 1 if errors are encountered.
1389 1389 """
1390 1390 wlock = repo.wlock(False)
1391 1391 try:
1392 1392 return cmdutil.copy(ui, repo, pats, opts)
1393 1393 finally:
1394 1394 wlock.release()
1395 1395
1396 1396 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1397 1397 def debugancestor(ui, repo, *args):
1398 1398 """find the ancestor revision of two revisions in a given index"""
1399 1399 if len(args) == 3:
1400 1400 index, rev1, rev2 = args
1401 1401 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1402 1402 lookup = r.lookup
1403 1403 elif len(args) == 2:
1404 1404 if not repo:
1405 1405 raise util.Abort(_("there is no Mercurial repository here "
1406 1406 "(.hg not found)"))
1407 1407 rev1, rev2 = args
1408 1408 r = repo.changelog
1409 1409 lookup = repo.lookup
1410 1410 else:
1411 1411 raise util.Abort(_('either two or three arguments required'))
1412 1412 a = r.ancestor(lookup(rev1), lookup(rev2))
1413 1413 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1414 1414
1415 1415 @command('debugbuilddag',
1416 1416 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1417 1417 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1418 1418 ('n', 'new-file', None, _('add new file at each rev'))],
1419 1419 _('[OPTION]... [TEXT]'))
1420 1420 def debugbuilddag(ui, repo, text=None,
1421 1421 mergeable_file=False,
1422 1422 overwritten_file=False,
1423 1423 new_file=False):
1424 1424 """builds a repo with a given DAG from scratch in the current empty repo
1425 1425
1426 1426 The description of the DAG is read from stdin if not given on the
1427 1427 command line.
1428 1428
1429 1429 Elements:
1430 1430
1431 1431 - "+n" is a linear run of n nodes based on the current default parent
1432 1432 - "." is a single node based on the current default parent
1433 1433 - "$" resets the default parent to null (implied at the start);
1434 1434 otherwise the default parent is always the last node created
1435 1435 - "<p" sets the default parent to the backref p
1436 1436 - "*p" is a fork at parent p, which is a backref
1437 1437 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1438 1438 - "/p2" is a merge of the preceding node and p2
1439 1439 - ":tag" defines a local tag for the preceding node
1440 1440 - "@branch" sets the named branch for subsequent nodes
1441 1441 - "#...\\n" is a comment up to the end of the line
1442 1442
1443 1443 Whitespace between the above elements is ignored.
1444 1444
1445 1445 A backref is either
1446 1446
1447 1447 - a number n, which references the node curr-n, where curr is the current
1448 1448 node, or
1449 1449 - the name of a local tag you placed earlier using ":tag", or
1450 1450 - empty to denote the default parent.
1451 1451
1452 1452 All string valued-elements are either strictly alphanumeric, or must
1453 1453 be enclosed in double quotes ("..."), with "\\" as escape character.
1454 1454 """
1455 1455
1456 1456 if text is None:
1457 1457 ui.status(_("reading DAG from stdin\n"))
1458 1458 text = ui.fin.read()
1459 1459
1460 1460 cl = repo.changelog
1461 1461 if len(cl) > 0:
1462 1462 raise util.Abort(_('repository is not empty'))
1463 1463
1464 1464 # determine number of revs in DAG
1465 1465 total = 0
1466 1466 for type, data in dagparser.parsedag(text):
1467 1467 if type == 'n':
1468 1468 total += 1
1469 1469
1470 1470 if mergeable_file:
1471 1471 linesperrev = 2
1472 1472 # make a file with k lines per rev
1473 1473 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1474 1474 initialmergedlines.append("")
1475 1475
1476 1476 tags = []
1477 1477
1478 1478 lock = tr = None
1479 1479 try:
1480 1480 lock = repo.lock()
1481 1481 tr = repo.transaction("builddag")
1482 1482
1483 1483 at = -1
1484 1484 atbranch = 'default'
1485 1485 nodeids = []
1486 1486 id = 0
1487 1487 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1488 1488 for type, data in dagparser.parsedag(text):
1489 1489 if type == 'n':
1490 1490 ui.note('node %s\n' % str(data))
1491 1491 id, ps = data
1492 1492
1493 1493 files = []
1494 1494 fctxs = {}
1495 1495
1496 1496 p2 = None
1497 1497 if mergeable_file:
1498 1498 fn = "mf"
1499 1499 p1 = repo[ps[0]]
1500 1500 if len(ps) > 1:
1501 1501 p2 = repo[ps[1]]
1502 1502 pa = p1.ancestor(p2)
1503 1503 base, local, other = [x[fn].data() for x in pa, p1, p2]
1504 1504 m3 = simplemerge.Merge3Text(base, local, other)
1505 1505 ml = [l.strip() for l in m3.merge_lines()]
1506 1506 ml.append("")
1507 1507 elif at > 0:
1508 1508 ml = p1[fn].data().split("\n")
1509 1509 else:
1510 1510 ml = initialmergedlines
1511 1511 ml[id * linesperrev] += " r%i" % id
1512 1512 mergedtext = "\n".join(ml)
1513 1513 files.append(fn)
1514 1514 fctxs[fn] = context.memfilectx(fn, mergedtext)
1515 1515
1516 1516 if overwritten_file:
1517 1517 fn = "of"
1518 1518 files.append(fn)
1519 1519 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1520 1520
1521 1521 if new_file:
1522 1522 fn = "nf%i" % id
1523 1523 files.append(fn)
1524 1524 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1525 1525 if len(ps) > 1:
1526 1526 if not p2:
1527 1527 p2 = repo[ps[1]]
1528 1528 for fn in p2:
1529 1529 if fn.startswith("nf"):
1530 1530 files.append(fn)
1531 1531 fctxs[fn] = p2[fn]
1532 1532
1533 1533 def fctxfn(repo, cx, path):
1534 1534 return fctxs.get(path)
1535 1535
1536 1536 if len(ps) == 0 or ps[0] < 0:
1537 1537 pars = [None, None]
1538 1538 elif len(ps) == 1:
1539 1539 pars = [nodeids[ps[0]], None]
1540 1540 else:
1541 1541 pars = [nodeids[p] for p in ps]
1542 1542 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1543 1543 date=(id, 0),
1544 1544 user="debugbuilddag",
1545 1545 extra={'branch': atbranch})
1546 1546 nodeid = repo.commitctx(cx)
1547 1547 nodeids.append(nodeid)
1548 1548 at = id
1549 1549 elif type == 'l':
1550 1550 id, name = data
1551 1551 ui.note('tag %s\n' % name)
1552 1552 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1553 1553 elif type == 'a':
1554 1554 ui.note('branch %s\n' % data)
1555 1555 atbranch = data
1556 1556 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1557 1557 tr.close()
1558 1558
1559 1559 if tags:
1560 1560 repo.opener.write("localtags", "".join(tags))
1561 1561 finally:
1562 1562 ui.progress(_('building'), None)
1563 1563 release(tr, lock)
1564 1564
1565 1565 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1566 1566 def debugbundle(ui, bundlepath, all=None, **opts):
1567 1567 """lists the contents of a bundle"""
1568 1568 f = url.open(ui, bundlepath)
1569 1569 try:
1570 1570 gen = changegroup.readbundle(f, bundlepath)
1571 1571 if all:
1572 1572 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1573 1573
1574 1574 def showchunks(named):
1575 1575 ui.write("\n%s\n" % named)
1576 1576 chain = None
1577 1577 while True:
1578 1578 chunkdata = gen.deltachunk(chain)
1579 1579 if not chunkdata:
1580 1580 break
1581 1581 node = chunkdata['node']
1582 1582 p1 = chunkdata['p1']
1583 1583 p2 = chunkdata['p2']
1584 1584 cs = chunkdata['cs']
1585 1585 deltabase = chunkdata['deltabase']
1586 1586 delta = chunkdata['delta']
1587 1587 ui.write("%s %s %s %s %s %s\n" %
1588 1588 (hex(node), hex(p1), hex(p2),
1589 1589 hex(cs), hex(deltabase), len(delta)))
1590 1590 chain = node
1591 1591
1592 1592 chunkdata = gen.changelogheader()
1593 1593 showchunks("changelog")
1594 1594 chunkdata = gen.manifestheader()
1595 1595 showchunks("manifest")
1596 1596 while True:
1597 1597 chunkdata = gen.filelogheader()
1598 1598 if not chunkdata:
1599 1599 break
1600 1600 fname = chunkdata['filename']
1601 1601 showchunks(fname)
1602 1602 else:
1603 1603 chunkdata = gen.changelogheader()
1604 1604 chain = None
1605 1605 while True:
1606 1606 chunkdata = gen.deltachunk(chain)
1607 1607 if not chunkdata:
1608 1608 break
1609 1609 node = chunkdata['node']
1610 1610 ui.write("%s\n" % hex(node))
1611 1611 chain = node
1612 1612 finally:
1613 1613 f.close()
1614 1614
1615 1615 @command('debugcheckstate', [], '')
1616 1616 def debugcheckstate(ui, repo):
1617 1617 """validate the correctness of the current dirstate"""
1618 1618 parent1, parent2 = repo.dirstate.parents()
1619 1619 m1 = repo[parent1].manifest()
1620 1620 m2 = repo[parent2].manifest()
1621 1621 errors = 0
1622 1622 for f in repo.dirstate:
1623 1623 state = repo.dirstate[f]
1624 1624 if state in "nr" and f not in m1:
1625 1625 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1626 1626 errors += 1
1627 1627 if state in "a" and f in m1:
1628 1628 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1629 1629 errors += 1
1630 1630 if state in "m" and f not in m1 and f not in m2:
1631 1631 ui.warn(_("%s in state %s, but not in either manifest\n") %
1632 1632 (f, state))
1633 1633 errors += 1
1634 1634 for f in m1:
1635 1635 state = repo.dirstate[f]
1636 1636 if state not in "nrm":
1637 1637 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1638 1638 errors += 1
1639 1639 if errors:
1640 1640 error = _(".hg/dirstate inconsistent with current parent's manifest")
1641 1641 raise util.Abort(error)
1642 1642
1643 1643 @command('debugcommands', [], _('[COMMAND]'))
1644 1644 def debugcommands(ui, cmd='', *args):
1645 1645 """list all available commands and options"""
1646 1646 for cmd, vals in sorted(table.iteritems()):
1647 1647 cmd = cmd.split('|')[0].strip('^')
1648 1648 opts = ', '.join([i[1] for i in vals[1]])
1649 1649 ui.write('%s: %s\n' % (cmd, opts))
1650 1650
1651 1651 @command('debugcomplete',
1652 1652 [('o', 'options', None, _('show the command options'))],
1653 1653 _('[-o] CMD'))
1654 1654 def debugcomplete(ui, cmd='', **opts):
1655 1655 """returns the completion list associated with the given command"""
1656 1656
1657 1657 if opts.get('options'):
1658 1658 options = []
1659 1659 otables = [globalopts]
1660 1660 if cmd:
1661 1661 aliases, entry = cmdutil.findcmd(cmd, table, False)
1662 1662 otables.append(entry[1])
1663 1663 for t in otables:
1664 1664 for o in t:
1665 1665 if "(DEPRECATED)" in o[3]:
1666 1666 continue
1667 1667 if o[0]:
1668 1668 options.append('-%s' % o[0])
1669 1669 options.append('--%s' % o[1])
1670 1670 ui.write("%s\n" % "\n".join(options))
1671 1671 return
1672 1672
1673 1673 cmdlist = cmdutil.findpossible(cmd, table)
1674 1674 if ui.verbose:
1675 1675 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1676 1676 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1677 1677
1678 1678 @command('debugdag',
1679 1679 [('t', 'tags', None, _('use tags as labels')),
1680 1680 ('b', 'branches', None, _('annotate with branch names')),
1681 1681 ('', 'dots', None, _('use dots for runs')),
1682 1682 ('s', 'spaces', None, _('separate elements by spaces'))],
1683 1683 _('[OPTION]... [FILE [REV]...]'))
1684 1684 def debugdag(ui, repo, file_=None, *revs, **opts):
1685 1685 """format the changelog or an index DAG as a concise textual description
1686 1686
1687 1687 If you pass a revlog index, the revlog's DAG is emitted. If you list
1688 1688 revision numbers, they get labelled in the output as rN.
1689 1689
1690 1690 Otherwise, the changelog DAG of the current repo is emitted.
1691 1691 """
1692 1692 spaces = opts.get('spaces')
1693 1693 dots = opts.get('dots')
1694 1694 if file_:
1695 1695 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1696 1696 revs = set((int(r) for r in revs))
1697 1697 def events():
1698 1698 for r in rlog:
1699 1699 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1700 1700 if p != -1)))
1701 1701 if r in revs:
1702 1702 yield 'l', (r, "r%i" % r)
1703 1703 elif repo:
1704 1704 cl = repo.changelog
1705 1705 tags = opts.get('tags')
1706 1706 branches = opts.get('branches')
1707 1707 if tags:
1708 1708 labels = {}
1709 1709 for l, n in repo.tags().items():
1710 1710 labels.setdefault(cl.rev(n), []).append(l)
1711 1711 def events():
1712 1712 b = "default"
1713 1713 for r in cl:
1714 1714 if branches:
1715 1715 newb = cl.read(cl.node(r))[5]['branch']
1716 1716 if newb != b:
1717 1717 yield 'a', newb
1718 1718 b = newb
1719 1719 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1720 1720 if p != -1)))
1721 1721 if tags:
1722 1722 ls = labels.get(r)
1723 1723 if ls:
1724 1724 for l in ls:
1725 1725 yield 'l', (r, l)
1726 1726 else:
1727 1727 raise util.Abort(_('need repo for changelog dag'))
1728 1728
1729 1729 for line in dagparser.dagtextlines(events(),
1730 1730 addspaces=spaces,
1731 1731 wraplabels=True,
1732 1732 wrapannotations=True,
1733 1733 wrapnonlinear=dots,
1734 1734 usedots=dots,
1735 1735 maxlinewidth=70):
1736 1736 ui.write(line)
1737 1737 ui.write("\n")
1738 1738
1739 1739 @command('debugdata',
1740 1740 [('c', 'changelog', False, _('open changelog')),
1741 1741 ('m', 'manifest', False, _('open manifest'))],
1742 1742 _('-c|-m|FILE REV'))
1743 1743 def debugdata(ui, repo, file_, rev = None, **opts):
1744 1744 """dump the contents of a data file revision"""
1745 1745 if opts.get('changelog') or opts.get('manifest'):
1746 1746 file_, rev = None, file_
1747 1747 elif rev is None:
1748 1748 raise error.CommandError('debugdata', _('invalid arguments'))
1749 1749 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1750 1750 try:
1751 1751 ui.write(r.revision(r.lookup(rev)))
1752 1752 except KeyError:
1753 1753 raise util.Abort(_('invalid revision identifier %s') % rev)
1754 1754
1755 1755 @command('debugdate',
1756 1756 [('e', 'extended', None, _('try extended date formats'))],
1757 1757 _('[-e] DATE [RANGE]'))
1758 1758 def debugdate(ui, date, range=None, **opts):
1759 1759 """parse and display a date"""
1760 1760 if opts["extended"]:
1761 1761 d = util.parsedate(date, util.extendeddateformats)
1762 1762 else:
1763 1763 d = util.parsedate(date)
1764 1764 ui.write("internal: %s %s\n" % d)
1765 1765 ui.write("standard: %s\n" % util.datestr(d))
1766 1766 if range:
1767 1767 m = util.matchdate(range)
1768 1768 ui.write("match: %s\n" % m(d[0]))
1769 1769
1770 1770 @command('debugdiscovery',
1771 1771 [('', 'old', None, _('use old-style discovery')),
1772 1772 ('', 'nonheads', None,
1773 1773 _('use old-style discovery with non-heads included')),
1774 1774 ] + remoteopts,
1775 1775 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1776 1776 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1777 1777 """runs the changeset discovery protocol in isolation"""
1778 1778 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1779 1779 opts.get('branch'))
1780 1780 remote = hg.peer(repo, opts, remoteurl)
1781 1781 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1782 1782
1783 1783 # make sure tests are repeatable
1784 1784 random.seed(12323)
1785 1785
1786 1786 def doit(localheads, remoteheads):
1787 1787 if opts.get('old'):
1788 1788 if localheads:
1789 1789 raise util.Abort('cannot use localheads with old style '
1790 1790 'discovery')
1791 1791 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1792 1792 force=True)
1793 1793 common = set(common)
1794 1794 if not opts.get('nonheads'):
1795 1795 ui.write("unpruned common: %s\n" % " ".join([short(n)
1796 1796 for n in common]))
1797 1797 dag = dagutil.revlogdag(repo.changelog)
1798 1798 all = dag.ancestorset(dag.internalizeall(common))
1799 1799 common = dag.externalizeall(dag.headsetofconnecteds(all))
1800 1800 else:
1801 1801 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1802 1802 common = set(common)
1803 1803 rheads = set(hds)
1804 1804 lheads = set(repo.heads())
1805 1805 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1806 1806 if lheads <= common:
1807 1807 ui.write("local is subset\n")
1808 1808 elif rheads <= common:
1809 1809 ui.write("remote is subset\n")
1810 1810
1811 1811 serverlogs = opts.get('serverlog')
1812 1812 if serverlogs:
1813 1813 for filename in serverlogs:
1814 1814 logfile = open(filename, 'r')
1815 1815 try:
1816 1816 line = logfile.readline()
1817 1817 while line:
1818 1818 parts = line.strip().split(';')
1819 1819 op = parts[1]
1820 1820 if op == 'cg':
1821 1821 pass
1822 1822 elif op == 'cgss':
1823 1823 doit(parts[2].split(' '), parts[3].split(' '))
1824 1824 elif op == 'unb':
1825 1825 doit(parts[3].split(' '), parts[2].split(' '))
1826 1826 line = logfile.readline()
1827 1827 finally:
1828 1828 logfile.close()
1829 1829
1830 1830 else:
1831 1831 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1832 1832 opts.get('remote_head'))
1833 1833 localrevs = opts.get('local_head')
1834 1834 doit(localrevs, remoterevs)
1835 1835
1836 1836 @command('debugfileset', [], ('REVSPEC'))
1837 1837 def debugfileset(ui, repo, expr):
1838 1838 '''parse and apply a fileset specification'''
1839 1839 if ui.verbose:
1840 1840 tree = fileset.parse(expr)[0]
1841 1841 ui.note(tree, "\n")
1842 1842
1843 1843 for f in fileset.getfileset(repo[None], expr):
1844 1844 ui.write("%s\n" % f)
1845 1845
1846 1846 @command('debugfsinfo', [], _('[PATH]'))
1847 1847 def debugfsinfo(ui, path = "."):
1848 1848 """show information detected about current filesystem"""
1849 1849 util.writefile('.debugfsinfo', '')
1850 1850 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1851 1851 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1852 1852 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1853 1853 and 'yes' or 'no'))
1854 1854 os.unlink('.debugfsinfo')
1855 1855
1856 1856 @command('debuggetbundle',
1857 1857 [('H', 'head', [], _('id of head node'), _('ID')),
1858 1858 ('C', 'common', [], _('id of common node'), _('ID')),
1859 1859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1860 1860 _('REPO FILE [-H|-C ID]...'))
1861 1861 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1862 1862 """retrieves a bundle from a repo
1863 1863
1864 1864 Every ID must be a full-length hex node id string. Saves the bundle to the
1865 1865 given file.
1866 1866 """
1867 1867 repo = hg.peer(ui, opts, repopath)
1868 1868 if not repo.capable('getbundle'):
1869 1869 raise util.Abort("getbundle() not supported by target repository")
1870 1870 args = {}
1871 1871 if common:
1872 1872 args['common'] = [bin(s) for s in common]
1873 1873 if head:
1874 1874 args['heads'] = [bin(s) for s in head]
1875 1875 bundle = repo.getbundle('debug', **args)
1876 1876
1877 1877 bundletype = opts.get('type', 'bzip2').lower()
1878 1878 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1879 1879 bundletype = btypes.get(bundletype)
1880 1880 if bundletype not in changegroup.bundletypes:
1881 1881 raise util.Abort(_('unknown bundle type specified with --type'))
1882 1882 changegroup.writebundle(bundle, bundlepath, bundletype)
1883 1883
1884 1884 @command('debugignore', [], '')
1885 1885 def debugignore(ui, repo, *values, **opts):
1886 1886 """display the combined ignore pattern"""
1887 1887 ignore = repo.dirstate._ignore
1888 1888 includepat = getattr(ignore, 'includepat', None)
1889 1889 if includepat is not None:
1890 1890 ui.write("%s\n" % includepat)
1891 1891 else:
1892 1892 raise util.Abort(_("no ignore patterns found"))
1893 1893
1894 1894 @command('debugindex',
1895 1895 [('c', 'changelog', False, _('open changelog')),
1896 1896 ('m', 'manifest', False, _('open manifest')),
1897 1897 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1898 1898 _('[-f FORMAT] -c|-m|FILE'))
1899 1899 def debugindex(ui, repo, file_ = None, **opts):
1900 1900 """dump the contents of an index file"""
1901 1901 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1902 1902 format = opts.get('format', 0)
1903 1903 if format not in (0, 1):
1904 1904 raise util.Abort(_("unknown format %d") % format)
1905 1905
1906 1906 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1907 1907 if generaldelta:
1908 1908 basehdr = ' delta'
1909 1909 else:
1910 1910 basehdr = ' base'
1911 1911
1912 1912 if format == 0:
1913 1913 ui.write(" rev offset length " + basehdr + " linkrev"
1914 1914 " nodeid p1 p2\n")
1915 1915 elif format == 1:
1916 1916 ui.write(" rev flag offset length"
1917 1917 " size " + basehdr + " link p1 p2"
1918 1918 " nodeid\n")
1919 1919
1920 1920 for i in r:
1921 1921 node = r.node(i)
1922 1922 if generaldelta:
1923 1923 base = r.deltaparent(i)
1924 1924 else:
1925 1925 base = r.chainbase(i)
1926 1926 if format == 0:
1927 1927 try:
1928 1928 pp = r.parents(node)
1929 1929 except Exception:
1930 1930 pp = [nullid, nullid]
1931 1931 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1932 1932 i, r.start(i), r.length(i), base, r.linkrev(i),
1933 1933 short(node), short(pp[0]), short(pp[1])))
1934 1934 elif format == 1:
1935 1935 pr = r.parentrevs(i)
1936 1936 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1937 1937 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1938 1938 base, r.linkrev(i), pr[0], pr[1], short(node)))
1939 1939
1940 1940 @command('debugindexdot', [], _('FILE'))
1941 1941 def debugindexdot(ui, repo, file_):
1942 1942 """dump an index DAG as a graphviz dot file"""
1943 1943 r = None
1944 1944 if repo:
1945 1945 filelog = repo.file(file_)
1946 1946 if len(filelog):
1947 1947 r = filelog
1948 1948 if not r:
1949 1949 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1950 1950 ui.write("digraph G {\n")
1951 1951 for i in r:
1952 1952 node = r.node(i)
1953 1953 pp = r.parents(node)
1954 1954 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1955 1955 if pp[1] != nullid:
1956 1956 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1957 1957 ui.write("}\n")
1958 1958
1959 1959 @command('debuginstall', [], '')
1960 1960 def debuginstall(ui):
1961 1961 '''test Mercurial installation
1962 1962
1963 1963 Returns 0 on success.
1964 1964 '''
1965 1965
1966 1966 def writetemp(contents):
1967 1967 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1968 1968 f = os.fdopen(fd, "wb")
1969 1969 f.write(contents)
1970 1970 f.close()
1971 1971 return name
1972 1972
1973 1973 problems = 0
1974 1974
1975 1975 # encoding
1976 1976 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1977 1977 try:
1978 1978 encoding.fromlocal("test")
1979 1979 except util.Abort, inst:
1980 1980 ui.write(" %s\n" % inst)
1981 1981 ui.write(_(" (check that your locale is properly set)\n"))
1982 1982 problems += 1
1983 1983
1984 1984 # compiled modules
1985 1985 ui.status(_("checking installed modules (%s)...\n")
1986 1986 % os.path.dirname(__file__))
1987 1987 try:
1988 1988 import bdiff, mpatch, base85, osutil
1989 1989 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1990 1990 except Exception, inst:
1991 1991 ui.write(" %s\n" % inst)
1992 1992 ui.write(_(" One or more extensions could not be found"))
1993 1993 ui.write(_(" (check that you compiled the extensions)\n"))
1994 1994 problems += 1
1995 1995
1996 1996 # templates
1997 1997 import templater
1998 1998 p = templater.templatepath()
1999 1999 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2000 2000 try:
2001 2001 templater.templater(templater.templatepath("map-cmdline.default"))
2002 2002 except Exception, inst:
2003 2003 ui.write(" %s\n" % inst)
2004 2004 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2005 2005 problems += 1
2006 2006
2007 2007 # editor
2008 2008 ui.status(_("checking commit editor...\n"))
2009 2009 editor = ui.geteditor()
2010 2010 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2011 2011 if not cmdpath:
2012 2012 if editor == 'vi':
2013 2013 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2014 2014 ui.write(_(" (specify a commit editor in your configuration"
2015 2015 " file)\n"))
2016 2016 else:
2017 2017 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2018 2018 ui.write(_(" (specify a commit editor in your configuration"
2019 2019 " file)\n"))
2020 2020 problems += 1
2021 2021
2022 2022 # check username
2023 2023 ui.status(_("checking username...\n"))
2024 2024 try:
2025 2025 ui.username()
2026 2026 except util.Abort, e:
2027 2027 ui.write(" %s\n" % e)
2028 2028 ui.write(_(" (specify a username in your configuration file)\n"))
2029 2029 problems += 1
2030 2030
2031 2031 if not problems:
2032 2032 ui.status(_("no problems detected\n"))
2033 2033 else:
2034 2034 ui.write(_("%s problems detected,"
2035 2035 " please check your install!\n") % problems)
2036 2036
2037 2037 return problems
2038 2038
2039 2039 @command('debugknown', [], _('REPO ID...'))
2040 2040 def debugknown(ui, repopath, *ids, **opts):
2041 2041 """test whether node ids are known to a repo
2042 2042
2043 2043 Every ID must be a full-length hex node id string. Returns a list of 0s
2044 2044 and 1s indicating unknown/known.
2045 2045 """
2046 2046 repo = hg.peer(ui, opts, repopath)
2047 2047 if not repo.capable('known'):
2048 2048 raise util.Abort("known() not supported by target repository")
2049 2049 flags = repo.known([bin(s) for s in ids])
2050 2050 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2051 2051
2052 @command('debugobsolete', [] + commitopts2,
2053 _('OBSOLETED [REPLACEMENT] [REPL...'))
2054 def debugobsolete(ui, repo, precursor, *successors, **opts):
2055 """create arbitrary obsolete marker"""
2056 metadata = {}
2057 if 'date' in opts:
2058 metadata['date'] = opts['date']
2059 metadata['user'] = opts['user'] or ui.username()
2060 succs = tuple(bin(succ) for succ in successors)
2061 l = repo.lock()
2062 try:
2063 repo.obsstore.create(bin(precursor), succs, 0, metadata)
2064 finally:
2065 l.release()
2066
2052 2067 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2053 2068 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2054 2069 '''access the pushkey key/value protocol
2055 2070
2056 2071 With two args, list the keys in the given namespace.
2057 2072
2058 2073 With five args, set a key to new if it currently is set to old.
2059 2074 Reports success or failure.
2060 2075 '''
2061 2076
2062 2077 target = hg.peer(ui, {}, repopath)
2063 2078 if keyinfo:
2064 2079 key, old, new = keyinfo
2065 2080 r = target.pushkey(namespace, key, old, new)
2066 2081 ui.status(str(r) + '\n')
2067 2082 return not r
2068 2083 else:
2069 2084 for k, v in target.listkeys(namespace).iteritems():
2070 2085 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2071 2086 v.encode('string-escape')))
2072 2087
2073 2088 @command('debugpvec', [], _('A B'))
2074 2089 def debugpvec(ui, repo, a, b=None):
2075 2090 ca = scmutil.revsingle(repo, a)
2076 2091 cb = scmutil.revsingle(repo, b)
2077 2092 pa = pvec.ctxpvec(ca)
2078 2093 pb = pvec.ctxpvec(cb)
2079 2094 if pa == pb:
2080 2095 rel = "="
2081 2096 elif pa > pb:
2082 2097 rel = ">"
2083 2098 elif pa < pb:
2084 2099 rel = "<"
2085 2100 elif pa | pb:
2086 2101 rel = "|"
2087 2102 ui.write(_("a: %s\n") % pa)
2088 2103 ui.write(_("b: %s\n") % pb)
2089 2104 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2090 2105 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2091 2106 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2092 2107 pa.distance(pb), rel))
2093 2108
2094 2109 @command('debugrebuildstate',
2095 2110 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2096 2111 _('[-r REV] [REV]'))
2097 2112 def debugrebuildstate(ui, repo, rev="tip"):
2098 2113 """rebuild the dirstate as it would look like for the given revision"""
2099 2114 ctx = scmutil.revsingle(repo, rev)
2100 2115 wlock = repo.wlock()
2101 2116 try:
2102 2117 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2103 2118 finally:
2104 2119 wlock.release()
2105 2120
2106 2121 @command('debugrename',
2107 2122 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2108 2123 _('[-r REV] FILE'))
2109 2124 def debugrename(ui, repo, file1, *pats, **opts):
2110 2125 """dump rename information"""
2111 2126
2112 2127 ctx = scmutil.revsingle(repo, opts.get('rev'))
2113 2128 m = scmutil.match(ctx, (file1,) + pats, opts)
2114 2129 for abs in ctx.walk(m):
2115 2130 fctx = ctx[abs]
2116 2131 o = fctx.filelog().renamed(fctx.filenode())
2117 2132 rel = m.rel(abs)
2118 2133 if o:
2119 2134 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2120 2135 else:
2121 2136 ui.write(_("%s not renamed\n") % rel)
2122 2137
2123 2138 @command('debugrevlog',
2124 2139 [('c', 'changelog', False, _('open changelog')),
2125 2140 ('m', 'manifest', False, _('open manifest')),
2126 2141 ('d', 'dump', False, _('dump index data'))],
2127 2142 _('-c|-m|FILE'))
2128 2143 def debugrevlog(ui, repo, file_ = None, **opts):
2129 2144 """show data and statistics about a revlog"""
2130 2145 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2131 2146
2132 2147 if opts.get("dump"):
2133 2148 numrevs = len(r)
2134 2149 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2135 2150 " rawsize totalsize compression heads\n")
2136 2151 ts = 0
2137 2152 heads = set()
2138 2153 for rev in xrange(numrevs):
2139 2154 dbase = r.deltaparent(rev)
2140 2155 if dbase == -1:
2141 2156 dbase = rev
2142 2157 cbase = r.chainbase(rev)
2143 2158 p1, p2 = r.parentrevs(rev)
2144 2159 rs = r.rawsize(rev)
2145 2160 ts = ts + rs
2146 2161 heads -= set(r.parentrevs(rev))
2147 2162 heads.add(rev)
2148 2163 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2149 2164 (rev, p1, p2, r.start(rev), r.end(rev),
2150 2165 r.start(dbase), r.start(cbase),
2151 2166 r.start(p1), r.start(p2),
2152 2167 rs, ts, ts / r.end(rev), len(heads)))
2153 2168 return 0
2154 2169
2155 2170 v = r.version
2156 2171 format = v & 0xFFFF
2157 2172 flags = []
2158 2173 gdelta = False
2159 2174 if v & revlog.REVLOGNGINLINEDATA:
2160 2175 flags.append('inline')
2161 2176 if v & revlog.REVLOGGENERALDELTA:
2162 2177 gdelta = True
2163 2178 flags.append('generaldelta')
2164 2179 if not flags:
2165 2180 flags = ['(none)']
2166 2181
2167 2182 nummerges = 0
2168 2183 numfull = 0
2169 2184 numprev = 0
2170 2185 nump1 = 0
2171 2186 nump2 = 0
2172 2187 numother = 0
2173 2188 nump1prev = 0
2174 2189 nump2prev = 0
2175 2190 chainlengths = []
2176 2191
2177 2192 datasize = [None, 0, 0L]
2178 2193 fullsize = [None, 0, 0L]
2179 2194 deltasize = [None, 0, 0L]
2180 2195
2181 2196 def addsize(size, l):
2182 2197 if l[0] is None or size < l[0]:
2183 2198 l[0] = size
2184 2199 if size > l[1]:
2185 2200 l[1] = size
2186 2201 l[2] += size
2187 2202
2188 2203 numrevs = len(r)
2189 2204 for rev in xrange(numrevs):
2190 2205 p1, p2 = r.parentrevs(rev)
2191 2206 delta = r.deltaparent(rev)
2192 2207 if format > 0:
2193 2208 addsize(r.rawsize(rev), datasize)
2194 2209 if p2 != nullrev:
2195 2210 nummerges += 1
2196 2211 size = r.length(rev)
2197 2212 if delta == nullrev:
2198 2213 chainlengths.append(0)
2199 2214 numfull += 1
2200 2215 addsize(size, fullsize)
2201 2216 else:
2202 2217 chainlengths.append(chainlengths[delta] + 1)
2203 2218 addsize(size, deltasize)
2204 2219 if delta == rev - 1:
2205 2220 numprev += 1
2206 2221 if delta == p1:
2207 2222 nump1prev += 1
2208 2223 elif delta == p2:
2209 2224 nump2prev += 1
2210 2225 elif delta == p1:
2211 2226 nump1 += 1
2212 2227 elif delta == p2:
2213 2228 nump2 += 1
2214 2229 elif delta != nullrev:
2215 2230 numother += 1
2216 2231
2217 2232 numdeltas = numrevs - numfull
2218 2233 numoprev = numprev - nump1prev - nump2prev
2219 2234 totalrawsize = datasize[2]
2220 2235 datasize[2] /= numrevs
2221 2236 fulltotal = fullsize[2]
2222 2237 fullsize[2] /= numfull
2223 2238 deltatotal = deltasize[2]
2224 2239 deltasize[2] /= numrevs - numfull
2225 2240 totalsize = fulltotal + deltatotal
2226 2241 avgchainlen = sum(chainlengths) / numrevs
2227 2242 compratio = totalrawsize / totalsize
2228 2243
2229 2244 basedfmtstr = '%%%dd\n'
2230 2245 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2231 2246
2232 2247 def dfmtstr(max):
2233 2248 return basedfmtstr % len(str(max))
2234 2249 def pcfmtstr(max, padding=0):
2235 2250 return basepcfmtstr % (len(str(max)), ' ' * padding)
2236 2251
2237 2252 def pcfmt(value, total):
2238 2253 return (value, 100 * float(value) / total)
2239 2254
2240 2255 ui.write('format : %d\n' % format)
2241 2256 ui.write('flags : %s\n' % ', '.join(flags))
2242 2257
2243 2258 ui.write('\n')
2244 2259 fmt = pcfmtstr(totalsize)
2245 2260 fmt2 = dfmtstr(totalsize)
2246 2261 ui.write('revisions : ' + fmt2 % numrevs)
2247 2262 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2248 2263 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2249 2264 ui.write('revisions : ' + fmt2 % numrevs)
2250 2265 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2251 2266 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2252 2267 ui.write('revision size : ' + fmt2 % totalsize)
2253 2268 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2254 2269 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2255 2270
2256 2271 ui.write('\n')
2257 2272 fmt = dfmtstr(max(avgchainlen, compratio))
2258 2273 ui.write('avg chain length : ' + fmt % avgchainlen)
2259 2274 ui.write('compression ratio : ' + fmt % compratio)
2260 2275
2261 2276 if format > 0:
2262 2277 ui.write('\n')
2263 2278 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2264 2279 % tuple(datasize))
2265 2280 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2266 2281 % tuple(fullsize))
2267 2282 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2268 2283 % tuple(deltasize))
2269 2284
2270 2285 if numdeltas > 0:
2271 2286 ui.write('\n')
2272 2287 fmt = pcfmtstr(numdeltas)
2273 2288 fmt2 = pcfmtstr(numdeltas, 4)
2274 2289 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2275 2290 if numprev > 0:
2276 2291 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2277 2292 numprev))
2278 2293 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2279 2294 numprev))
2280 2295 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2281 2296 numprev))
2282 2297 if gdelta:
2283 2298 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2284 2299 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2285 2300 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2286 2301 numdeltas))
2287 2302
2288 2303 @command('debugrevspec', [], ('REVSPEC'))
2289 2304 def debugrevspec(ui, repo, expr):
2290 2305 """parse and apply a revision specification
2291 2306
2292 2307 Use --verbose to print the parsed tree before and after aliases
2293 2308 expansion.
2294 2309 """
2295 2310 if ui.verbose:
2296 2311 tree = revset.parse(expr)[0]
2297 2312 ui.note(revset.prettyformat(tree), "\n")
2298 2313 newtree = revset.findaliases(ui, tree)
2299 2314 if newtree != tree:
2300 2315 ui.note(revset.prettyformat(newtree), "\n")
2301 2316 func = revset.match(ui, expr)
2302 2317 for c in func(repo, range(len(repo))):
2303 2318 ui.write("%s\n" % c)
2304 2319
2305 2320 @command('debugsetparents', [], _('REV1 [REV2]'))
2306 2321 def debugsetparents(ui, repo, rev1, rev2=None):
2307 2322 """manually set the parents of the current working directory
2308 2323
2309 2324 This is useful for writing repository conversion tools, but should
2310 2325 be used with care.
2311 2326
2312 2327 Returns 0 on success.
2313 2328 """
2314 2329
2315 2330 r1 = scmutil.revsingle(repo, rev1).node()
2316 2331 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2317 2332
2318 2333 wlock = repo.wlock()
2319 2334 try:
2320 2335 repo.setparents(r1, r2)
2321 2336 finally:
2322 2337 wlock.release()
2323 2338
2324 2339 @command('debugstate',
2325 2340 [('', 'nodates', None, _('do not display the saved mtime')),
2326 2341 ('', 'datesort', None, _('sort by saved mtime'))],
2327 2342 _('[OPTION]...'))
2328 2343 def debugstate(ui, repo, nodates=None, datesort=None):
2329 2344 """show the contents of the current dirstate"""
2330 2345 timestr = ""
2331 2346 showdate = not nodates
2332 2347 if datesort:
2333 2348 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2334 2349 else:
2335 2350 keyfunc = None # sort by filename
2336 2351 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2337 2352 if showdate:
2338 2353 if ent[3] == -1:
2339 2354 # Pad or slice to locale representation
2340 2355 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2341 2356 time.localtime(0)))
2342 2357 timestr = 'unset'
2343 2358 timestr = (timestr[:locale_len] +
2344 2359 ' ' * (locale_len - len(timestr)))
2345 2360 else:
2346 2361 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2347 2362 time.localtime(ent[3]))
2348 2363 if ent[1] & 020000:
2349 2364 mode = 'lnk'
2350 2365 else:
2351 2366 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2352 2367 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2353 2368 for f in repo.dirstate.copies():
2354 2369 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2355 2370
2356 2371 @command('debugsub',
2357 2372 [('r', 'rev', '',
2358 2373 _('revision to check'), _('REV'))],
2359 2374 _('[-r REV] [REV]'))
2360 2375 def debugsub(ui, repo, rev=None):
2361 2376 ctx = scmutil.revsingle(repo, rev, None)
2362 2377 for k, v in sorted(ctx.substate.items()):
2363 2378 ui.write('path %s\n' % k)
2364 2379 ui.write(' source %s\n' % v[0])
2365 2380 ui.write(' revision %s\n' % v[1])
2366 2381
2367 2382 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2368 2383 def debugwalk(ui, repo, *pats, **opts):
2369 2384 """show how files match on given patterns"""
2370 2385 m = scmutil.match(repo[None], pats, opts)
2371 2386 items = list(repo.walk(m))
2372 2387 if not items:
2373 2388 return
2374 2389 f = lambda fn: fn
2375 2390 if ui.configbool('ui', 'slash') and os.sep != '/':
2376 2391 f = lambda fn: util.normpath(fn)
2377 2392 fmt = 'f %%-%ds %%-%ds %%s' % (
2378 2393 max([len(abs) for abs in items]),
2379 2394 max([len(m.rel(abs)) for abs in items]))
2380 2395 for abs in items:
2381 2396 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2382 2397 ui.write("%s\n" % line.rstrip())
2383 2398
2384 2399 @command('debugwireargs',
2385 2400 [('', 'three', '', 'three'),
2386 2401 ('', 'four', '', 'four'),
2387 2402 ('', 'five', '', 'five'),
2388 2403 ] + remoteopts,
2389 2404 _('REPO [OPTIONS]... [ONE [TWO]]'))
2390 2405 def debugwireargs(ui, repopath, *vals, **opts):
2391 2406 repo = hg.peer(ui, opts, repopath)
2392 2407 for opt in remoteopts:
2393 2408 del opts[opt[1]]
2394 2409 args = {}
2395 2410 for k, v in opts.iteritems():
2396 2411 if v:
2397 2412 args[k] = v
2398 2413 # run twice to check that we don't mess up the stream for the next command
2399 2414 res1 = repo.debugwireargs(*vals, **args)
2400 2415 res2 = repo.debugwireargs(*vals, **args)
2401 2416 ui.write("%s\n" % res1)
2402 2417 if res1 != res2:
2403 2418 ui.warn("%s\n" % res2)
2404 2419
2405 2420 @command('^diff',
2406 2421 [('r', 'rev', [], _('revision'), _('REV')),
2407 2422 ('c', 'change', '', _('change made by revision'), _('REV'))
2408 2423 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2409 2424 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2410 2425 def diff(ui, repo, *pats, **opts):
2411 2426 """diff repository (or selected files)
2412 2427
2413 2428 Show differences between revisions for the specified files.
2414 2429
2415 2430 Differences between files are shown using the unified diff format.
2416 2431
2417 2432 .. note::
2418 2433 diff may generate unexpected results for merges, as it will
2419 2434 default to comparing against the working directory's first
2420 2435 parent changeset if no revisions are specified.
2421 2436
2422 2437 When two revision arguments are given, then changes are shown
2423 2438 between those revisions. If only one revision is specified then
2424 2439 that revision is compared to the working directory, and, when no
2425 2440 revisions are specified, the working directory files are compared
2426 2441 to its parent.
2427 2442
2428 2443 Alternatively you can specify -c/--change with a revision to see
2429 2444 the changes in that changeset relative to its first parent.
2430 2445
2431 2446 Without the -a/--text option, diff will avoid generating diffs of
2432 2447 files it detects as binary. With -a, diff will generate a diff
2433 2448 anyway, probably with undesirable results.
2434 2449
2435 2450 Use the -g/--git option to generate diffs in the git extended diff
2436 2451 format. For more information, read :hg:`help diffs`.
2437 2452
2438 2453 .. container:: verbose
2439 2454
2440 2455 Examples:
2441 2456
2442 2457 - compare a file in the current working directory to its parent::
2443 2458
2444 2459 hg diff foo.c
2445 2460
2446 2461 - compare two historical versions of a directory, with rename info::
2447 2462
2448 2463 hg diff --git -r 1.0:1.2 lib/
2449 2464
2450 2465 - get change stats relative to the last change on some date::
2451 2466
2452 2467 hg diff --stat -r "date('may 2')"
2453 2468
2454 2469 - diff all newly-added files that contain a keyword::
2455 2470
2456 2471 hg diff "set:added() and grep(GNU)"
2457 2472
2458 2473 - compare a revision and its parents::
2459 2474
2460 2475 hg diff -c 9353 # compare against first parent
2461 2476 hg diff -r 9353^:9353 # same using revset syntax
2462 2477 hg diff -r 9353^2:9353 # compare against the second parent
2463 2478
2464 2479 Returns 0 on success.
2465 2480 """
2466 2481
2467 2482 revs = opts.get('rev')
2468 2483 change = opts.get('change')
2469 2484 stat = opts.get('stat')
2470 2485 reverse = opts.get('reverse')
2471 2486
2472 2487 if revs and change:
2473 2488 msg = _('cannot specify --rev and --change at the same time')
2474 2489 raise util.Abort(msg)
2475 2490 elif change:
2476 2491 node2 = scmutil.revsingle(repo, change, None).node()
2477 2492 node1 = repo[node2].p1().node()
2478 2493 else:
2479 2494 node1, node2 = scmutil.revpair(repo, revs)
2480 2495
2481 2496 if reverse:
2482 2497 node1, node2 = node2, node1
2483 2498
2484 2499 diffopts = patch.diffopts(ui, opts)
2485 2500 m = scmutil.match(repo[node2], pats, opts)
2486 2501 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2487 2502 listsubrepos=opts.get('subrepos'))
2488 2503
2489 2504 @command('^export',
2490 2505 [('o', 'output', '',
2491 2506 _('print output to file with formatted name'), _('FORMAT')),
2492 2507 ('', 'switch-parent', None, _('diff against the second parent')),
2493 2508 ('r', 'rev', [], _('revisions to export'), _('REV')),
2494 2509 ] + diffopts,
2495 2510 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2496 2511 def export(ui, repo, *changesets, **opts):
2497 2512 """dump the header and diffs for one or more changesets
2498 2513
2499 2514 Print the changeset header and diffs for one or more revisions.
2500 2515
2501 2516 The information shown in the changeset header is: author, date,
2502 2517 branch name (if non-default), changeset hash, parent(s) and commit
2503 2518 comment.
2504 2519
2505 2520 .. note::
2506 2521 export may generate unexpected diff output for merge
2507 2522 changesets, as it will compare the merge changeset against its
2508 2523 first parent only.
2509 2524
2510 2525 Output may be to a file, in which case the name of the file is
2511 2526 given using a format string. The formatting rules are as follows:
2512 2527
2513 2528 :``%%``: literal "%" character
2514 2529 :``%H``: changeset hash (40 hexadecimal digits)
2515 2530 :``%N``: number of patches being generated
2516 2531 :``%R``: changeset revision number
2517 2532 :``%b``: basename of the exporting repository
2518 2533 :``%h``: short-form changeset hash (12 hexadecimal digits)
2519 2534 :``%m``: first line of the commit message (only alphanumeric characters)
2520 2535 :``%n``: zero-padded sequence number, starting at 1
2521 2536 :``%r``: zero-padded changeset revision number
2522 2537
2523 2538 Without the -a/--text option, export will avoid generating diffs
2524 2539 of files it detects as binary. With -a, export will generate a
2525 2540 diff anyway, probably with undesirable results.
2526 2541
2527 2542 Use the -g/--git option to generate diffs in the git extended diff
2528 2543 format. See :hg:`help diffs` for more information.
2529 2544
2530 2545 With the --switch-parent option, the diff will be against the
2531 2546 second parent. It can be useful to review a merge.
2532 2547
2533 2548 .. container:: verbose
2534 2549
2535 2550 Examples:
2536 2551
2537 2552 - use export and import to transplant a bugfix to the current
2538 2553 branch::
2539 2554
2540 2555 hg export -r 9353 | hg import -
2541 2556
2542 2557 - export all the changesets between two revisions to a file with
2543 2558 rename information::
2544 2559
2545 2560 hg export --git -r 123:150 > changes.txt
2546 2561
2547 2562 - split outgoing changes into a series of patches with
2548 2563 descriptive names::
2549 2564
2550 2565 hg export -r "outgoing()" -o "%n-%m.patch"
2551 2566
2552 2567 Returns 0 on success.
2553 2568 """
2554 2569 changesets += tuple(opts.get('rev', []))
2555 2570 revs = scmutil.revrange(repo, changesets)
2556 2571 if not revs:
2557 2572 raise util.Abort(_("export requires at least one changeset"))
2558 2573 if len(revs) > 1:
2559 2574 ui.note(_('exporting patches:\n'))
2560 2575 else:
2561 2576 ui.note(_('exporting patch:\n'))
2562 2577 cmdutil.export(repo, revs, template=opts.get('output'),
2563 2578 switch_parent=opts.get('switch_parent'),
2564 2579 opts=patch.diffopts(ui, opts))
2565 2580
2566 2581 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2567 2582 def forget(ui, repo, *pats, **opts):
2568 2583 """forget the specified files on the next commit
2569 2584
2570 2585 Mark the specified files so they will no longer be tracked
2571 2586 after the next commit.
2572 2587
2573 2588 This only removes files from the current branch, not from the
2574 2589 entire project history, and it does not delete them from the
2575 2590 working directory.
2576 2591
2577 2592 To undo a forget before the next commit, see :hg:`add`.
2578 2593
2579 2594 .. container:: verbose
2580 2595
2581 2596 Examples:
2582 2597
2583 2598 - forget newly-added binary files::
2584 2599
2585 2600 hg forget "set:added() and binary()"
2586 2601
2587 2602 - forget files that would be excluded by .hgignore::
2588 2603
2589 2604 hg forget "set:hgignore()"
2590 2605
2591 2606 Returns 0 on success.
2592 2607 """
2593 2608
2594 2609 if not pats:
2595 2610 raise util.Abort(_('no files specified'))
2596 2611
2597 2612 m = scmutil.match(repo[None], pats, opts)
2598 2613 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2599 2614 return rejected and 1 or 0
2600 2615
2601 2616 @command(
2602 2617 'graft',
2603 2618 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2604 2619 ('c', 'continue', False, _('resume interrupted graft')),
2605 2620 ('e', 'edit', False, _('invoke editor on commit messages')),
2606 2621 ('', 'log', None, _('append graft info to log message')),
2607 2622 ('D', 'currentdate', False,
2608 2623 _('record the current date as commit date')),
2609 2624 ('U', 'currentuser', False,
2610 2625 _('record the current user as committer'), _('DATE'))]
2611 2626 + commitopts2 + mergetoolopts + dryrunopts,
2612 2627 _('[OPTION]... [-r] REV...'))
2613 2628 def graft(ui, repo, *revs, **opts):
2614 2629 '''copy changes from other branches onto the current branch
2615 2630
2616 2631 This command uses Mercurial's merge logic to copy individual
2617 2632 changes from other branches without merging branches in the
2618 2633 history graph. This is sometimes known as 'backporting' or
2619 2634 'cherry-picking'. By default, graft will copy user, date, and
2620 2635 description from the source changesets.
2621 2636
2622 2637 Changesets that are ancestors of the current revision, that have
2623 2638 already been grafted, or that are merges will be skipped.
2624 2639
2625 2640 If --log is specified, log messages will have a comment appended
2626 2641 of the form::
2627 2642
2628 2643 (grafted from CHANGESETHASH)
2629 2644
2630 2645 If a graft merge results in conflicts, the graft process is
2631 2646 interrupted so that the current merge can be manually resolved.
2632 2647 Once all conflicts are addressed, the graft process can be
2633 2648 continued with the -c/--continue option.
2634 2649
2635 2650 .. note::
2636 2651 The -c/--continue option does not reapply earlier options.
2637 2652
2638 2653 .. container:: verbose
2639 2654
2640 2655 Examples:
2641 2656
2642 2657 - copy a single change to the stable branch and edit its description::
2643 2658
2644 2659 hg update stable
2645 2660 hg graft --edit 9393
2646 2661
2647 2662 - graft a range of changesets with one exception, updating dates::
2648 2663
2649 2664 hg graft -D "2085::2093 and not 2091"
2650 2665
2651 2666 - continue a graft after resolving conflicts::
2652 2667
2653 2668 hg graft -c
2654 2669
2655 2670 - show the source of a grafted changeset::
2656 2671
2657 2672 hg log --debug -r tip
2658 2673
2659 2674 Returns 0 on successful completion.
2660 2675 '''
2661 2676
2662 2677 revs = list(revs)
2663 2678 revs.extend(opts['rev'])
2664 2679
2665 2680 if not opts.get('user') and opts.get('currentuser'):
2666 2681 opts['user'] = ui.username()
2667 2682 if not opts.get('date') and opts.get('currentdate'):
2668 2683 opts['date'] = "%d %d" % util.makedate()
2669 2684
2670 2685 editor = None
2671 2686 if opts.get('edit'):
2672 2687 editor = cmdutil.commitforceeditor
2673 2688
2674 2689 cont = False
2675 2690 if opts['continue']:
2676 2691 cont = True
2677 2692 if revs:
2678 2693 raise util.Abort(_("can't specify --continue and revisions"))
2679 2694 # read in unfinished revisions
2680 2695 try:
2681 2696 nodes = repo.opener.read('graftstate').splitlines()
2682 2697 revs = [repo[node].rev() for node in nodes]
2683 2698 except IOError, inst:
2684 2699 if inst.errno != errno.ENOENT:
2685 2700 raise
2686 2701 raise util.Abort(_("no graft state found, can't continue"))
2687 2702 else:
2688 2703 cmdutil.bailifchanged(repo)
2689 2704 if not revs:
2690 2705 raise util.Abort(_('no revisions specified'))
2691 2706 revs = scmutil.revrange(repo, revs)
2692 2707
2693 2708 # check for merges
2694 2709 for rev in repo.revs('%ld and merge()', revs):
2695 2710 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2696 2711 revs.remove(rev)
2697 2712 if not revs:
2698 2713 return -1
2699 2714
2700 2715 # check for ancestors of dest branch
2701 2716 for rev in repo.revs('::. and %ld', revs):
2702 2717 ui.warn(_('skipping ancestor revision %s\n') % rev)
2703 2718 revs.remove(rev)
2704 2719 if not revs:
2705 2720 return -1
2706 2721
2707 2722 # analyze revs for earlier grafts
2708 2723 ids = {}
2709 2724 for ctx in repo.set("%ld", revs):
2710 2725 ids[ctx.hex()] = ctx.rev()
2711 2726 n = ctx.extra().get('source')
2712 2727 if n:
2713 2728 ids[n] = ctx.rev()
2714 2729
2715 2730 # check ancestors for earlier grafts
2716 2731 ui.debug('scanning for duplicate grafts\n')
2717 2732 for ctx in repo.set("::. - ::%ld", revs):
2718 2733 n = ctx.extra().get('source')
2719 2734 if n in ids:
2720 2735 r = repo[n].rev()
2721 2736 if r in revs:
2722 2737 ui.warn(_('skipping already grafted revision %s\n') % r)
2723 2738 revs.remove(r)
2724 2739 elif ids[n] in revs:
2725 2740 ui.warn(_('skipping already grafted revision %s '
2726 2741 '(same origin %d)\n') % (ids[n], r))
2727 2742 revs.remove(ids[n])
2728 2743 elif ctx.hex() in ids:
2729 2744 r = ids[ctx.hex()]
2730 2745 ui.warn(_('skipping already grafted revision %s '
2731 2746 '(was grafted from %d)\n') % (r, ctx.rev()))
2732 2747 revs.remove(r)
2733 2748 if not revs:
2734 2749 return -1
2735 2750
2736 2751 wlock = repo.wlock()
2737 2752 try:
2738 2753 for pos, ctx in enumerate(repo.set("%ld", revs)):
2739 2754 current = repo['.']
2740 2755
2741 2756 ui.status(_('grafting revision %s\n') % ctx.rev())
2742 2757 if opts.get('dry_run'):
2743 2758 continue
2744 2759
2745 2760 # we don't merge the first commit when continuing
2746 2761 if not cont:
2747 2762 # perform the graft merge with p1(rev) as 'ancestor'
2748 2763 try:
2749 2764 # ui.forcemerge is an internal variable, do not document
2750 2765 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2751 2766 stats = mergemod.update(repo, ctx.node(), True, True, False,
2752 2767 ctx.p1().node())
2753 2768 finally:
2754 2769 repo.ui.setconfig('ui', 'forcemerge', '')
2755 2770 # report any conflicts
2756 2771 if stats and stats[3] > 0:
2757 2772 # write out state for --continue
2758 2773 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2759 2774 repo.opener.write('graftstate', ''.join(nodelines))
2760 2775 raise util.Abort(
2761 2776 _("unresolved conflicts, can't continue"),
2762 2777 hint=_('use hg resolve and hg graft --continue'))
2763 2778 else:
2764 2779 cont = False
2765 2780
2766 2781 # drop the second merge parent
2767 2782 repo.setparents(current.node(), nullid)
2768 2783 repo.dirstate.write()
2769 2784 # fix up dirstate for copies and renames
2770 2785 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2771 2786
2772 2787 # commit
2773 2788 source = ctx.extra().get('source')
2774 2789 if not source:
2775 2790 source = ctx.hex()
2776 2791 extra = {'source': source}
2777 2792 user = ctx.user()
2778 2793 if opts.get('user'):
2779 2794 user = opts['user']
2780 2795 date = ctx.date()
2781 2796 if opts.get('date'):
2782 2797 date = opts['date']
2783 2798 message = ctx.description()
2784 2799 if opts.get('log'):
2785 2800 message += '\n(grafted from %s)' % ctx.hex()
2786 2801 node = repo.commit(text=message, user=user,
2787 2802 date=date, extra=extra, editor=editor)
2788 2803 if node is None:
2789 2804 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2790 2805 finally:
2791 2806 wlock.release()
2792 2807
2793 2808 # remove state when we complete successfully
2794 2809 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2795 2810 util.unlinkpath(repo.join('graftstate'))
2796 2811
2797 2812 return 0
2798 2813
2799 2814 @command('grep',
2800 2815 [('0', 'print0', None, _('end fields with NUL')),
2801 2816 ('', 'all', None, _('print all revisions that match')),
2802 2817 ('a', 'text', None, _('treat all files as text')),
2803 2818 ('f', 'follow', None,
2804 2819 _('follow changeset history,'
2805 2820 ' or file history across copies and renames')),
2806 2821 ('i', 'ignore-case', None, _('ignore case when matching')),
2807 2822 ('l', 'files-with-matches', None,
2808 2823 _('print only filenames and revisions that match')),
2809 2824 ('n', 'line-number', None, _('print matching line numbers')),
2810 2825 ('r', 'rev', [],
2811 2826 _('only search files changed within revision range'), _('REV')),
2812 2827 ('u', 'user', None, _('list the author (long with -v)')),
2813 2828 ('d', 'date', None, _('list the date (short with -q)')),
2814 2829 ] + walkopts,
2815 2830 _('[OPTION]... PATTERN [FILE]...'))
2816 2831 def grep(ui, repo, pattern, *pats, **opts):
2817 2832 """search for a pattern in specified files and revisions
2818 2833
2819 2834 Search revisions of files for a regular expression.
2820 2835
2821 2836 This command behaves differently than Unix grep. It only accepts
2822 2837 Python/Perl regexps. It searches repository history, not the
2823 2838 working directory. It always prints the revision number in which a
2824 2839 match appears.
2825 2840
2826 2841 By default, grep only prints output for the first revision of a
2827 2842 file in which it finds a match. To get it to print every revision
2828 2843 that contains a change in match status ("-" for a match that
2829 2844 becomes a non-match, or "+" for a non-match that becomes a match),
2830 2845 use the --all flag.
2831 2846
2832 2847 Returns 0 if a match is found, 1 otherwise.
2833 2848 """
2834 2849 reflags = re.M
2835 2850 if opts.get('ignore_case'):
2836 2851 reflags |= re.I
2837 2852 try:
2838 2853 regexp = re.compile(pattern, reflags)
2839 2854 except re.error, inst:
2840 2855 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2841 2856 return 1
2842 2857 sep, eol = ':', '\n'
2843 2858 if opts.get('print0'):
2844 2859 sep = eol = '\0'
2845 2860
2846 2861 getfile = util.lrucachefunc(repo.file)
2847 2862
2848 2863 def matchlines(body):
2849 2864 begin = 0
2850 2865 linenum = 0
2851 2866 while True:
2852 2867 match = regexp.search(body, begin)
2853 2868 if not match:
2854 2869 break
2855 2870 mstart, mend = match.span()
2856 2871 linenum += body.count('\n', begin, mstart) + 1
2857 2872 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2858 2873 begin = body.find('\n', mend) + 1 or len(body) + 1
2859 2874 lend = begin - 1
2860 2875 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2861 2876
2862 2877 class linestate(object):
2863 2878 def __init__(self, line, linenum, colstart, colend):
2864 2879 self.line = line
2865 2880 self.linenum = linenum
2866 2881 self.colstart = colstart
2867 2882 self.colend = colend
2868 2883
2869 2884 def __hash__(self):
2870 2885 return hash((self.linenum, self.line))
2871 2886
2872 2887 def __eq__(self, other):
2873 2888 return self.line == other.line
2874 2889
2875 2890 matches = {}
2876 2891 copies = {}
2877 2892 def grepbody(fn, rev, body):
2878 2893 matches[rev].setdefault(fn, [])
2879 2894 m = matches[rev][fn]
2880 2895 for lnum, cstart, cend, line in matchlines(body):
2881 2896 s = linestate(line, lnum, cstart, cend)
2882 2897 m.append(s)
2883 2898
2884 2899 def difflinestates(a, b):
2885 2900 sm = difflib.SequenceMatcher(None, a, b)
2886 2901 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2887 2902 if tag == 'insert':
2888 2903 for i in xrange(blo, bhi):
2889 2904 yield ('+', b[i])
2890 2905 elif tag == 'delete':
2891 2906 for i in xrange(alo, ahi):
2892 2907 yield ('-', a[i])
2893 2908 elif tag == 'replace':
2894 2909 for i in xrange(alo, ahi):
2895 2910 yield ('-', a[i])
2896 2911 for i in xrange(blo, bhi):
2897 2912 yield ('+', b[i])
2898 2913
2899 2914 def display(fn, ctx, pstates, states):
2900 2915 rev = ctx.rev()
2901 2916 datefunc = ui.quiet and util.shortdate or util.datestr
2902 2917 found = False
2903 2918 filerevmatches = {}
2904 2919 def binary():
2905 2920 flog = getfile(fn)
2906 2921 return util.binary(flog.read(ctx.filenode(fn)))
2907 2922
2908 2923 if opts.get('all'):
2909 2924 iter = difflinestates(pstates, states)
2910 2925 else:
2911 2926 iter = [('', l) for l in states]
2912 2927 for change, l in iter:
2913 2928 cols = [fn, str(rev)]
2914 2929 before, match, after = None, None, None
2915 2930 if opts.get('line_number'):
2916 2931 cols.append(str(l.linenum))
2917 2932 if opts.get('all'):
2918 2933 cols.append(change)
2919 2934 if opts.get('user'):
2920 2935 cols.append(ui.shortuser(ctx.user()))
2921 2936 if opts.get('date'):
2922 2937 cols.append(datefunc(ctx.date()))
2923 2938 if opts.get('files_with_matches'):
2924 2939 c = (fn, rev)
2925 2940 if c in filerevmatches:
2926 2941 continue
2927 2942 filerevmatches[c] = 1
2928 2943 else:
2929 2944 before = l.line[:l.colstart]
2930 2945 match = l.line[l.colstart:l.colend]
2931 2946 after = l.line[l.colend:]
2932 2947 ui.write(sep.join(cols))
2933 2948 if before is not None:
2934 2949 if not opts.get('text') and binary():
2935 2950 ui.write(sep + " Binary file matches")
2936 2951 else:
2937 2952 ui.write(sep + before)
2938 2953 ui.write(match, label='grep.match')
2939 2954 ui.write(after)
2940 2955 ui.write(eol)
2941 2956 found = True
2942 2957 return found
2943 2958
2944 2959 skip = {}
2945 2960 revfiles = {}
2946 2961 matchfn = scmutil.match(repo[None], pats, opts)
2947 2962 found = False
2948 2963 follow = opts.get('follow')
2949 2964
2950 2965 def prep(ctx, fns):
2951 2966 rev = ctx.rev()
2952 2967 pctx = ctx.p1()
2953 2968 parent = pctx.rev()
2954 2969 matches.setdefault(rev, {})
2955 2970 matches.setdefault(parent, {})
2956 2971 files = revfiles.setdefault(rev, [])
2957 2972 for fn in fns:
2958 2973 flog = getfile(fn)
2959 2974 try:
2960 2975 fnode = ctx.filenode(fn)
2961 2976 except error.LookupError:
2962 2977 continue
2963 2978
2964 2979 copied = flog.renamed(fnode)
2965 2980 copy = follow and copied and copied[0]
2966 2981 if copy:
2967 2982 copies.setdefault(rev, {})[fn] = copy
2968 2983 if fn in skip:
2969 2984 if copy:
2970 2985 skip[copy] = True
2971 2986 continue
2972 2987 files.append(fn)
2973 2988
2974 2989 if fn not in matches[rev]:
2975 2990 grepbody(fn, rev, flog.read(fnode))
2976 2991
2977 2992 pfn = copy or fn
2978 2993 if pfn not in matches[parent]:
2979 2994 try:
2980 2995 fnode = pctx.filenode(pfn)
2981 2996 grepbody(pfn, parent, flog.read(fnode))
2982 2997 except error.LookupError:
2983 2998 pass
2984 2999
2985 3000 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2986 3001 rev = ctx.rev()
2987 3002 parent = ctx.p1().rev()
2988 3003 for fn in sorted(revfiles.get(rev, [])):
2989 3004 states = matches[rev][fn]
2990 3005 copy = copies.get(rev, {}).get(fn)
2991 3006 if fn in skip:
2992 3007 if copy:
2993 3008 skip[copy] = True
2994 3009 continue
2995 3010 pstates = matches.get(parent, {}).get(copy or fn, [])
2996 3011 if pstates or states:
2997 3012 r = display(fn, ctx, pstates, states)
2998 3013 found = found or r
2999 3014 if r and not opts.get('all'):
3000 3015 skip[fn] = True
3001 3016 if copy:
3002 3017 skip[copy] = True
3003 3018 del matches[rev]
3004 3019 del revfiles[rev]
3005 3020
3006 3021 return not found
3007 3022
3008 3023 @command('heads',
3009 3024 [('r', 'rev', '',
3010 3025 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3011 3026 ('t', 'topo', False, _('show topological heads only')),
3012 3027 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3013 3028 ('c', 'closed', False, _('show normal and closed branch heads')),
3014 3029 ] + templateopts,
3015 3030 _('[-ct] [-r STARTREV] [REV]...'))
3016 3031 def heads(ui, repo, *branchrevs, **opts):
3017 3032 """show current repository heads or show branch heads
3018 3033
3019 3034 With no arguments, show all repository branch heads.
3020 3035
3021 3036 Repository "heads" are changesets with no child changesets. They are
3022 3037 where development generally takes place and are the usual targets
3023 3038 for update and merge operations. Branch heads are changesets that have
3024 3039 no child changeset on the same branch.
3025 3040
3026 3041 If one or more REVs are given, only branch heads on the branches
3027 3042 associated with the specified changesets are shown. This means
3028 3043 that you can use :hg:`heads foo` to see the heads on a branch
3029 3044 named ``foo``.
3030 3045
3031 3046 If -c/--closed is specified, also show branch heads marked closed
3032 3047 (see :hg:`commit --close-branch`).
3033 3048
3034 3049 If STARTREV is specified, only those heads that are descendants of
3035 3050 STARTREV will be displayed.
3036 3051
3037 3052 If -t/--topo is specified, named branch mechanics will be ignored and only
3038 3053 changesets without children will be shown.
3039 3054
3040 3055 Returns 0 if matching heads are found, 1 if not.
3041 3056 """
3042 3057
3043 3058 start = None
3044 3059 if 'rev' in opts:
3045 3060 start = scmutil.revsingle(repo, opts['rev'], None).node()
3046 3061
3047 3062 if opts.get('topo'):
3048 3063 heads = [repo[h] for h in repo.heads(start)]
3049 3064 else:
3050 3065 heads = []
3051 3066 for branch in repo.branchmap():
3052 3067 heads += repo.branchheads(branch, start, opts.get('closed'))
3053 3068 heads = [repo[h] for h in heads]
3054 3069
3055 3070 if branchrevs:
3056 3071 branches = set(repo[br].branch() for br in branchrevs)
3057 3072 heads = [h for h in heads if h.branch() in branches]
3058 3073
3059 3074 if opts.get('active') and branchrevs:
3060 3075 dagheads = repo.heads(start)
3061 3076 heads = [h for h in heads if h.node() in dagheads]
3062 3077
3063 3078 if branchrevs:
3064 3079 haveheads = set(h.branch() for h in heads)
3065 3080 if branches - haveheads:
3066 3081 headless = ', '.join(b for b in branches - haveheads)
3067 3082 msg = _('no open branch heads found on branches %s')
3068 3083 if opts.get('rev'):
3069 3084 msg += _(' (started at %s)') % opts['rev']
3070 3085 ui.warn((msg + '\n') % headless)
3071 3086
3072 3087 if not heads:
3073 3088 return 1
3074 3089
3075 3090 heads = sorted(heads, key=lambda x: -x.rev())
3076 3091 displayer = cmdutil.show_changeset(ui, repo, opts)
3077 3092 for ctx in heads:
3078 3093 displayer.show(ctx)
3079 3094 displayer.close()
3080 3095
3081 3096 @command('help',
3082 3097 [('e', 'extension', None, _('show only help for extensions')),
3083 3098 ('c', 'command', None, _('show only help for commands')),
3084 3099 ('k', 'keyword', '', _('show topics matching keyword')),
3085 3100 ],
3086 3101 _('[-ec] [TOPIC]'))
3087 3102 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3088 3103 """show help for a given topic or a help overview
3089 3104
3090 3105 With no arguments, print a list of commands with short help messages.
3091 3106
3092 3107 Given a topic, extension, or command name, print help for that
3093 3108 topic.
3094 3109
3095 3110 Returns 0 if successful.
3096 3111 """
3097 3112
3098 3113 textwidth = min(ui.termwidth(), 80) - 2
3099 3114
3100 3115 def helpcmd(name):
3101 3116 try:
3102 3117 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3103 3118 except error.AmbiguousCommand, inst:
3104 3119 # py3k fix: except vars can't be used outside the scope of the
3105 3120 # except block, nor can be used inside a lambda. python issue4617
3106 3121 prefix = inst.args[0]
3107 3122 select = lambda c: c.lstrip('^').startswith(prefix)
3108 3123 rst = helplist(select)
3109 3124 return rst
3110 3125
3111 3126 rst = []
3112 3127
3113 3128 # check if it's an invalid alias and display its error if it is
3114 3129 if getattr(entry[0], 'badalias', False):
3115 3130 if not unknowncmd:
3116 3131 ui.pushbuffer()
3117 3132 entry[0](ui)
3118 3133 rst.append(ui.popbuffer())
3119 3134 return rst
3120 3135
3121 3136 # synopsis
3122 3137 if len(entry) > 2:
3123 3138 if entry[2].startswith('hg'):
3124 3139 rst.append("%s\n" % entry[2])
3125 3140 else:
3126 3141 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3127 3142 else:
3128 3143 rst.append('hg %s\n' % aliases[0])
3129 3144 # aliases
3130 3145 if full and not ui.quiet and len(aliases) > 1:
3131 3146 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3132 3147 rst.append('\n')
3133 3148
3134 3149 # description
3135 3150 doc = gettext(entry[0].__doc__)
3136 3151 if not doc:
3137 3152 doc = _("(no help text available)")
3138 3153 if util.safehasattr(entry[0], 'definition'): # aliased command
3139 3154 if entry[0].definition.startswith('!'): # shell alias
3140 3155 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3141 3156 else:
3142 3157 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3143 3158 doc = doc.splitlines(True)
3144 3159 if ui.quiet or not full:
3145 3160 rst.append(doc[0])
3146 3161 else:
3147 3162 rst.extend(doc)
3148 3163 rst.append('\n')
3149 3164
3150 3165 # check if this command shadows a non-trivial (multi-line)
3151 3166 # extension help text
3152 3167 try:
3153 3168 mod = extensions.find(name)
3154 3169 doc = gettext(mod.__doc__) or ''
3155 3170 if '\n' in doc.strip():
3156 3171 msg = _('use "hg help -e %s" to show help for '
3157 3172 'the %s extension') % (name, name)
3158 3173 rst.append('\n%s\n' % msg)
3159 3174 except KeyError:
3160 3175 pass
3161 3176
3162 3177 # options
3163 3178 if not ui.quiet and entry[1]:
3164 3179 rst.append('\n%s\n\n' % _("options:"))
3165 3180 rst.append(help.optrst(entry[1], ui.verbose))
3166 3181
3167 3182 if ui.verbose:
3168 3183 rst.append('\n%s\n\n' % _("global options:"))
3169 3184 rst.append(help.optrst(globalopts, ui.verbose))
3170 3185
3171 3186 if not ui.verbose:
3172 3187 if not full:
3173 3188 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3174 3189 % name)
3175 3190 elif not ui.quiet:
3176 3191 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3177 3192 % name)
3178 3193 return rst
3179 3194
3180 3195
3181 3196 def helplist(select=None):
3182 3197 # list of commands
3183 3198 if name == "shortlist":
3184 3199 header = _('basic commands:\n\n')
3185 3200 else:
3186 3201 header = _('list of commands:\n\n')
3187 3202
3188 3203 h = {}
3189 3204 cmds = {}
3190 3205 for c, e in table.iteritems():
3191 3206 f = c.split("|", 1)[0]
3192 3207 if select and not select(f):
3193 3208 continue
3194 3209 if (not select and name != 'shortlist' and
3195 3210 e[0].__module__ != __name__):
3196 3211 continue
3197 3212 if name == "shortlist" and not f.startswith("^"):
3198 3213 continue
3199 3214 f = f.lstrip("^")
3200 3215 if not ui.debugflag and f.startswith("debug"):
3201 3216 continue
3202 3217 doc = e[0].__doc__
3203 3218 if doc and 'DEPRECATED' in doc and not ui.verbose:
3204 3219 continue
3205 3220 doc = gettext(doc)
3206 3221 if not doc:
3207 3222 doc = _("(no help text available)")
3208 3223 h[f] = doc.splitlines()[0].rstrip()
3209 3224 cmds[f] = c.lstrip("^")
3210 3225
3211 3226 rst = []
3212 3227 if not h:
3213 3228 if not ui.quiet:
3214 3229 rst.append(_('no commands defined\n'))
3215 3230 return rst
3216 3231
3217 3232 if not ui.quiet:
3218 3233 rst.append(header)
3219 3234 fns = sorted(h)
3220 3235 for f in fns:
3221 3236 if ui.verbose:
3222 3237 commands = cmds[f].replace("|",", ")
3223 3238 rst.append(" :%s: %s\n" % (commands, h[f]))
3224 3239 else:
3225 3240 rst.append(' :%s: %s\n' % (f, h[f]))
3226 3241
3227 3242 if not name:
3228 3243 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3229 3244 if exts:
3230 3245 rst.append('\n')
3231 3246 rst.extend(exts)
3232 3247
3233 3248 rst.append(_("\nadditional help topics:\n\n"))
3234 3249 topics = []
3235 3250 for names, header, doc in help.helptable:
3236 3251 topics.append((sorted(names, key=len, reverse=True)[0], header))
3237 3252 for t, desc in topics:
3238 3253 rst.append(" :%s: %s\n" % (t, desc))
3239 3254
3240 3255 optlist = []
3241 3256 if not ui.quiet:
3242 3257 if ui.verbose:
3243 3258 optlist.append((_("global options:"), globalopts))
3244 3259 if name == 'shortlist':
3245 3260 optlist.append((_('use "hg help" for the full list '
3246 3261 'of commands'), ()))
3247 3262 else:
3248 3263 if name == 'shortlist':
3249 3264 msg = _('use "hg help" for the full list of commands '
3250 3265 'or "hg -v" for details')
3251 3266 elif name and not full:
3252 3267 msg = _('use "hg help %s" to show the full help '
3253 3268 'text') % name
3254 3269 else:
3255 3270 msg = _('use "hg -v help%s" to show builtin aliases and '
3256 3271 'global options') % (name and " " + name or "")
3257 3272 optlist.append((msg, ()))
3258 3273
3259 3274 if optlist:
3260 3275 for title, options in optlist:
3261 3276 rst.append('\n%s\n' % title)
3262 3277 if options:
3263 3278 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3264 3279 return rst
3265 3280
3266 3281 def helptopic(name):
3267 3282 for names, header, doc in help.helptable:
3268 3283 if name in names:
3269 3284 break
3270 3285 else:
3271 3286 raise error.UnknownCommand(name)
3272 3287
3273 3288 rst = ["%s\n\n" % header]
3274 3289 # description
3275 3290 if not doc:
3276 3291 rst.append(" %s\n" % _("(no help text available)"))
3277 3292 if util.safehasattr(doc, '__call__'):
3278 3293 rst += [" %s\n" % l for l in doc().splitlines()]
3279 3294
3280 3295 try:
3281 3296 cmdutil.findcmd(name, table)
3282 3297 rst.append(_('\nuse "hg help -c %s" to see help for '
3283 3298 'the %s command\n') % (name, name))
3284 3299 except error.UnknownCommand:
3285 3300 pass
3286 3301 return rst
3287 3302
3288 3303 def helpext(name):
3289 3304 try:
3290 3305 mod = extensions.find(name)
3291 3306 doc = gettext(mod.__doc__) or _('no help text available')
3292 3307 except KeyError:
3293 3308 mod = None
3294 3309 doc = extensions.disabledext(name)
3295 3310 if not doc:
3296 3311 raise error.UnknownCommand(name)
3297 3312
3298 3313 if '\n' not in doc:
3299 3314 head, tail = doc, ""
3300 3315 else:
3301 3316 head, tail = doc.split('\n', 1)
3302 3317 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3303 3318 if tail:
3304 3319 rst.extend(tail.splitlines(True))
3305 3320 rst.append('\n')
3306 3321
3307 3322 if mod:
3308 3323 try:
3309 3324 ct = mod.cmdtable
3310 3325 except AttributeError:
3311 3326 ct = {}
3312 3327 modcmds = set([c.split('|', 1)[0] for c in ct])
3313 3328 rst.extend(helplist(modcmds.__contains__))
3314 3329 else:
3315 3330 rst.append(_('use "hg help extensions" for information on enabling '
3316 3331 'extensions\n'))
3317 3332 return rst
3318 3333
3319 3334 def helpextcmd(name):
3320 3335 cmd, ext, mod = extensions.disabledcmd(ui, name,
3321 3336 ui.configbool('ui', 'strict'))
3322 3337 doc = gettext(mod.__doc__).splitlines()[0]
3323 3338
3324 3339 rst = help.listexts(_("'%s' is provided by the following "
3325 3340 "extension:") % cmd, {ext: doc}, indent=4)
3326 3341 rst.append('\n')
3327 3342 rst.append(_('use "hg help extensions" for information on enabling '
3328 3343 'extensions\n'))
3329 3344 return rst
3330 3345
3331 3346
3332 3347 rst = []
3333 3348 kw = opts.get('keyword')
3334 3349 if kw:
3335 3350 matches = help.topicmatch(kw)
3336 3351 for t, title in (('topics', _('Topics')),
3337 3352 ('commands', _('Commands')),
3338 3353 ('extensions', _('Extensions')),
3339 3354 ('extensioncommands', _('Extension Commands'))):
3340 3355 if matches[t]:
3341 3356 rst.append('%s:\n\n' % title)
3342 3357 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3343 3358 rst.append('\n')
3344 3359 elif name and name != 'shortlist':
3345 3360 i = None
3346 3361 if unknowncmd:
3347 3362 queries = (helpextcmd,)
3348 3363 elif opts.get('extension'):
3349 3364 queries = (helpext,)
3350 3365 elif opts.get('command'):
3351 3366 queries = (helpcmd,)
3352 3367 else:
3353 3368 queries = (helptopic, helpcmd, helpext, helpextcmd)
3354 3369 for f in queries:
3355 3370 try:
3356 3371 rst = f(name)
3357 3372 i = None
3358 3373 break
3359 3374 except error.UnknownCommand, inst:
3360 3375 i = inst
3361 3376 if i:
3362 3377 raise i
3363 3378 else:
3364 3379 # program name
3365 3380 if not ui.quiet:
3366 3381 rst = [_("Mercurial Distributed SCM\n"), '\n']
3367 3382 rst.extend(helplist())
3368 3383
3369 3384 keep = ui.verbose and ['verbose'] or []
3370 3385 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3371 3386 ui.write(formatted)
3372 3387
3373 3388
3374 3389 @command('identify|id',
3375 3390 [('r', 'rev', '',
3376 3391 _('identify the specified revision'), _('REV')),
3377 3392 ('n', 'num', None, _('show local revision number')),
3378 3393 ('i', 'id', None, _('show global revision id')),
3379 3394 ('b', 'branch', None, _('show branch')),
3380 3395 ('t', 'tags', None, _('show tags')),
3381 3396 ('B', 'bookmarks', None, _('show bookmarks')),
3382 3397 ] + remoteopts,
3383 3398 _('[-nibtB] [-r REV] [SOURCE]'))
3384 3399 def identify(ui, repo, source=None, rev=None,
3385 3400 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3386 3401 """identify the working copy or specified revision
3387 3402
3388 3403 Print a summary identifying the repository state at REV using one or
3389 3404 two parent hash identifiers, followed by a "+" if the working
3390 3405 directory has uncommitted changes, the branch name (if not default),
3391 3406 a list of tags, and a list of bookmarks.
3392 3407
3393 3408 When REV is not given, print a summary of the current state of the
3394 3409 repository.
3395 3410
3396 3411 Specifying a path to a repository root or Mercurial bundle will
3397 3412 cause lookup to operate on that repository/bundle.
3398 3413
3399 3414 .. container:: verbose
3400 3415
3401 3416 Examples:
3402 3417
3403 3418 - generate a build identifier for the working directory::
3404 3419
3405 3420 hg id --id > build-id.dat
3406 3421
3407 3422 - find the revision corresponding to a tag::
3408 3423
3409 3424 hg id -n -r 1.3
3410 3425
3411 3426 - check the most recent revision of a remote repository::
3412 3427
3413 3428 hg id -r tip http://selenic.com/hg/
3414 3429
3415 3430 Returns 0 if successful.
3416 3431 """
3417 3432
3418 3433 if not repo and not source:
3419 3434 raise util.Abort(_("there is no Mercurial repository here "
3420 3435 "(.hg not found)"))
3421 3436
3422 3437 hexfunc = ui.debugflag and hex or short
3423 3438 default = not (num or id or branch or tags or bookmarks)
3424 3439 output = []
3425 3440 revs = []
3426 3441
3427 3442 if source:
3428 3443 source, branches = hg.parseurl(ui.expandpath(source))
3429 3444 repo = hg.peer(ui, opts, source)
3430 3445 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3431 3446
3432 3447 if not repo.local():
3433 3448 if num or branch or tags:
3434 3449 raise util.Abort(
3435 3450 _("can't query remote revision number, branch, or tags"))
3436 3451 if not rev and revs:
3437 3452 rev = revs[0]
3438 3453 if not rev:
3439 3454 rev = "tip"
3440 3455
3441 3456 remoterev = repo.lookup(rev)
3442 3457 if default or id:
3443 3458 output = [hexfunc(remoterev)]
3444 3459
3445 3460 def getbms():
3446 3461 bms = []
3447 3462
3448 3463 if 'bookmarks' in repo.listkeys('namespaces'):
3449 3464 hexremoterev = hex(remoterev)
3450 3465 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3451 3466 if bmr == hexremoterev]
3452 3467
3453 3468 return bms
3454 3469
3455 3470 if bookmarks:
3456 3471 output.extend(getbms())
3457 3472 elif default and not ui.quiet:
3458 3473 # multiple bookmarks for a single parent separated by '/'
3459 3474 bm = '/'.join(getbms())
3460 3475 if bm:
3461 3476 output.append(bm)
3462 3477 else:
3463 3478 if not rev:
3464 3479 ctx = repo[None]
3465 3480 parents = ctx.parents()
3466 3481 changed = ""
3467 3482 if default or id or num:
3468 3483 changed = util.any(repo.status()) and "+" or ""
3469 3484 if default or id:
3470 3485 output = ["%s%s" %
3471 3486 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3472 3487 if num:
3473 3488 output.append("%s%s" %
3474 3489 ('+'.join([str(p.rev()) for p in parents]), changed))
3475 3490 else:
3476 3491 ctx = scmutil.revsingle(repo, rev)
3477 3492 if default or id:
3478 3493 output = [hexfunc(ctx.node())]
3479 3494 if num:
3480 3495 output.append(str(ctx.rev()))
3481 3496
3482 3497 if default and not ui.quiet:
3483 3498 b = ctx.branch()
3484 3499 if b != 'default':
3485 3500 output.append("(%s)" % b)
3486 3501
3487 3502 # multiple tags for a single parent separated by '/'
3488 3503 t = '/'.join(ctx.tags())
3489 3504 if t:
3490 3505 output.append(t)
3491 3506
3492 3507 # multiple bookmarks for a single parent separated by '/'
3493 3508 bm = '/'.join(ctx.bookmarks())
3494 3509 if bm:
3495 3510 output.append(bm)
3496 3511 else:
3497 3512 if branch:
3498 3513 output.append(ctx.branch())
3499 3514
3500 3515 if tags:
3501 3516 output.extend(ctx.tags())
3502 3517
3503 3518 if bookmarks:
3504 3519 output.extend(ctx.bookmarks())
3505 3520
3506 3521 ui.write("%s\n" % ' '.join(output))
3507 3522
3508 3523 @command('import|patch',
3509 3524 [('p', 'strip', 1,
3510 3525 _('directory strip option for patch. This has the same '
3511 3526 'meaning as the corresponding patch option'), _('NUM')),
3512 3527 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3513 3528 ('e', 'edit', False, _('invoke editor on commit messages')),
3514 3529 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3515 3530 ('', 'no-commit', None,
3516 3531 _("don't commit, just update the working directory")),
3517 3532 ('', 'bypass', None,
3518 3533 _("apply patch without touching the working directory")),
3519 3534 ('', 'exact', None,
3520 3535 _('apply patch to the nodes from which it was generated')),
3521 3536 ('', 'import-branch', None,
3522 3537 _('use any branch information in patch (implied by --exact)'))] +
3523 3538 commitopts + commitopts2 + similarityopts,
3524 3539 _('[OPTION]... PATCH...'))
3525 3540 def import_(ui, repo, patch1=None, *patches, **opts):
3526 3541 """import an ordered set of patches
3527 3542
3528 3543 Import a list of patches and commit them individually (unless
3529 3544 --no-commit is specified).
3530 3545
3531 3546 If there are outstanding changes in the working directory, import
3532 3547 will abort unless given the -f/--force flag.
3533 3548
3534 3549 You can import a patch straight from a mail message. Even patches
3535 3550 as attachments work (to use the body part, it must have type
3536 3551 text/plain or text/x-patch). From and Subject headers of email
3537 3552 message are used as default committer and commit message. All
3538 3553 text/plain body parts before first diff are added to commit
3539 3554 message.
3540 3555
3541 3556 If the imported patch was generated by :hg:`export`, user and
3542 3557 description from patch override values from message headers and
3543 3558 body. Values given on command line with -m/--message and -u/--user
3544 3559 override these.
3545 3560
3546 3561 If --exact is specified, import will set the working directory to
3547 3562 the parent of each patch before applying it, and will abort if the
3548 3563 resulting changeset has a different ID than the one recorded in
3549 3564 the patch. This may happen due to character set problems or other
3550 3565 deficiencies in the text patch format.
3551 3566
3552 3567 Use --bypass to apply and commit patches directly to the
3553 3568 repository, not touching the working directory. Without --exact,
3554 3569 patches will be applied on top of the working directory parent
3555 3570 revision.
3556 3571
3557 3572 With -s/--similarity, hg will attempt to discover renames and
3558 3573 copies in the patch in the same way as :hg:`addremove`.
3559 3574
3560 3575 To read a patch from standard input, use "-" as the patch name. If
3561 3576 a URL is specified, the patch will be downloaded from it.
3562 3577 See :hg:`help dates` for a list of formats valid for -d/--date.
3563 3578
3564 3579 .. container:: verbose
3565 3580
3566 3581 Examples:
3567 3582
3568 3583 - import a traditional patch from a website and detect renames::
3569 3584
3570 3585 hg import -s 80 http://example.com/bugfix.patch
3571 3586
3572 3587 - import a changeset from an hgweb server::
3573 3588
3574 3589 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3575 3590
3576 3591 - import all the patches in an Unix-style mbox::
3577 3592
3578 3593 hg import incoming-patches.mbox
3579 3594
3580 3595 - attempt to exactly restore an exported changeset (not always
3581 3596 possible)::
3582 3597
3583 3598 hg import --exact proposed-fix.patch
3584 3599
3585 3600 Returns 0 on success.
3586 3601 """
3587 3602
3588 3603 if not patch1:
3589 3604 raise util.Abort(_('need at least one patch to import'))
3590 3605
3591 3606 patches = (patch1,) + patches
3592 3607
3593 3608 date = opts.get('date')
3594 3609 if date:
3595 3610 opts['date'] = util.parsedate(date)
3596 3611
3597 3612 editor = cmdutil.commiteditor
3598 3613 if opts.get('edit'):
3599 3614 editor = cmdutil.commitforceeditor
3600 3615
3601 3616 update = not opts.get('bypass')
3602 3617 if not update and opts.get('no_commit'):
3603 3618 raise util.Abort(_('cannot use --no-commit with --bypass'))
3604 3619 try:
3605 3620 sim = float(opts.get('similarity') or 0)
3606 3621 except ValueError:
3607 3622 raise util.Abort(_('similarity must be a number'))
3608 3623 if sim < 0 or sim > 100:
3609 3624 raise util.Abort(_('similarity must be between 0 and 100'))
3610 3625 if sim and not update:
3611 3626 raise util.Abort(_('cannot use --similarity with --bypass'))
3612 3627
3613 3628 if (opts.get('exact') or not opts.get('force')) and update:
3614 3629 cmdutil.bailifchanged(repo)
3615 3630
3616 3631 base = opts["base"]
3617 3632 strip = opts["strip"]
3618 3633 wlock = lock = tr = None
3619 3634 msgs = []
3620 3635
3621 3636 def checkexact(repo, n, nodeid):
3622 3637 if opts.get('exact') and hex(n) != nodeid:
3623 3638 repo.rollback()
3624 3639 raise util.Abort(_('patch is damaged or loses information'))
3625 3640
3626 3641 def tryone(ui, hunk, parents):
3627 3642 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3628 3643 patch.extract(ui, hunk)
3629 3644
3630 3645 if not tmpname:
3631 3646 return (None, None)
3632 3647 msg = _('applied to working directory')
3633 3648
3634 3649 try:
3635 3650 cmdline_message = cmdutil.logmessage(ui, opts)
3636 3651 if cmdline_message:
3637 3652 # pickup the cmdline msg
3638 3653 message = cmdline_message
3639 3654 elif message:
3640 3655 # pickup the patch msg
3641 3656 message = message.strip()
3642 3657 else:
3643 3658 # launch the editor
3644 3659 message = None
3645 3660 ui.debug('message:\n%s\n' % message)
3646 3661
3647 3662 if len(parents) == 1:
3648 3663 parents.append(repo[nullid])
3649 3664 if opts.get('exact'):
3650 3665 if not nodeid or not p1:
3651 3666 raise util.Abort(_('not a Mercurial patch'))
3652 3667 p1 = repo[p1]
3653 3668 p2 = repo[p2 or nullid]
3654 3669 elif p2:
3655 3670 try:
3656 3671 p1 = repo[p1]
3657 3672 p2 = repo[p2]
3658 3673 # Without any options, consider p2 only if the
3659 3674 # patch is being applied on top of the recorded
3660 3675 # first parent.
3661 3676 if p1 != parents[0]:
3662 3677 p1 = parents[0]
3663 3678 p2 = repo[nullid]
3664 3679 except error.RepoError:
3665 3680 p1, p2 = parents
3666 3681 else:
3667 3682 p1, p2 = parents
3668 3683
3669 3684 n = None
3670 3685 if update:
3671 3686 if p1 != parents[0]:
3672 3687 hg.clean(repo, p1.node())
3673 3688 if p2 != parents[1]:
3674 3689 repo.setparents(p1.node(), p2.node())
3675 3690
3676 3691 if opts.get('exact') or opts.get('import_branch'):
3677 3692 repo.dirstate.setbranch(branch or 'default')
3678 3693
3679 3694 files = set()
3680 3695 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3681 3696 eolmode=None, similarity=sim / 100.0)
3682 3697 files = list(files)
3683 3698 if opts.get('no_commit'):
3684 3699 if message:
3685 3700 msgs.append(message)
3686 3701 else:
3687 3702 if opts.get('exact') or p2:
3688 3703 # If you got here, you either use --force and know what
3689 3704 # you are doing or used --exact or a merge patch while
3690 3705 # being updated to its first parent.
3691 3706 m = None
3692 3707 else:
3693 3708 m = scmutil.matchfiles(repo, files or [])
3694 3709 n = repo.commit(message, opts.get('user') or user,
3695 3710 opts.get('date') or date, match=m,
3696 3711 editor=editor)
3697 3712 checkexact(repo, n, nodeid)
3698 3713 else:
3699 3714 if opts.get('exact') or opts.get('import_branch'):
3700 3715 branch = branch or 'default'
3701 3716 else:
3702 3717 branch = p1.branch()
3703 3718 store = patch.filestore()
3704 3719 try:
3705 3720 files = set()
3706 3721 try:
3707 3722 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3708 3723 files, eolmode=None)
3709 3724 except patch.PatchError, e:
3710 3725 raise util.Abort(str(e))
3711 3726 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3712 3727 message,
3713 3728 opts.get('user') or user,
3714 3729 opts.get('date') or date,
3715 3730 branch, files, store,
3716 3731 editor=cmdutil.commiteditor)
3717 3732 repo.savecommitmessage(memctx.description())
3718 3733 n = memctx.commit()
3719 3734 checkexact(repo, n, nodeid)
3720 3735 finally:
3721 3736 store.close()
3722 3737 if n:
3723 3738 # i18n: refers to a short changeset id
3724 3739 msg = _('created %s') % short(n)
3725 3740 return (msg, n)
3726 3741 finally:
3727 3742 os.unlink(tmpname)
3728 3743
3729 3744 try:
3730 3745 try:
3731 3746 wlock = repo.wlock()
3732 3747 if not opts.get('no_commit'):
3733 3748 lock = repo.lock()
3734 3749 tr = repo.transaction('import')
3735 3750 parents = repo.parents()
3736 3751 for patchurl in patches:
3737 3752 if patchurl == '-':
3738 3753 ui.status(_('applying patch from stdin\n'))
3739 3754 patchfile = ui.fin
3740 3755 patchurl = 'stdin' # for error message
3741 3756 else:
3742 3757 patchurl = os.path.join(base, patchurl)
3743 3758 ui.status(_('applying %s\n') % patchurl)
3744 3759 patchfile = url.open(ui, patchurl)
3745 3760
3746 3761 haspatch = False
3747 3762 for hunk in patch.split(patchfile):
3748 3763 (msg, node) = tryone(ui, hunk, parents)
3749 3764 if msg:
3750 3765 haspatch = True
3751 3766 ui.note(msg + '\n')
3752 3767 if update or opts.get('exact'):
3753 3768 parents = repo.parents()
3754 3769 else:
3755 3770 parents = [repo[node]]
3756 3771
3757 3772 if not haspatch:
3758 3773 raise util.Abort(_('%s: no diffs found') % patchurl)
3759 3774
3760 3775 if tr:
3761 3776 tr.close()
3762 3777 if msgs:
3763 3778 repo.savecommitmessage('\n* * *\n'.join(msgs))
3764 3779 except: # re-raises
3765 3780 # wlock.release() indirectly calls dirstate.write(): since
3766 3781 # we're crashing, we do not want to change the working dir
3767 3782 # parent after all, so make sure it writes nothing
3768 3783 repo.dirstate.invalidate()
3769 3784 raise
3770 3785 finally:
3771 3786 if tr:
3772 3787 tr.release()
3773 3788 release(lock, wlock)
3774 3789
3775 3790 @command('incoming|in',
3776 3791 [('f', 'force', None,
3777 3792 _('run even if remote repository is unrelated')),
3778 3793 ('n', 'newest-first', None, _('show newest record first')),
3779 3794 ('', 'bundle', '',
3780 3795 _('file to store the bundles into'), _('FILE')),
3781 3796 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3782 3797 ('B', 'bookmarks', False, _("compare bookmarks")),
3783 3798 ('b', 'branch', [],
3784 3799 _('a specific branch you would like to pull'), _('BRANCH')),
3785 3800 ] + logopts + remoteopts + subrepoopts,
3786 3801 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3787 3802 def incoming(ui, repo, source="default", **opts):
3788 3803 """show new changesets found in source
3789 3804
3790 3805 Show new changesets found in the specified path/URL or the default
3791 3806 pull location. These are the changesets that would have been pulled
3792 3807 if a pull at the time you issued this command.
3793 3808
3794 3809 For remote repository, using --bundle avoids downloading the
3795 3810 changesets twice if the incoming is followed by a pull.
3796 3811
3797 3812 See pull for valid source format details.
3798 3813
3799 3814 Returns 0 if there are incoming changes, 1 otherwise.
3800 3815 """
3801 3816 if opts.get('bundle') and opts.get('subrepos'):
3802 3817 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3803 3818
3804 3819 if opts.get('bookmarks'):
3805 3820 source, branches = hg.parseurl(ui.expandpath(source),
3806 3821 opts.get('branch'))
3807 3822 other = hg.peer(repo, opts, source)
3808 3823 if 'bookmarks' not in other.listkeys('namespaces'):
3809 3824 ui.warn(_("remote doesn't support bookmarks\n"))
3810 3825 return 0
3811 3826 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3812 3827 return bookmarks.diff(ui, repo, other)
3813 3828
3814 3829 repo._subtoppath = ui.expandpath(source)
3815 3830 try:
3816 3831 return hg.incoming(ui, repo, source, opts)
3817 3832 finally:
3818 3833 del repo._subtoppath
3819 3834
3820 3835
3821 3836 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3822 3837 def init(ui, dest=".", **opts):
3823 3838 """create a new repository in the given directory
3824 3839
3825 3840 Initialize a new repository in the given directory. If the given
3826 3841 directory does not exist, it will be created.
3827 3842
3828 3843 If no directory is given, the current directory is used.
3829 3844
3830 3845 It is possible to specify an ``ssh://`` URL as the destination.
3831 3846 See :hg:`help urls` for more information.
3832 3847
3833 3848 Returns 0 on success.
3834 3849 """
3835 3850 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3836 3851
3837 3852 @command('locate',
3838 3853 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3839 3854 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3840 3855 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3841 3856 ] + walkopts,
3842 3857 _('[OPTION]... [PATTERN]...'))
3843 3858 def locate(ui, repo, *pats, **opts):
3844 3859 """locate files matching specific patterns
3845 3860
3846 3861 Print files under Mercurial control in the working directory whose
3847 3862 names match the given patterns.
3848 3863
3849 3864 By default, this command searches all directories in the working
3850 3865 directory. To search just the current directory and its
3851 3866 subdirectories, use "--include .".
3852 3867
3853 3868 If no patterns are given to match, this command prints the names
3854 3869 of all files under Mercurial control in the working directory.
3855 3870
3856 3871 If you want to feed the output of this command into the "xargs"
3857 3872 command, use the -0 option to both this command and "xargs". This
3858 3873 will avoid the problem of "xargs" treating single filenames that
3859 3874 contain whitespace as multiple filenames.
3860 3875
3861 3876 Returns 0 if a match is found, 1 otherwise.
3862 3877 """
3863 3878 end = opts.get('print0') and '\0' or '\n'
3864 3879 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3865 3880
3866 3881 ret = 1
3867 3882 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3868 3883 m.bad = lambda x, y: False
3869 3884 for abs in repo[rev].walk(m):
3870 3885 if not rev and abs not in repo.dirstate:
3871 3886 continue
3872 3887 if opts.get('fullpath'):
3873 3888 ui.write(repo.wjoin(abs), end)
3874 3889 else:
3875 3890 ui.write(((pats and m.rel(abs)) or abs), end)
3876 3891 ret = 0
3877 3892
3878 3893 return ret
3879 3894
3880 3895 @command('^log|history',
3881 3896 [('f', 'follow', None,
3882 3897 _('follow changeset history, or file history across copies and renames')),
3883 3898 ('', 'follow-first', None,
3884 3899 _('only follow the first parent of merge changesets (DEPRECATED)')),
3885 3900 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3886 3901 ('C', 'copies', None, _('show copied files')),
3887 3902 ('k', 'keyword', [],
3888 3903 _('do case-insensitive search for a given text'), _('TEXT')),
3889 3904 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3890 3905 ('', 'removed', None, _('include revisions where files were removed')),
3891 3906 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3892 3907 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3893 3908 ('', 'only-branch', [],
3894 3909 _('show only changesets within the given named branch (DEPRECATED)'),
3895 3910 _('BRANCH')),
3896 3911 ('b', 'branch', [],
3897 3912 _('show changesets within the given named branch'), _('BRANCH')),
3898 3913 ('P', 'prune', [],
3899 3914 _('do not display revision or any of its ancestors'), _('REV')),
3900 3915 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3901 3916 ] + logopts + walkopts,
3902 3917 _('[OPTION]... [FILE]'))
3903 3918 def log(ui, repo, *pats, **opts):
3904 3919 """show revision history of entire repository or files
3905 3920
3906 3921 Print the revision history of the specified files or the entire
3907 3922 project.
3908 3923
3909 3924 If no revision range is specified, the default is ``tip:0`` unless
3910 3925 --follow is set, in which case the working directory parent is
3911 3926 used as the starting revision.
3912 3927
3913 3928 File history is shown without following rename or copy history of
3914 3929 files. Use -f/--follow with a filename to follow history across
3915 3930 renames and copies. --follow without a filename will only show
3916 3931 ancestors or descendants of the starting revision.
3917 3932
3918 3933 By default this command prints revision number and changeset id,
3919 3934 tags, non-trivial parents, user, date and time, and a summary for
3920 3935 each commit. When the -v/--verbose switch is used, the list of
3921 3936 changed files and full commit message are shown.
3922 3937
3923 3938 .. note::
3924 3939 log -p/--patch may generate unexpected diff output for merge
3925 3940 changesets, as it will only compare the merge changeset against
3926 3941 its first parent. Also, only files different from BOTH parents
3927 3942 will appear in files:.
3928 3943
3929 3944 .. note::
3930 3945 for performance reasons, log FILE may omit duplicate changes
3931 3946 made on branches and will not show deletions. To see all
3932 3947 changes including duplicates and deletions, use the --removed
3933 3948 switch.
3934 3949
3935 3950 .. container:: verbose
3936 3951
3937 3952 Some examples:
3938 3953
3939 3954 - changesets with full descriptions and file lists::
3940 3955
3941 3956 hg log -v
3942 3957
3943 3958 - changesets ancestral to the working directory::
3944 3959
3945 3960 hg log -f
3946 3961
3947 3962 - last 10 commits on the current branch::
3948 3963
3949 3964 hg log -l 10 -b .
3950 3965
3951 3966 - changesets showing all modifications of a file, including removals::
3952 3967
3953 3968 hg log --removed file.c
3954 3969
3955 3970 - all changesets that touch a directory, with diffs, excluding merges::
3956 3971
3957 3972 hg log -Mp lib/
3958 3973
3959 3974 - all revision numbers that match a keyword::
3960 3975
3961 3976 hg log -k bug --template "{rev}\\n"
3962 3977
3963 3978 - check if a given changeset is included is a tagged release::
3964 3979
3965 3980 hg log -r "a21ccf and ancestor(1.9)"
3966 3981
3967 3982 - find all changesets by some user in a date range::
3968 3983
3969 3984 hg log -k alice -d "may 2008 to jul 2008"
3970 3985
3971 3986 - summary of all changesets after the last tag::
3972 3987
3973 3988 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3974 3989
3975 3990 See :hg:`help dates` for a list of formats valid for -d/--date.
3976 3991
3977 3992 See :hg:`help revisions` and :hg:`help revsets` for more about
3978 3993 specifying revisions.
3979 3994
3980 3995 See :hg:`help templates` for more about pre-packaged styles and
3981 3996 specifying custom templates.
3982 3997
3983 3998 Returns 0 on success.
3984 3999 """
3985 4000
3986 4001 matchfn = scmutil.match(repo[None], pats, opts)
3987 4002 limit = cmdutil.loglimit(opts)
3988 4003 count = 0
3989 4004
3990 4005 getrenamed, endrev = None, None
3991 4006 if opts.get('copies'):
3992 4007 if opts.get('rev'):
3993 4008 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3994 4009 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3995 4010
3996 4011 df = False
3997 4012 if opts["date"]:
3998 4013 df = util.matchdate(opts["date"])
3999 4014
4000 4015 branches = opts.get('branch', []) + opts.get('only_branch', [])
4001 4016 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4002 4017
4003 4018 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4004 4019 def prep(ctx, fns):
4005 4020 rev = ctx.rev()
4006 4021 parents = [p for p in repo.changelog.parentrevs(rev)
4007 4022 if p != nullrev]
4008 4023 if opts.get('no_merges') and len(parents) == 2:
4009 4024 return
4010 4025 if opts.get('only_merges') and len(parents) != 2:
4011 4026 return
4012 4027 if opts.get('branch') and ctx.branch() not in opts['branch']:
4013 4028 return
4014 4029 if not opts.get('hidden') and ctx.hidden():
4015 4030 return
4016 4031 if df and not df(ctx.date()[0]):
4017 4032 return
4018 4033
4019 4034 lower = encoding.lower
4020 4035 if opts.get('user'):
4021 4036 luser = lower(ctx.user())
4022 4037 for k in [lower(x) for x in opts['user']]:
4023 4038 if (k in luser):
4024 4039 break
4025 4040 else:
4026 4041 return
4027 4042 if opts.get('keyword'):
4028 4043 luser = lower(ctx.user())
4029 4044 ldesc = lower(ctx.description())
4030 4045 lfiles = lower(" ".join(ctx.files()))
4031 4046 for k in [lower(x) for x in opts['keyword']]:
4032 4047 if (k in luser or k in ldesc or k in lfiles):
4033 4048 break
4034 4049 else:
4035 4050 return
4036 4051
4037 4052 copies = None
4038 4053 if getrenamed is not None and rev:
4039 4054 copies = []
4040 4055 for fn in ctx.files():
4041 4056 rename = getrenamed(fn, rev)
4042 4057 if rename:
4043 4058 copies.append((fn, rename[0]))
4044 4059
4045 4060 revmatchfn = None
4046 4061 if opts.get('patch') or opts.get('stat'):
4047 4062 if opts.get('follow') or opts.get('follow_first'):
4048 4063 # note: this might be wrong when following through merges
4049 4064 revmatchfn = scmutil.match(repo[None], fns, default='path')
4050 4065 else:
4051 4066 revmatchfn = matchfn
4052 4067
4053 4068 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4054 4069
4055 4070 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4056 4071 if count == limit:
4057 4072 break
4058 4073 if displayer.flush(ctx.rev()):
4059 4074 count += 1
4060 4075 displayer.close()
4061 4076
4062 4077 @command('manifest',
4063 4078 [('r', 'rev', '', _('revision to display'), _('REV')),
4064 4079 ('', 'all', False, _("list files from all revisions"))],
4065 4080 _('[-r REV]'))
4066 4081 def manifest(ui, repo, node=None, rev=None, **opts):
4067 4082 """output the current or given revision of the project manifest
4068 4083
4069 4084 Print a list of version controlled files for the given revision.
4070 4085 If no revision is given, the first parent of the working directory
4071 4086 is used, or the null revision if no revision is checked out.
4072 4087
4073 4088 With -v, print file permissions, symlink and executable bits.
4074 4089 With --debug, print file revision hashes.
4075 4090
4076 4091 If option --all is specified, the list of all files from all revisions
4077 4092 is printed. This includes deleted and renamed files.
4078 4093
4079 4094 Returns 0 on success.
4080 4095 """
4081 4096 if opts.get('all'):
4082 4097 if rev or node:
4083 4098 raise util.Abort(_("can't specify a revision with --all"))
4084 4099
4085 4100 res = []
4086 4101 prefix = "data/"
4087 4102 suffix = ".i"
4088 4103 plen = len(prefix)
4089 4104 slen = len(suffix)
4090 4105 lock = repo.lock()
4091 4106 try:
4092 4107 for fn, b, size in repo.store.datafiles():
4093 4108 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4094 4109 res.append(fn[plen:-slen])
4095 4110 finally:
4096 4111 lock.release()
4097 4112 for f in sorted(res):
4098 4113 ui.write("%s\n" % f)
4099 4114 return
4100 4115
4101 4116 if rev and node:
4102 4117 raise util.Abort(_("please specify just one revision"))
4103 4118
4104 4119 if not node:
4105 4120 node = rev
4106 4121
4107 4122 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4108 4123 ctx = scmutil.revsingle(repo, node)
4109 4124 for f in ctx:
4110 4125 if ui.debugflag:
4111 4126 ui.write("%40s " % hex(ctx.manifest()[f]))
4112 4127 if ui.verbose:
4113 4128 ui.write(decor[ctx.flags(f)])
4114 4129 ui.write("%s\n" % f)
4115 4130
4116 4131 @command('^merge',
4117 4132 [('f', 'force', None, _('force a merge with outstanding changes')),
4118 4133 ('r', 'rev', '', _('revision to merge'), _('REV')),
4119 4134 ('P', 'preview', None,
4120 4135 _('review revisions to merge (no merge is performed)'))
4121 4136 ] + mergetoolopts,
4122 4137 _('[-P] [-f] [[-r] REV]'))
4123 4138 def merge(ui, repo, node=None, **opts):
4124 4139 """merge working directory with another revision
4125 4140
4126 4141 The current working directory is updated with all changes made in
4127 4142 the requested revision since the last common predecessor revision.
4128 4143
4129 4144 Files that changed between either parent are marked as changed for
4130 4145 the next commit and a commit must be performed before any further
4131 4146 updates to the repository are allowed. The next commit will have
4132 4147 two parents.
4133 4148
4134 4149 ``--tool`` can be used to specify the merge tool used for file
4135 4150 merges. It overrides the HGMERGE environment variable and your
4136 4151 configuration files. See :hg:`help merge-tools` for options.
4137 4152
4138 4153 If no revision is specified, the working directory's parent is a
4139 4154 head revision, and the current branch contains exactly one other
4140 4155 head, the other head is merged with by default. Otherwise, an
4141 4156 explicit revision with which to merge with must be provided.
4142 4157
4143 4158 :hg:`resolve` must be used to resolve unresolved files.
4144 4159
4145 4160 To undo an uncommitted merge, use :hg:`update --clean .` which
4146 4161 will check out a clean copy of the original merge parent, losing
4147 4162 all changes.
4148 4163
4149 4164 Returns 0 on success, 1 if there are unresolved files.
4150 4165 """
4151 4166
4152 4167 if opts.get('rev') and node:
4153 4168 raise util.Abort(_("please specify just one revision"))
4154 4169 if not node:
4155 4170 node = opts.get('rev')
4156 4171
4157 4172 if node:
4158 4173 node = scmutil.revsingle(repo, node).node()
4159 4174
4160 4175 if not node and repo._bookmarkcurrent:
4161 4176 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4162 4177 curhead = repo[repo._bookmarkcurrent]
4163 4178 if len(bmheads) == 2:
4164 4179 if curhead == bmheads[0]:
4165 4180 node = bmheads[1]
4166 4181 else:
4167 4182 node = bmheads[0]
4168 4183 elif len(bmheads) > 2:
4169 4184 raise util.Abort(_("multiple matching bookmarks to merge - "
4170 4185 "please merge with an explicit rev or bookmark"),
4171 4186 hint=_("run 'hg heads' to see all heads"))
4172 4187 elif len(bmheads) <= 1:
4173 4188 raise util.Abort(_("no matching bookmark to merge - "
4174 4189 "please merge with an explicit rev or bookmark"),
4175 4190 hint=_("run 'hg heads' to see all heads"))
4176 4191
4177 4192 if not node and not repo._bookmarkcurrent:
4178 4193 branch = repo[None].branch()
4179 4194 bheads = repo.branchheads(branch)
4180 4195 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4181 4196
4182 4197 if len(nbhs) > 2:
4183 4198 raise util.Abort(_("branch '%s' has %d heads - "
4184 4199 "please merge with an explicit rev")
4185 4200 % (branch, len(bheads)),
4186 4201 hint=_("run 'hg heads .' to see heads"))
4187 4202
4188 4203 parent = repo.dirstate.p1()
4189 4204 if len(nbhs) == 1:
4190 4205 if len(bheads) > 1:
4191 4206 raise util.Abort(_("heads are bookmarked - "
4192 4207 "please merge with an explicit rev"),
4193 4208 hint=_("run 'hg heads' to see all heads"))
4194 4209 if len(repo.heads()) > 1:
4195 4210 raise util.Abort(_("branch '%s' has one head - "
4196 4211 "please merge with an explicit rev")
4197 4212 % branch,
4198 4213 hint=_("run 'hg heads' to see all heads"))
4199 4214 msg, hint = _('nothing to merge'), None
4200 4215 if parent != repo.lookup(branch):
4201 4216 hint = _("use 'hg update' instead")
4202 4217 raise util.Abort(msg, hint=hint)
4203 4218
4204 4219 if parent not in bheads:
4205 4220 raise util.Abort(_('working directory not at a head revision'),
4206 4221 hint=_("use 'hg update' or merge with an "
4207 4222 "explicit revision"))
4208 4223 if parent == nbhs[0]:
4209 4224 node = nbhs[-1]
4210 4225 else:
4211 4226 node = nbhs[0]
4212 4227
4213 4228 if opts.get('preview'):
4214 4229 # find nodes that are ancestors of p2 but not of p1
4215 4230 p1 = repo.lookup('.')
4216 4231 p2 = repo.lookup(node)
4217 4232 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4218 4233
4219 4234 displayer = cmdutil.show_changeset(ui, repo, opts)
4220 4235 for node in nodes:
4221 4236 displayer.show(repo[node])
4222 4237 displayer.close()
4223 4238 return 0
4224 4239
4225 4240 try:
4226 4241 # ui.forcemerge is an internal variable, do not document
4227 4242 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4228 4243 return hg.merge(repo, node, force=opts.get('force'))
4229 4244 finally:
4230 4245 ui.setconfig('ui', 'forcemerge', '')
4231 4246
4232 4247 @command('outgoing|out',
4233 4248 [('f', 'force', None, _('run even when the destination is unrelated')),
4234 4249 ('r', 'rev', [],
4235 4250 _('a changeset intended to be included in the destination'), _('REV')),
4236 4251 ('n', 'newest-first', None, _('show newest record first')),
4237 4252 ('B', 'bookmarks', False, _('compare bookmarks')),
4238 4253 ('b', 'branch', [], _('a specific branch you would like to push'),
4239 4254 _('BRANCH')),
4240 4255 ] + logopts + remoteopts + subrepoopts,
4241 4256 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4242 4257 def outgoing(ui, repo, dest=None, **opts):
4243 4258 """show changesets not found in the destination
4244 4259
4245 4260 Show changesets not found in the specified destination repository
4246 4261 or the default push location. These are the changesets that would
4247 4262 be pushed if a push was requested.
4248 4263
4249 4264 See pull for details of valid destination formats.
4250 4265
4251 4266 Returns 0 if there are outgoing changes, 1 otherwise.
4252 4267 """
4253 4268
4254 4269 if opts.get('bookmarks'):
4255 4270 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4256 4271 dest, branches = hg.parseurl(dest, opts.get('branch'))
4257 4272 other = hg.peer(repo, opts, dest)
4258 4273 if 'bookmarks' not in other.listkeys('namespaces'):
4259 4274 ui.warn(_("remote doesn't support bookmarks\n"))
4260 4275 return 0
4261 4276 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4262 4277 return bookmarks.diff(ui, other, repo)
4263 4278
4264 4279 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4265 4280 try:
4266 4281 return hg.outgoing(ui, repo, dest, opts)
4267 4282 finally:
4268 4283 del repo._subtoppath
4269 4284
4270 4285 @command('parents',
4271 4286 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4272 4287 ] + templateopts,
4273 4288 _('[-r REV] [FILE]'))
4274 4289 def parents(ui, repo, file_=None, **opts):
4275 4290 """show the parents of the working directory or revision
4276 4291
4277 4292 Print the working directory's parent revisions. If a revision is
4278 4293 given via -r/--rev, the parent of that revision will be printed.
4279 4294 If a file argument is given, the revision in which the file was
4280 4295 last changed (before the working directory revision or the
4281 4296 argument to --rev if given) is printed.
4282 4297
4283 4298 Returns 0 on success.
4284 4299 """
4285 4300
4286 4301 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4287 4302
4288 4303 if file_:
4289 4304 m = scmutil.match(ctx, (file_,), opts)
4290 4305 if m.anypats() or len(m.files()) != 1:
4291 4306 raise util.Abort(_('can only specify an explicit filename'))
4292 4307 file_ = m.files()[0]
4293 4308 filenodes = []
4294 4309 for cp in ctx.parents():
4295 4310 if not cp:
4296 4311 continue
4297 4312 try:
4298 4313 filenodes.append(cp.filenode(file_))
4299 4314 except error.LookupError:
4300 4315 pass
4301 4316 if not filenodes:
4302 4317 raise util.Abort(_("'%s' not found in manifest!") % file_)
4303 4318 fl = repo.file(file_)
4304 4319 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4305 4320 else:
4306 4321 p = [cp.node() for cp in ctx.parents()]
4307 4322
4308 4323 displayer = cmdutil.show_changeset(ui, repo, opts)
4309 4324 for n in p:
4310 4325 if n != nullid:
4311 4326 displayer.show(repo[n])
4312 4327 displayer.close()
4313 4328
4314 4329 @command('paths', [], _('[NAME]'))
4315 4330 def paths(ui, repo, search=None):
4316 4331 """show aliases for remote repositories
4317 4332
4318 4333 Show definition of symbolic path name NAME. If no name is given,
4319 4334 show definition of all available names.
4320 4335
4321 4336 Option -q/--quiet suppresses all output when searching for NAME
4322 4337 and shows only the path names when listing all definitions.
4323 4338
4324 4339 Path names are defined in the [paths] section of your
4325 4340 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4326 4341 repository, ``.hg/hgrc`` is used, too.
4327 4342
4328 4343 The path names ``default`` and ``default-push`` have a special
4329 4344 meaning. When performing a push or pull operation, they are used
4330 4345 as fallbacks if no location is specified on the command-line.
4331 4346 When ``default-push`` is set, it will be used for push and
4332 4347 ``default`` will be used for pull; otherwise ``default`` is used
4333 4348 as the fallback for both. When cloning a repository, the clone
4334 4349 source is written as ``default`` in ``.hg/hgrc``. Note that
4335 4350 ``default`` and ``default-push`` apply to all inbound (e.g.
4336 4351 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4337 4352 :hg:`bundle`) operations.
4338 4353
4339 4354 See :hg:`help urls` for more information.
4340 4355
4341 4356 Returns 0 on success.
4342 4357 """
4343 4358 if search:
4344 4359 for name, path in ui.configitems("paths"):
4345 4360 if name == search:
4346 4361 ui.status("%s\n" % util.hidepassword(path))
4347 4362 return
4348 4363 if not ui.quiet:
4349 4364 ui.warn(_("not found!\n"))
4350 4365 return 1
4351 4366 else:
4352 4367 for name, path in ui.configitems("paths"):
4353 4368 if ui.quiet:
4354 4369 ui.write("%s\n" % name)
4355 4370 else:
4356 4371 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4357 4372
4358 4373 @command('^phase',
4359 4374 [('p', 'public', False, _('set changeset phase to public')),
4360 4375 ('d', 'draft', False, _('set changeset phase to draft')),
4361 4376 ('s', 'secret', False, _('set changeset phase to secret')),
4362 4377 ('f', 'force', False, _('allow to move boundary backward')),
4363 4378 ('r', 'rev', [], _('target revision'), _('REV')),
4364 4379 ],
4365 4380 _('[-p|-d|-s] [-f] [-r] REV...'))
4366 4381 def phase(ui, repo, *revs, **opts):
4367 4382 """set or show the current phase name
4368 4383
4369 4384 With no argument, show the phase name of specified revisions.
4370 4385
4371 4386 With one of -p/--public, -d/--draft or -s/--secret, change the
4372 4387 phase value of the specified revisions.
4373 4388
4374 4389 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4375 4390 lower phase to an higher phase. Phases are ordered as follows::
4376 4391
4377 4392 public < draft < secret
4378 4393
4379 4394 Return 0 on success, 1 if no phases were changed or some could not
4380 4395 be changed.
4381 4396 """
4382 4397 # search for a unique phase argument
4383 4398 targetphase = None
4384 4399 for idx, name in enumerate(phases.phasenames):
4385 4400 if opts[name]:
4386 4401 if targetphase is not None:
4387 4402 raise util.Abort(_('only one phase can be specified'))
4388 4403 targetphase = idx
4389 4404
4390 4405 # look for specified revision
4391 4406 revs = list(revs)
4392 4407 revs.extend(opts['rev'])
4393 4408 if not revs:
4394 4409 raise util.Abort(_('no revisions specified'))
4395 4410
4396 4411 revs = scmutil.revrange(repo, revs)
4397 4412
4398 4413 lock = None
4399 4414 ret = 0
4400 4415 if targetphase is None:
4401 4416 # display
4402 4417 for r in revs:
4403 4418 ctx = repo[r]
4404 4419 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4405 4420 else:
4406 4421 lock = repo.lock()
4407 4422 try:
4408 4423 # set phase
4409 4424 if not revs:
4410 4425 raise util.Abort(_('empty revision set'))
4411 4426 nodes = [repo[r].node() for r in revs]
4412 4427 olddata = repo._phasecache.getphaserevs(repo)[:]
4413 4428 phases.advanceboundary(repo, targetphase, nodes)
4414 4429 if opts['force']:
4415 4430 phases.retractboundary(repo, targetphase, nodes)
4416 4431 finally:
4417 4432 lock.release()
4418 4433 newdata = repo._phasecache.getphaserevs(repo)
4419 4434 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4420 4435 rejected = [n for n in nodes
4421 4436 if newdata[repo[n].rev()] < targetphase]
4422 4437 if rejected:
4423 4438 ui.warn(_('cannot move %i changesets to a more permissive '
4424 4439 'phase, use --force\n') % len(rejected))
4425 4440 ret = 1
4426 4441 if changes:
4427 4442 msg = _('phase changed for %i changesets\n') % changes
4428 4443 if ret:
4429 4444 ui.status(msg)
4430 4445 else:
4431 4446 ui.note(msg)
4432 4447 else:
4433 4448 ui.warn(_('no phases changed\n'))
4434 4449 ret = 1
4435 4450 return ret
4436 4451
4437 4452 def postincoming(ui, repo, modheads, optupdate, checkout):
4438 4453 if modheads == 0:
4439 4454 return
4440 4455 if optupdate:
4441 4456 movemarkfrom = repo['.'].node()
4442 4457 try:
4443 4458 ret = hg.update(repo, checkout)
4444 4459 except util.Abort, inst:
4445 4460 ui.warn(_("not updating: %s\n") % str(inst))
4446 4461 return 0
4447 4462 if not ret and not checkout:
4448 4463 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4449 4464 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4450 4465 return ret
4451 4466 if modheads > 1:
4452 4467 currentbranchheads = len(repo.branchheads())
4453 4468 if currentbranchheads == modheads:
4454 4469 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4455 4470 elif currentbranchheads > 1:
4456 4471 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4457 4472 "merge)\n"))
4458 4473 else:
4459 4474 ui.status(_("(run 'hg heads' to see heads)\n"))
4460 4475 else:
4461 4476 ui.status(_("(run 'hg update' to get a working copy)\n"))
4462 4477
4463 4478 @command('^pull',
4464 4479 [('u', 'update', None,
4465 4480 _('update to new branch head if changesets were pulled')),
4466 4481 ('f', 'force', None, _('run even when remote repository is unrelated')),
4467 4482 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4468 4483 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4469 4484 ('b', 'branch', [], _('a specific branch you would like to pull'),
4470 4485 _('BRANCH')),
4471 4486 ] + remoteopts,
4472 4487 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4473 4488 def pull(ui, repo, source="default", **opts):
4474 4489 """pull changes from the specified source
4475 4490
4476 4491 Pull changes from a remote repository to a local one.
4477 4492
4478 4493 This finds all changes from the repository at the specified path
4479 4494 or URL and adds them to a local repository (the current one unless
4480 4495 -R is specified). By default, this does not update the copy of the
4481 4496 project in the working directory.
4482 4497
4483 4498 Use :hg:`incoming` if you want to see what would have been added
4484 4499 by a pull at the time you issued this command. If you then decide
4485 4500 to add those changes to the repository, you should use :hg:`pull
4486 4501 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4487 4502
4488 4503 If SOURCE is omitted, the 'default' path will be used.
4489 4504 See :hg:`help urls` for more information.
4490 4505
4491 4506 Returns 0 on success, 1 if an update had unresolved files.
4492 4507 """
4493 4508 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4494 4509 other = hg.peer(repo, opts, source)
4495 4510 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4496 4511 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4497 4512
4498 4513 if opts.get('bookmark'):
4499 4514 if not revs:
4500 4515 revs = []
4501 4516 rb = other.listkeys('bookmarks')
4502 4517 for b in opts['bookmark']:
4503 4518 if b not in rb:
4504 4519 raise util.Abort(_('remote bookmark %s not found!') % b)
4505 4520 revs.append(rb[b])
4506 4521
4507 4522 if revs:
4508 4523 try:
4509 4524 revs = [other.lookup(rev) for rev in revs]
4510 4525 except error.CapabilityError:
4511 4526 err = _("other repository doesn't support revision lookup, "
4512 4527 "so a rev cannot be specified.")
4513 4528 raise util.Abort(err)
4514 4529
4515 4530 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4516 4531 bookmarks.updatefromremote(ui, repo, other, source)
4517 4532 if checkout:
4518 4533 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4519 4534 repo._subtoppath = source
4520 4535 try:
4521 4536 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4522 4537
4523 4538 finally:
4524 4539 del repo._subtoppath
4525 4540
4526 4541 # update specified bookmarks
4527 4542 if opts.get('bookmark'):
4528 4543 for b in opts['bookmark']:
4529 4544 # explicit pull overrides local bookmark if any
4530 4545 ui.status(_("importing bookmark %s\n") % b)
4531 4546 repo._bookmarks[b] = repo[rb[b]].node()
4532 4547 bookmarks.write(repo)
4533 4548
4534 4549 return ret
4535 4550
4536 4551 @command('^push',
4537 4552 [('f', 'force', None, _('force push')),
4538 4553 ('r', 'rev', [],
4539 4554 _('a changeset intended to be included in the destination'),
4540 4555 _('REV')),
4541 4556 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4542 4557 ('b', 'branch', [],
4543 4558 _('a specific branch you would like to push'), _('BRANCH')),
4544 4559 ('', 'new-branch', False, _('allow pushing a new branch')),
4545 4560 ] + remoteopts,
4546 4561 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4547 4562 def push(ui, repo, dest=None, **opts):
4548 4563 """push changes to the specified destination
4549 4564
4550 4565 Push changesets from the local repository to the specified
4551 4566 destination.
4552 4567
4553 4568 This operation is symmetrical to pull: it is identical to a pull
4554 4569 in the destination repository from the current one.
4555 4570
4556 4571 By default, push will not allow creation of new heads at the
4557 4572 destination, since multiple heads would make it unclear which head
4558 4573 to use. In this situation, it is recommended to pull and merge
4559 4574 before pushing.
4560 4575
4561 4576 Use --new-branch if you want to allow push to create a new named
4562 4577 branch that is not present at the destination. This allows you to
4563 4578 only create a new branch without forcing other changes.
4564 4579
4565 4580 Use -f/--force to override the default behavior and push all
4566 4581 changesets on all branches.
4567 4582
4568 4583 If -r/--rev is used, the specified revision and all its ancestors
4569 4584 will be pushed to the remote repository.
4570 4585
4571 4586 Please see :hg:`help urls` for important details about ``ssh://``
4572 4587 URLs. If DESTINATION is omitted, a default path will be used.
4573 4588
4574 4589 Returns 0 if push was successful, 1 if nothing to push.
4575 4590 """
4576 4591
4577 4592 if opts.get('bookmark'):
4578 4593 for b in opts['bookmark']:
4579 4594 # translate -B options to -r so changesets get pushed
4580 4595 if b in repo._bookmarks:
4581 4596 opts.setdefault('rev', []).append(b)
4582 4597 else:
4583 4598 # if we try to push a deleted bookmark, translate it to null
4584 4599 # this lets simultaneous -r, -b options continue working
4585 4600 opts.setdefault('rev', []).append("null")
4586 4601
4587 4602 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4588 4603 dest, branches = hg.parseurl(dest, opts.get('branch'))
4589 4604 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4590 4605 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4591 4606 other = hg.peer(repo, opts, dest)
4592 4607 if revs:
4593 4608 revs = [repo.lookup(rev) for rev in revs]
4594 4609
4595 4610 repo._subtoppath = dest
4596 4611 try:
4597 4612 # push subrepos depth-first for coherent ordering
4598 4613 c = repo['']
4599 4614 subs = c.substate # only repos that are committed
4600 4615 for s in sorted(subs):
4601 4616 if c.sub(s).push(opts) == 0:
4602 4617 return False
4603 4618 finally:
4604 4619 del repo._subtoppath
4605 4620 result = repo.push(other, opts.get('force'), revs=revs,
4606 4621 newbranch=opts.get('new_branch'))
4607 4622
4608 4623 result = not result
4609 4624
4610 4625 if opts.get('bookmark'):
4611 4626 rb = other.listkeys('bookmarks')
4612 4627 for b in opts['bookmark']:
4613 4628 # explicit push overrides remote bookmark if any
4614 4629 if b in repo._bookmarks:
4615 4630 ui.status(_("exporting bookmark %s\n") % b)
4616 4631 new = repo[b].hex()
4617 4632 elif b in rb:
4618 4633 ui.status(_("deleting remote bookmark %s\n") % b)
4619 4634 new = '' # delete
4620 4635 else:
4621 4636 ui.warn(_('bookmark %s does not exist on the local '
4622 4637 'or remote repository!\n') % b)
4623 4638 return 2
4624 4639 old = rb.get(b, '')
4625 4640 r = other.pushkey('bookmarks', b, old, new)
4626 4641 if not r:
4627 4642 ui.warn(_('updating bookmark %s failed!\n') % b)
4628 4643 if not result:
4629 4644 result = 2
4630 4645
4631 4646 return result
4632 4647
4633 4648 @command('recover', [])
4634 4649 def recover(ui, repo):
4635 4650 """roll back an interrupted transaction
4636 4651
4637 4652 Recover from an interrupted commit or pull.
4638 4653
4639 4654 This command tries to fix the repository status after an
4640 4655 interrupted operation. It should only be necessary when Mercurial
4641 4656 suggests it.
4642 4657
4643 4658 Returns 0 if successful, 1 if nothing to recover or verify fails.
4644 4659 """
4645 4660 if repo.recover():
4646 4661 return hg.verify(repo)
4647 4662 return 1
4648 4663
4649 4664 @command('^remove|rm',
4650 4665 [('A', 'after', None, _('record delete for missing files')),
4651 4666 ('f', 'force', None,
4652 4667 _('remove (and delete) file even if added or modified')),
4653 4668 ] + walkopts,
4654 4669 _('[OPTION]... FILE...'))
4655 4670 def remove(ui, repo, *pats, **opts):
4656 4671 """remove the specified files on the next commit
4657 4672
4658 4673 Schedule the indicated files for removal from the current branch.
4659 4674
4660 4675 This command schedules the files to be removed at the next commit.
4661 4676 To undo a remove before that, see :hg:`revert`. To undo added
4662 4677 files, see :hg:`forget`.
4663 4678
4664 4679 .. container:: verbose
4665 4680
4666 4681 -A/--after can be used to remove only files that have already
4667 4682 been deleted, -f/--force can be used to force deletion, and -Af
4668 4683 can be used to remove files from the next revision without
4669 4684 deleting them from the working directory.
4670 4685
4671 4686 The following table details the behavior of remove for different
4672 4687 file states (columns) and option combinations (rows). The file
4673 4688 states are Added [A], Clean [C], Modified [M] and Missing [!]
4674 4689 (as reported by :hg:`status`). The actions are Warn, Remove
4675 4690 (from branch) and Delete (from disk):
4676 4691
4677 4692 ======= == == == ==
4678 4693 A C M !
4679 4694 ======= == == == ==
4680 4695 none W RD W R
4681 4696 -f R RD RD R
4682 4697 -A W W W R
4683 4698 -Af R R R R
4684 4699 ======= == == == ==
4685 4700
4686 4701 Note that remove never deletes files in Added [A] state from the
4687 4702 working directory, not even if option --force is specified.
4688 4703
4689 4704 Returns 0 on success, 1 if any warnings encountered.
4690 4705 """
4691 4706
4692 4707 ret = 0
4693 4708 after, force = opts.get('after'), opts.get('force')
4694 4709 if not pats and not after:
4695 4710 raise util.Abort(_('no files specified'))
4696 4711
4697 4712 m = scmutil.match(repo[None], pats, opts)
4698 4713 s = repo.status(match=m, clean=True)
4699 4714 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4700 4715
4701 4716 for f in m.files():
4702 4717 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4703 4718 if os.path.exists(m.rel(f)):
4704 4719 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4705 4720 ret = 1
4706 4721
4707 4722 if force:
4708 4723 list = modified + deleted + clean + added
4709 4724 elif after:
4710 4725 list = deleted
4711 4726 for f in modified + added + clean:
4712 4727 ui.warn(_('not removing %s: file still exists (use -f'
4713 4728 ' to force removal)\n') % m.rel(f))
4714 4729 ret = 1
4715 4730 else:
4716 4731 list = deleted + clean
4717 4732 for f in modified:
4718 4733 ui.warn(_('not removing %s: file is modified (use -f'
4719 4734 ' to force removal)\n') % m.rel(f))
4720 4735 ret = 1
4721 4736 for f in added:
4722 4737 ui.warn(_('not removing %s: file has been marked for add'
4723 4738 ' (use forget to undo)\n') % m.rel(f))
4724 4739 ret = 1
4725 4740
4726 4741 for f in sorted(list):
4727 4742 if ui.verbose or not m.exact(f):
4728 4743 ui.status(_('removing %s\n') % m.rel(f))
4729 4744
4730 4745 wlock = repo.wlock()
4731 4746 try:
4732 4747 if not after:
4733 4748 for f in list:
4734 4749 if f in added:
4735 4750 continue # we never unlink added files on remove
4736 4751 try:
4737 4752 util.unlinkpath(repo.wjoin(f))
4738 4753 except OSError, inst:
4739 4754 if inst.errno != errno.ENOENT:
4740 4755 raise
4741 4756 repo[None].forget(list)
4742 4757 finally:
4743 4758 wlock.release()
4744 4759
4745 4760 return ret
4746 4761
4747 4762 @command('rename|move|mv',
4748 4763 [('A', 'after', None, _('record a rename that has already occurred')),
4749 4764 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4750 4765 ] + walkopts + dryrunopts,
4751 4766 _('[OPTION]... SOURCE... DEST'))
4752 4767 def rename(ui, repo, *pats, **opts):
4753 4768 """rename files; equivalent of copy + remove
4754 4769
4755 4770 Mark dest as copies of sources; mark sources for deletion. If dest
4756 4771 is a directory, copies are put in that directory. If dest is a
4757 4772 file, there can only be one source.
4758 4773
4759 4774 By default, this command copies the contents of files as they
4760 4775 exist in the working directory. If invoked with -A/--after, the
4761 4776 operation is recorded, but no copying is performed.
4762 4777
4763 4778 This command takes effect at the next commit. To undo a rename
4764 4779 before that, see :hg:`revert`.
4765 4780
4766 4781 Returns 0 on success, 1 if errors are encountered.
4767 4782 """
4768 4783 wlock = repo.wlock(False)
4769 4784 try:
4770 4785 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4771 4786 finally:
4772 4787 wlock.release()
4773 4788
4774 4789 @command('resolve',
4775 4790 [('a', 'all', None, _('select all unresolved files')),
4776 4791 ('l', 'list', None, _('list state of files needing merge')),
4777 4792 ('m', 'mark', None, _('mark files as resolved')),
4778 4793 ('u', 'unmark', None, _('mark files as unresolved')),
4779 4794 ('n', 'no-status', None, _('hide status prefix'))]
4780 4795 + mergetoolopts + walkopts,
4781 4796 _('[OPTION]... [FILE]...'))
4782 4797 def resolve(ui, repo, *pats, **opts):
4783 4798 """redo merges or set/view the merge status of files
4784 4799
4785 4800 Merges with unresolved conflicts are often the result of
4786 4801 non-interactive merging using the ``internal:merge`` configuration
4787 4802 setting, or a command-line merge tool like ``diff3``. The resolve
4788 4803 command is used to manage the files involved in a merge, after
4789 4804 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4790 4805 working directory must have two parents). See :hg:`help
4791 4806 merge-tools` for information on configuring merge tools.
4792 4807
4793 4808 The resolve command can be used in the following ways:
4794 4809
4795 4810 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4796 4811 files, discarding any previous merge attempts. Re-merging is not
4797 4812 performed for files already marked as resolved. Use ``--all/-a``
4798 4813 to select all unresolved files. ``--tool`` can be used to specify
4799 4814 the merge tool used for the given files. It overrides the HGMERGE
4800 4815 environment variable and your configuration files. Previous file
4801 4816 contents are saved with a ``.orig`` suffix.
4802 4817
4803 4818 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4804 4819 (e.g. after having manually fixed-up the files). The default is
4805 4820 to mark all unresolved files.
4806 4821
4807 4822 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4808 4823 default is to mark all resolved files.
4809 4824
4810 4825 - :hg:`resolve -l`: list files which had or still have conflicts.
4811 4826 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4812 4827
4813 4828 Note that Mercurial will not let you commit files with unresolved
4814 4829 merge conflicts. You must use :hg:`resolve -m ...` before you can
4815 4830 commit after a conflicting merge.
4816 4831
4817 4832 Returns 0 on success, 1 if any files fail a resolve attempt.
4818 4833 """
4819 4834
4820 4835 all, mark, unmark, show, nostatus = \
4821 4836 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4822 4837
4823 4838 if (show and (mark or unmark)) or (mark and unmark):
4824 4839 raise util.Abort(_("too many options specified"))
4825 4840 if pats and all:
4826 4841 raise util.Abort(_("can't specify --all and patterns"))
4827 4842 if not (all or pats or show or mark or unmark):
4828 4843 raise util.Abort(_('no files or directories specified; '
4829 4844 'use --all to remerge all files'))
4830 4845
4831 4846 ms = mergemod.mergestate(repo)
4832 4847 m = scmutil.match(repo[None], pats, opts)
4833 4848 ret = 0
4834 4849
4835 4850 for f in ms:
4836 4851 if m(f):
4837 4852 if show:
4838 4853 if nostatus:
4839 4854 ui.write("%s\n" % f)
4840 4855 else:
4841 4856 ui.write("%s %s\n" % (ms[f].upper(), f),
4842 4857 label='resolve.' +
4843 4858 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4844 4859 elif mark:
4845 4860 ms.mark(f, "r")
4846 4861 elif unmark:
4847 4862 ms.mark(f, "u")
4848 4863 else:
4849 4864 wctx = repo[None]
4850 4865 mctx = wctx.parents()[-1]
4851 4866
4852 4867 # backup pre-resolve (merge uses .orig for its own purposes)
4853 4868 a = repo.wjoin(f)
4854 4869 util.copyfile(a, a + ".resolve")
4855 4870
4856 4871 try:
4857 4872 # resolve file
4858 4873 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4859 4874 if ms.resolve(f, wctx, mctx):
4860 4875 ret = 1
4861 4876 finally:
4862 4877 ui.setconfig('ui', 'forcemerge', '')
4863 4878
4864 4879 # replace filemerge's .orig file with our resolve file
4865 4880 util.rename(a + ".resolve", a + ".orig")
4866 4881
4867 4882 ms.commit()
4868 4883 return ret
4869 4884
4870 4885 @command('revert',
4871 4886 [('a', 'all', None, _('revert all changes when no arguments given')),
4872 4887 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4873 4888 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4874 4889 ('C', 'no-backup', None, _('do not save backup copies of files')),
4875 4890 ] + walkopts + dryrunopts,
4876 4891 _('[OPTION]... [-r REV] [NAME]...'))
4877 4892 def revert(ui, repo, *pats, **opts):
4878 4893 """restore files to their checkout state
4879 4894
4880 4895 .. note::
4881 4896 To check out earlier revisions, you should use :hg:`update REV`.
4882 4897 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4883 4898
4884 4899 With no revision specified, revert the specified files or directories
4885 4900 to the contents they had in the parent of the working directory.
4886 4901 This restores the contents of files to an unmodified
4887 4902 state and unschedules adds, removes, copies, and renames. If the
4888 4903 working directory has two parents, you must explicitly specify a
4889 4904 revision.
4890 4905
4891 4906 Using the -r/--rev or -d/--date options, revert the given files or
4892 4907 directories to their states as of a specific revision. Because
4893 4908 revert does not change the working directory parents, this will
4894 4909 cause these files to appear modified. This can be helpful to "back
4895 4910 out" some or all of an earlier change. See :hg:`backout` for a
4896 4911 related method.
4897 4912
4898 4913 Modified files are saved with a .orig suffix before reverting.
4899 4914 To disable these backups, use --no-backup.
4900 4915
4901 4916 See :hg:`help dates` for a list of formats valid for -d/--date.
4902 4917
4903 4918 Returns 0 on success.
4904 4919 """
4905 4920
4906 4921 if opts.get("date"):
4907 4922 if opts.get("rev"):
4908 4923 raise util.Abort(_("you can't specify a revision and a date"))
4909 4924 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4910 4925
4911 4926 parent, p2 = repo.dirstate.parents()
4912 4927 if not opts.get('rev') and p2 != nullid:
4913 4928 # revert after merge is a trap for new users (issue2915)
4914 4929 raise util.Abort(_('uncommitted merge with no revision specified'),
4915 4930 hint=_('use "hg update" or see "hg help revert"'))
4916 4931
4917 4932 ctx = scmutil.revsingle(repo, opts.get('rev'))
4918 4933
4919 4934 if not pats and not opts.get('all'):
4920 4935 msg = _("no files or directories specified")
4921 4936 if p2 != nullid:
4922 4937 hint = _("uncommitted merge, use --all to discard all changes,"
4923 4938 " or 'hg update -C .' to abort the merge")
4924 4939 raise util.Abort(msg, hint=hint)
4925 4940 dirty = util.any(repo.status())
4926 4941 node = ctx.node()
4927 4942 if node != parent:
4928 4943 if dirty:
4929 4944 hint = _("uncommitted changes, use --all to discard all"
4930 4945 " changes, or 'hg update %s' to update") % ctx.rev()
4931 4946 else:
4932 4947 hint = _("use --all to revert all files,"
4933 4948 " or 'hg update %s' to update") % ctx.rev()
4934 4949 elif dirty:
4935 4950 hint = _("uncommitted changes, use --all to discard all changes")
4936 4951 else:
4937 4952 hint = _("use --all to revert all files")
4938 4953 raise util.Abort(msg, hint=hint)
4939 4954
4940 4955 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4941 4956
4942 4957 @command('rollback', dryrunopts +
4943 4958 [('f', 'force', False, _('ignore safety measures'))])
4944 4959 def rollback(ui, repo, **opts):
4945 4960 """roll back the last transaction (dangerous)
4946 4961
4947 4962 This command should be used with care. There is only one level of
4948 4963 rollback, and there is no way to undo a rollback. It will also
4949 4964 restore the dirstate at the time of the last transaction, losing
4950 4965 any dirstate changes since that time. This command does not alter
4951 4966 the working directory.
4952 4967
4953 4968 Transactions are used to encapsulate the effects of all commands
4954 4969 that create new changesets or propagate existing changesets into a
4955 4970 repository. For example, the following commands are transactional,
4956 4971 and their effects can be rolled back:
4957 4972
4958 4973 - commit
4959 4974 - import
4960 4975 - pull
4961 4976 - push (with this repository as the destination)
4962 4977 - unbundle
4963 4978
4964 4979 To avoid permanent data loss, rollback will refuse to rollback a
4965 4980 commit transaction if it isn't checked out. Use --force to
4966 4981 override this protection.
4967 4982
4968 4983 This command is not intended for use on public repositories. Once
4969 4984 changes are visible for pull by other users, rolling a transaction
4970 4985 back locally is ineffective (someone else may already have pulled
4971 4986 the changes). Furthermore, a race is possible with readers of the
4972 4987 repository; for example an in-progress pull from the repository
4973 4988 may fail if a rollback is performed.
4974 4989
4975 4990 Returns 0 on success, 1 if no rollback data is available.
4976 4991 """
4977 4992 return repo.rollback(dryrun=opts.get('dry_run'),
4978 4993 force=opts.get('force'))
4979 4994
4980 4995 @command('root', [])
4981 4996 def root(ui, repo):
4982 4997 """print the root (top) of the current working directory
4983 4998
4984 4999 Print the root directory of the current repository.
4985 5000
4986 5001 Returns 0 on success.
4987 5002 """
4988 5003 ui.write(repo.root + "\n")
4989 5004
4990 5005 @command('^serve',
4991 5006 [('A', 'accesslog', '', _('name of access log file to write to'),
4992 5007 _('FILE')),
4993 5008 ('d', 'daemon', None, _('run server in background')),
4994 5009 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4995 5010 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4996 5011 # use string type, then we can check if something was passed
4997 5012 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4998 5013 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4999 5014 _('ADDR')),
5000 5015 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5001 5016 _('PREFIX')),
5002 5017 ('n', 'name', '',
5003 5018 _('name to show in web pages (default: working directory)'), _('NAME')),
5004 5019 ('', 'web-conf', '',
5005 5020 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5006 5021 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5007 5022 _('FILE')),
5008 5023 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5009 5024 ('', 'stdio', None, _('for remote clients')),
5010 5025 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5011 5026 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5012 5027 ('', 'style', '', _('template style to use'), _('STYLE')),
5013 5028 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5014 5029 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5015 5030 _('[OPTION]...'))
5016 5031 def serve(ui, repo, **opts):
5017 5032 """start stand-alone webserver
5018 5033
5019 5034 Start a local HTTP repository browser and pull server. You can use
5020 5035 this for ad-hoc sharing and browsing of repositories. It is
5021 5036 recommended to use a real web server to serve a repository for
5022 5037 longer periods of time.
5023 5038
5024 5039 Please note that the server does not implement access control.
5025 5040 This means that, by default, anybody can read from the server and
5026 5041 nobody can write to it by default. Set the ``web.allow_push``
5027 5042 option to ``*`` to allow everybody to push to the server. You
5028 5043 should use a real web server if you need to authenticate users.
5029 5044
5030 5045 By default, the server logs accesses to stdout and errors to
5031 5046 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5032 5047 files.
5033 5048
5034 5049 To have the server choose a free port number to listen on, specify
5035 5050 a port number of 0; in this case, the server will print the port
5036 5051 number it uses.
5037 5052
5038 5053 Returns 0 on success.
5039 5054 """
5040 5055
5041 5056 if opts["stdio"] and opts["cmdserver"]:
5042 5057 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5043 5058
5044 5059 def checkrepo():
5045 5060 if repo is None:
5046 5061 raise error.RepoError(_("there is no Mercurial repository here"
5047 5062 " (.hg not found)"))
5048 5063
5049 5064 if opts["stdio"]:
5050 5065 checkrepo()
5051 5066 s = sshserver.sshserver(ui, repo)
5052 5067 s.serve_forever()
5053 5068
5054 5069 if opts["cmdserver"]:
5055 5070 checkrepo()
5056 5071 s = commandserver.server(ui, repo, opts["cmdserver"])
5057 5072 return s.serve()
5058 5073
5059 5074 # this way we can check if something was given in the command-line
5060 5075 if opts.get('port'):
5061 5076 opts['port'] = util.getport(opts.get('port'))
5062 5077
5063 5078 baseui = repo and repo.baseui or ui
5064 5079 optlist = ("name templates style address port prefix ipv6"
5065 5080 " accesslog errorlog certificate encoding")
5066 5081 for o in optlist.split():
5067 5082 val = opts.get(o, '')
5068 5083 if val in (None, ''): # should check against default options instead
5069 5084 continue
5070 5085 baseui.setconfig("web", o, val)
5071 5086 if repo and repo.ui != baseui:
5072 5087 repo.ui.setconfig("web", o, val)
5073 5088
5074 5089 o = opts.get('web_conf') or opts.get('webdir_conf')
5075 5090 if not o:
5076 5091 if not repo:
5077 5092 raise error.RepoError(_("there is no Mercurial repository"
5078 5093 " here (.hg not found)"))
5079 5094 o = repo.root
5080 5095
5081 5096 app = hgweb.hgweb(o, baseui=ui)
5082 5097
5083 5098 class service(object):
5084 5099 def init(self):
5085 5100 util.setsignalhandler()
5086 5101 self.httpd = hgweb.server.create_server(ui, app)
5087 5102
5088 5103 if opts['port'] and not ui.verbose:
5089 5104 return
5090 5105
5091 5106 if self.httpd.prefix:
5092 5107 prefix = self.httpd.prefix.strip('/') + '/'
5093 5108 else:
5094 5109 prefix = ''
5095 5110
5096 5111 port = ':%d' % self.httpd.port
5097 5112 if port == ':80':
5098 5113 port = ''
5099 5114
5100 5115 bindaddr = self.httpd.addr
5101 5116 if bindaddr == '0.0.0.0':
5102 5117 bindaddr = '*'
5103 5118 elif ':' in bindaddr: # IPv6
5104 5119 bindaddr = '[%s]' % bindaddr
5105 5120
5106 5121 fqaddr = self.httpd.fqaddr
5107 5122 if ':' in fqaddr:
5108 5123 fqaddr = '[%s]' % fqaddr
5109 5124 if opts['port']:
5110 5125 write = ui.status
5111 5126 else:
5112 5127 write = ui.write
5113 5128 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5114 5129 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5115 5130
5116 5131 def run(self):
5117 5132 self.httpd.serve_forever()
5118 5133
5119 5134 service = service()
5120 5135
5121 5136 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5122 5137
5123 5138 @command('showconfig|debugconfig',
5124 5139 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5125 5140 _('[-u] [NAME]...'))
5126 5141 def showconfig(ui, repo, *values, **opts):
5127 5142 """show combined config settings from all hgrc files
5128 5143
5129 5144 With no arguments, print names and values of all config items.
5130 5145
5131 5146 With one argument of the form section.name, print just the value
5132 5147 of that config item.
5133 5148
5134 5149 With multiple arguments, print names and values of all config
5135 5150 items with matching section names.
5136 5151
5137 5152 With --debug, the source (filename and line number) is printed
5138 5153 for each config item.
5139 5154
5140 5155 Returns 0 on success.
5141 5156 """
5142 5157
5143 5158 for f in scmutil.rcpath():
5144 5159 ui.debug('read config from: %s\n' % f)
5145 5160 untrusted = bool(opts.get('untrusted'))
5146 5161 if values:
5147 5162 sections = [v for v in values if '.' not in v]
5148 5163 items = [v for v in values if '.' in v]
5149 5164 if len(items) > 1 or items and sections:
5150 5165 raise util.Abort(_('only one config item permitted'))
5151 5166 for section, name, value in ui.walkconfig(untrusted=untrusted):
5152 5167 value = str(value).replace('\n', '\\n')
5153 5168 sectname = section + '.' + name
5154 5169 if values:
5155 5170 for v in values:
5156 5171 if v == section:
5157 5172 ui.debug('%s: ' %
5158 5173 ui.configsource(section, name, untrusted))
5159 5174 ui.write('%s=%s\n' % (sectname, value))
5160 5175 elif v == sectname:
5161 5176 ui.debug('%s: ' %
5162 5177 ui.configsource(section, name, untrusted))
5163 5178 ui.write(value, '\n')
5164 5179 else:
5165 5180 ui.debug('%s: ' %
5166 5181 ui.configsource(section, name, untrusted))
5167 5182 ui.write('%s=%s\n' % (sectname, value))
5168 5183
5169 5184 @command('^status|st',
5170 5185 [('A', 'all', None, _('show status of all files')),
5171 5186 ('m', 'modified', None, _('show only modified files')),
5172 5187 ('a', 'added', None, _('show only added files')),
5173 5188 ('r', 'removed', None, _('show only removed files')),
5174 5189 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5175 5190 ('c', 'clean', None, _('show only files without changes')),
5176 5191 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5177 5192 ('i', 'ignored', None, _('show only ignored files')),
5178 5193 ('n', 'no-status', None, _('hide status prefix')),
5179 5194 ('C', 'copies', None, _('show source of copied files')),
5180 5195 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5181 5196 ('', 'rev', [], _('show difference from revision'), _('REV')),
5182 5197 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5183 5198 ] + walkopts + subrepoopts,
5184 5199 _('[OPTION]... [FILE]...'))
5185 5200 def status(ui, repo, *pats, **opts):
5186 5201 """show changed files in the working directory
5187 5202
5188 5203 Show status of files in the repository. If names are given, only
5189 5204 files that match are shown. Files that are clean or ignored or
5190 5205 the source of a copy/move operation, are not listed unless
5191 5206 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5192 5207 Unless options described with "show only ..." are given, the
5193 5208 options -mardu are used.
5194 5209
5195 5210 Option -q/--quiet hides untracked (unknown and ignored) files
5196 5211 unless explicitly requested with -u/--unknown or -i/--ignored.
5197 5212
5198 5213 .. note::
5199 5214 status may appear to disagree with diff if permissions have
5200 5215 changed or a merge has occurred. The standard diff format does
5201 5216 not report permission changes and diff only reports changes
5202 5217 relative to one merge parent.
5203 5218
5204 5219 If one revision is given, it is used as the base revision.
5205 5220 If two revisions are given, the differences between them are
5206 5221 shown. The --change option can also be used as a shortcut to list
5207 5222 the changed files of a revision from its first parent.
5208 5223
5209 5224 The codes used to show the status of files are::
5210 5225
5211 5226 M = modified
5212 5227 A = added
5213 5228 R = removed
5214 5229 C = clean
5215 5230 ! = missing (deleted by non-hg command, but still tracked)
5216 5231 ? = not tracked
5217 5232 I = ignored
5218 5233 = origin of the previous file listed as A (added)
5219 5234
5220 5235 .. container:: verbose
5221 5236
5222 5237 Examples:
5223 5238
5224 5239 - show changes in the working directory relative to a
5225 5240 changeset::
5226 5241
5227 5242 hg status --rev 9353
5228 5243
5229 5244 - show all changes including copies in an existing changeset::
5230 5245
5231 5246 hg status --copies --change 9353
5232 5247
5233 5248 - get a NUL separated list of added files, suitable for xargs::
5234 5249
5235 5250 hg status -an0
5236 5251
5237 5252 Returns 0 on success.
5238 5253 """
5239 5254
5240 5255 revs = opts.get('rev')
5241 5256 change = opts.get('change')
5242 5257
5243 5258 if revs and change:
5244 5259 msg = _('cannot specify --rev and --change at the same time')
5245 5260 raise util.Abort(msg)
5246 5261 elif change:
5247 5262 node2 = scmutil.revsingle(repo, change, None).node()
5248 5263 node1 = repo[node2].p1().node()
5249 5264 else:
5250 5265 node1, node2 = scmutil.revpair(repo, revs)
5251 5266
5252 5267 cwd = (pats and repo.getcwd()) or ''
5253 5268 end = opts.get('print0') and '\0' or '\n'
5254 5269 copy = {}
5255 5270 states = 'modified added removed deleted unknown ignored clean'.split()
5256 5271 show = [k for k in states if opts.get(k)]
5257 5272 if opts.get('all'):
5258 5273 show += ui.quiet and (states[:4] + ['clean']) or states
5259 5274 if not show:
5260 5275 show = ui.quiet and states[:4] or states[:5]
5261 5276
5262 5277 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5263 5278 'ignored' in show, 'clean' in show, 'unknown' in show,
5264 5279 opts.get('subrepos'))
5265 5280 changestates = zip(states, 'MAR!?IC', stat)
5266 5281
5267 5282 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5268 5283 copy = copies.pathcopies(repo[node1], repo[node2])
5269 5284
5270 5285 fm = ui.formatter('status', opts)
5271 5286 format = '%s %s' + end
5272 5287 if opts.get('no_status'):
5273 5288 format = '%.0s%s' + end
5274 5289
5275 5290 for state, char, files in changestates:
5276 5291 if state in show:
5277 5292 label = 'status.' + state
5278 5293 for f in files:
5279 5294 fm.startitem()
5280 5295 fm.write("status path", format, char,
5281 5296 repo.pathto(f, cwd), label=label)
5282 5297 if f in copy:
5283 5298 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5284 5299 label='status.copied')
5285 5300 fm.end()
5286 5301
5287 5302 @command('^summary|sum',
5288 5303 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5289 5304 def summary(ui, repo, **opts):
5290 5305 """summarize working directory state
5291 5306
5292 5307 This generates a brief summary of the working directory state,
5293 5308 including parents, branch, commit status, and available updates.
5294 5309
5295 5310 With the --remote option, this will check the default paths for
5296 5311 incoming and outgoing changes. This can be time-consuming.
5297 5312
5298 5313 Returns 0 on success.
5299 5314 """
5300 5315
5301 5316 ctx = repo[None]
5302 5317 parents = ctx.parents()
5303 5318 pnode = parents[0].node()
5304 5319 marks = []
5305 5320
5306 5321 for p in parents:
5307 5322 # label with log.changeset (instead of log.parent) since this
5308 5323 # shows a working directory parent *changeset*:
5309 5324 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5310 5325 label='log.changeset')
5311 5326 ui.write(' '.join(p.tags()), label='log.tag')
5312 5327 if p.bookmarks():
5313 5328 marks.extend(p.bookmarks())
5314 5329 if p.rev() == -1:
5315 5330 if not len(repo):
5316 5331 ui.write(_(' (empty repository)'))
5317 5332 else:
5318 5333 ui.write(_(' (no revision checked out)'))
5319 5334 ui.write('\n')
5320 5335 if p.description():
5321 5336 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5322 5337 label='log.summary')
5323 5338
5324 5339 branch = ctx.branch()
5325 5340 bheads = repo.branchheads(branch)
5326 5341 m = _('branch: %s\n') % branch
5327 5342 if branch != 'default':
5328 5343 ui.write(m, label='log.branch')
5329 5344 else:
5330 5345 ui.status(m, label='log.branch')
5331 5346
5332 5347 if marks:
5333 5348 current = repo._bookmarkcurrent
5334 5349 ui.write(_('bookmarks:'), label='log.bookmark')
5335 5350 if current is not None:
5336 5351 try:
5337 5352 marks.remove(current)
5338 5353 ui.write(' *' + current, label='bookmarks.current')
5339 5354 except ValueError:
5340 5355 # current bookmark not in parent ctx marks
5341 5356 pass
5342 5357 for m in marks:
5343 5358 ui.write(' ' + m, label='log.bookmark')
5344 5359 ui.write('\n', label='log.bookmark')
5345 5360
5346 5361 st = list(repo.status(unknown=True))[:6]
5347 5362
5348 5363 c = repo.dirstate.copies()
5349 5364 copied, renamed = [], []
5350 5365 for d, s in c.iteritems():
5351 5366 if s in st[2]:
5352 5367 st[2].remove(s)
5353 5368 renamed.append(d)
5354 5369 else:
5355 5370 copied.append(d)
5356 5371 if d in st[1]:
5357 5372 st[1].remove(d)
5358 5373 st.insert(3, renamed)
5359 5374 st.insert(4, copied)
5360 5375
5361 5376 ms = mergemod.mergestate(repo)
5362 5377 st.append([f for f in ms if ms[f] == 'u'])
5363 5378
5364 5379 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5365 5380 st.append(subs)
5366 5381
5367 5382 labels = [ui.label(_('%d modified'), 'status.modified'),
5368 5383 ui.label(_('%d added'), 'status.added'),
5369 5384 ui.label(_('%d removed'), 'status.removed'),
5370 5385 ui.label(_('%d renamed'), 'status.copied'),
5371 5386 ui.label(_('%d copied'), 'status.copied'),
5372 5387 ui.label(_('%d deleted'), 'status.deleted'),
5373 5388 ui.label(_('%d unknown'), 'status.unknown'),
5374 5389 ui.label(_('%d ignored'), 'status.ignored'),
5375 5390 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5376 5391 ui.label(_('%d subrepos'), 'status.modified')]
5377 5392 t = []
5378 5393 for s, l in zip(st, labels):
5379 5394 if s:
5380 5395 t.append(l % len(s))
5381 5396
5382 5397 t = ', '.join(t)
5383 5398 cleanworkdir = False
5384 5399
5385 5400 if len(parents) > 1:
5386 5401 t += _(' (merge)')
5387 5402 elif branch != parents[0].branch():
5388 5403 t += _(' (new branch)')
5389 5404 elif (parents[0].closesbranch() and
5390 5405 pnode in repo.branchheads(branch, closed=True)):
5391 5406 t += _(' (head closed)')
5392 5407 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5393 5408 t += _(' (clean)')
5394 5409 cleanworkdir = True
5395 5410 elif pnode not in bheads:
5396 5411 t += _(' (new branch head)')
5397 5412
5398 5413 if cleanworkdir:
5399 5414 ui.status(_('commit: %s\n') % t.strip())
5400 5415 else:
5401 5416 ui.write(_('commit: %s\n') % t.strip())
5402 5417
5403 5418 # all ancestors of branch heads - all ancestors of parent = new csets
5404 5419 new = [0] * len(repo)
5405 5420 cl = repo.changelog
5406 5421 for a in [cl.rev(n) for n in bheads]:
5407 5422 new[a] = 1
5408 5423 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5409 5424 new[a] = 1
5410 5425 for a in [p.rev() for p in parents]:
5411 5426 if a >= 0:
5412 5427 new[a] = 0
5413 5428 for a in cl.ancestors([p.rev() for p in parents]):
5414 5429 new[a] = 0
5415 5430 new = sum(new)
5416 5431
5417 5432 if new == 0:
5418 5433 ui.status(_('update: (current)\n'))
5419 5434 elif pnode not in bheads:
5420 5435 ui.write(_('update: %d new changesets (update)\n') % new)
5421 5436 else:
5422 5437 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5423 5438 (new, len(bheads)))
5424 5439
5425 5440 if opts.get('remote'):
5426 5441 t = []
5427 5442 source, branches = hg.parseurl(ui.expandpath('default'))
5428 5443 other = hg.peer(repo, {}, source)
5429 5444 revs, checkout = hg.addbranchrevs(repo, other, branches,
5430 5445 opts.get('rev'))
5431 5446 ui.debug('comparing with %s\n' % util.hidepassword(source))
5432 5447 repo.ui.pushbuffer()
5433 5448 commoninc = discovery.findcommonincoming(repo, other)
5434 5449 _common, incoming, _rheads = commoninc
5435 5450 repo.ui.popbuffer()
5436 5451 if incoming:
5437 5452 t.append(_('1 or more incoming'))
5438 5453
5439 5454 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5440 5455 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5441 5456 if source != dest:
5442 5457 other = hg.peer(repo, {}, dest)
5443 5458 commoninc = None
5444 5459 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5445 5460 repo.ui.pushbuffer()
5446 5461 outgoing = discovery.findcommonoutgoing(repo, other,
5447 5462 commoninc=commoninc)
5448 5463 repo.ui.popbuffer()
5449 5464 o = outgoing.missing
5450 5465 if o:
5451 5466 t.append(_('%d outgoing') % len(o))
5452 5467 if 'bookmarks' in other.listkeys('namespaces'):
5453 5468 lmarks = repo.listkeys('bookmarks')
5454 5469 rmarks = other.listkeys('bookmarks')
5455 5470 diff = set(rmarks) - set(lmarks)
5456 5471 if len(diff) > 0:
5457 5472 t.append(_('%d incoming bookmarks') % len(diff))
5458 5473 diff = set(lmarks) - set(rmarks)
5459 5474 if len(diff) > 0:
5460 5475 t.append(_('%d outgoing bookmarks') % len(diff))
5461 5476
5462 5477 if t:
5463 5478 ui.write(_('remote: %s\n') % (', '.join(t)))
5464 5479 else:
5465 5480 ui.status(_('remote: (synced)\n'))
5466 5481
5467 5482 @command('tag',
5468 5483 [('f', 'force', None, _('force tag')),
5469 5484 ('l', 'local', None, _('make the tag local')),
5470 5485 ('r', 'rev', '', _('revision to tag'), _('REV')),
5471 5486 ('', 'remove', None, _('remove a tag')),
5472 5487 # -l/--local is already there, commitopts cannot be used
5473 5488 ('e', 'edit', None, _('edit commit message')),
5474 5489 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5475 5490 ] + commitopts2,
5476 5491 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5477 5492 def tag(ui, repo, name1, *names, **opts):
5478 5493 """add one or more tags for the current or given revision
5479 5494
5480 5495 Name a particular revision using <name>.
5481 5496
5482 5497 Tags are used to name particular revisions of the repository and are
5483 5498 very useful to compare different revisions, to go back to significant
5484 5499 earlier versions or to mark branch points as releases, etc. Changing
5485 5500 an existing tag is normally disallowed; use -f/--force to override.
5486 5501
5487 5502 If no revision is given, the parent of the working directory is
5488 5503 used, or tip if no revision is checked out.
5489 5504
5490 5505 To facilitate version control, distribution, and merging of tags,
5491 5506 they are stored as a file named ".hgtags" which is managed similarly
5492 5507 to other project files and can be hand-edited if necessary. This
5493 5508 also means that tagging creates a new commit. The file
5494 5509 ".hg/localtags" is used for local tags (not shared among
5495 5510 repositories).
5496 5511
5497 5512 Tag commits are usually made at the head of a branch. If the parent
5498 5513 of the working directory is not a branch head, :hg:`tag` aborts; use
5499 5514 -f/--force to force the tag commit to be based on a non-head
5500 5515 changeset.
5501 5516
5502 5517 See :hg:`help dates` for a list of formats valid for -d/--date.
5503 5518
5504 5519 Since tag names have priority over branch names during revision
5505 5520 lookup, using an existing branch name as a tag name is discouraged.
5506 5521
5507 5522 Returns 0 on success.
5508 5523 """
5509 5524 wlock = lock = None
5510 5525 try:
5511 5526 wlock = repo.wlock()
5512 5527 lock = repo.lock()
5513 5528 rev_ = "."
5514 5529 names = [t.strip() for t in (name1,) + names]
5515 5530 if len(names) != len(set(names)):
5516 5531 raise util.Abort(_('tag names must be unique'))
5517 5532 for n in names:
5518 5533 if n in ['tip', '.', 'null']:
5519 5534 raise util.Abort(_("the name '%s' is reserved") % n)
5520 5535 if not n:
5521 5536 raise util.Abort(_('tag names cannot consist entirely of '
5522 5537 'whitespace'))
5523 5538 if opts.get('rev') and opts.get('remove'):
5524 5539 raise util.Abort(_("--rev and --remove are incompatible"))
5525 5540 if opts.get('rev'):
5526 5541 rev_ = opts['rev']
5527 5542 message = opts.get('message')
5528 5543 if opts.get('remove'):
5529 5544 expectedtype = opts.get('local') and 'local' or 'global'
5530 5545 for n in names:
5531 5546 if not repo.tagtype(n):
5532 5547 raise util.Abort(_("tag '%s' does not exist") % n)
5533 5548 if repo.tagtype(n) != expectedtype:
5534 5549 if expectedtype == 'global':
5535 5550 raise util.Abort(_("tag '%s' is not a global tag") % n)
5536 5551 else:
5537 5552 raise util.Abort(_("tag '%s' is not a local tag") % n)
5538 5553 rev_ = nullid
5539 5554 if not message:
5540 5555 # we don't translate commit messages
5541 5556 message = 'Removed tag %s' % ', '.join(names)
5542 5557 elif not opts.get('force'):
5543 5558 for n in names:
5544 5559 if n in repo.tags():
5545 5560 raise util.Abort(_("tag '%s' already exists "
5546 5561 "(use -f to force)") % n)
5547 5562 if not opts.get('local'):
5548 5563 p1, p2 = repo.dirstate.parents()
5549 5564 if p2 != nullid:
5550 5565 raise util.Abort(_('uncommitted merge'))
5551 5566 bheads = repo.branchheads()
5552 5567 if not opts.get('force') and bheads and p1 not in bheads:
5553 5568 raise util.Abort(_('not at a branch head (use -f to force)'))
5554 5569 r = scmutil.revsingle(repo, rev_).node()
5555 5570
5556 5571 if not message:
5557 5572 # we don't translate commit messages
5558 5573 message = ('Added tag %s for changeset %s' %
5559 5574 (', '.join(names), short(r)))
5560 5575
5561 5576 date = opts.get('date')
5562 5577 if date:
5563 5578 date = util.parsedate(date)
5564 5579
5565 5580 if opts.get('edit'):
5566 5581 message = ui.edit(message, ui.username())
5567 5582
5568 5583 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5569 5584 finally:
5570 5585 release(lock, wlock)
5571 5586
5572 5587 @command('tags', [], '')
5573 5588 def tags(ui, repo):
5574 5589 """list repository tags
5575 5590
5576 5591 This lists both regular and local tags. When the -v/--verbose
5577 5592 switch is used, a third column "local" is printed for local tags.
5578 5593
5579 5594 Returns 0 on success.
5580 5595 """
5581 5596
5582 5597 hexfunc = ui.debugflag and hex or short
5583 5598 tagtype = ""
5584 5599
5585 5600 for t, n in reversed(repo.tagslist()):
5586 5601 if ui.quiet:
5587 5602 ui.write("%s\n" % t, label='tags.normal')
5588 5603 continue
5589 5604
5590 5605 hn = hexfunc(n)
5591 5606 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5592 5607 rev = ui.label(r, 'log.changeset')
5593 5608 spaces = " " * (30 - encoding.colwidth(t))
5594 5609
5595 5610 tag = ui.label(t, 'tags.normal')
5596 5611 if ui.verbose:
5597 5612 if repo.tagtype(t) == 'local':
5598 5613 tagtype = " local"
5599 5614 tag = ui.label(t, 'tags.local')
5600 5615 else:
5601 5616 tagtype = ""
5602 5617 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5603 5618
5604 5619 @command('tip',
5605 5620 [('p', 'patch', None, _('show patch')),
5606 5621 ('g', 'git', None, _('use git extended diff format')),
5607 5622 ] + templateopts,
5608 5623 _('[-p] [-g]'))
5609 5624 def tip(ui, repo, **opts):
5610 5625 """show the tip revision
5611 5626
5612 5627 The tip revision (usually just called the tip) is the changeset
5613 5628 most recently added to the repository (and therefore the most
5614 5629 recently changed head).
5615 5630
5616 5631 If you have just made a commit, that commit will be the tip. If
5617 5632 you have just pulled changes from another repository, the tip of
5618 5633 that repository becomes the current tip. The "tip" tag is special
5619 5634 and cannot be renamed or assigned to a different changeset.
5620 5635
5621 5636 Returns 0 on success.
5622 5637 """
5623 5638 displayer = cmdutil.show_changeset(ui, repo, opts)
5624 5639 displayer.show(repo[len(repo) - 1])
5625 5640 displayer.close()
5626 5641
5627 5642 @command('unbundle',
5628 5643 [('u', 'update', None,
5629 5644 _('update to new branch head if changesets were unbundled'))],
5630 5645 _('[-u] FILE...'))
5631 5646 def unbundle(ui, repo, fname1, *fnames, **opts):
5632 5647 """apply one or more changegroup files
5633 5648
5634 5649 Apply one or more compressed changegroup files generated by the
5635 5650 bundle command.
5636 5651
5637 5652 Returns 0 on success, 1 if an update has unresolved files.
5638 5653 """
5639 5654 fnames = (fname1,) + fnames
5640 5655
5641 5656 lock = repo.lock()
5642 5657 wc = repo['.']
5643 5658 try:
5644 5659 for fname in fnames:
5645 5660 f = url.open(ui, fname)
5646 5661 gen = changegroup.readbundle(f, fname)
5647 5662 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5648 5663 finally:
5649 5664 lock.release()
5650 5665 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5651 5666 return postincoming(ui, repo, modheads, opts.get('update'), None)
5652 5667
5653 5668 @command('^update|up|checkout|co',
5654 5669 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5655 5670 ('c', 'check', None,
5656 5671 _('update across branches if no uncommitted changes')),
5657 5672 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5658 5673 ('r', 'rev', '', _('revision'), _('REV'))],
5659 5674 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5660 5675 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5661 5676 """update working directory (or switch revisions)
5662 5677
5663 5678 Update the repository's working directory to the specified
5664 5679 changeset. If no changeset is specified, update to the tip of the
5665 5680 current named branch and move the current bookmark (see :hg:`help
5666 5681 bookmarks`).
5667 5682
5668 5683 If the changeset is not a descendant or ancestor of the working
5669 5684 directory's parent, the update is aborted. With the -c/--check
5670 5685 option, the working directory is checked for uncommitted changes; if
5671 5686 none are found, the working directory is updated to the specified
5672 5687 changeset.
5673 5688
5674 5689 Update sets the working directory's parent revison to the specified
5675 5690 changeset (see :hg:`help parents`).
5676 5691
5677 5692 The following rules apply when the working directory contains
5678 5693 uncommitted changes:
5679 5694
5680 5695 1. If neither -c/--check nor -C/--clean is specified, and if
5681 5696 the requested changeset is an ancestor or descendant of
5682 5697 the working directory's parent, the uncommitted changes
5683 5698 are merged into the requested changeset and the merged
5684 5699 result is left uncommitted. If the requested changeset is
5685 5700 not an ancestor or descendant (that is, it is on another
5686 5701 branch), the update is aborted and the uncommitted changes
5687 5702 are preserved.
5688 5703
5689 5704 2. With the -c/--check option, the update is aborted and the
5690 5705 uncommitted changes are preserved.
5691 5706
5692 5707 3. With the -C/--clean option, uncommitted changes are discarded and
5693 5708 the working directory is updated to the requested changeset.
5694 5709
5695 5710 Use null as the changeset to remove the working directory (like
5696 5711 :hg:`clone -U`).
5697 5712
5698 5713 If you want to revert just one file to an older revision, use
5699 5714 :hg:`revert [-r REV] NAME`.
5700 5715
5701 5716 See :hg:`help dates` for a list of formats valid for -d/--date.
5702 5717
5703 5718 Returns 0 on success, 1 if there are unresolved files.
5704 5719 """
5705 5720 if rev and node:
5706 5721 raise util.Abort(_("please specify just one revision"))
5707 5722
5708 5723 if rev is None or rev == '':
5709 5724 rev = node
5710 5725
5711 5726 # with no argument, we also move the current bookmark, if any
5712 5727 movemarkfrom = None
5713 5728 if rev is None or node == '':
5714 5729 movemarkfrom = repo['.'].node()
5715 5730
5716 5731 # if we defined a bookmark, we have to remember the original bookmark name
5717 5732 brev = rev
5718 5733 rev = scmutil.revsingle(repo, rev, rev).rev()
5719 5734
5720 5735 if check and clean:
5721 5736 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5722 5737
5723 5738 if date:
5724 5739 if rev is not None:
5725 5740 raise util.Abort(_("you can't specify a revision and a date"))
5726 5741 rev = cmdutil.finddate(ui, repo, date)
5727 5742
5728 5743 if check:
5729 5744 c = repo[None]
5730 5745 if c.dirty(merge=False, branch=False):
5731 5746 raise util.Abort(_("uncommitted local changes"))
5732 5747 if rev is None:
5733 5748 rev = repo[repo[None].branch()].rev()
5734 5749 mergemod._checkunknown(repo, repo[None], repo[rev])
5735 5750
5736 5751 if clean:
5737 5752 ret = hg.clean(repo, rev)
5738 5753 else:
5739 5754 ret = hg.update(repo, rev)
5740 5755
5741 5756 if not ret and movemarkfrom:
5742 5757 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5743 5758 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5744 5759 elif brev in repo._bookmarks:
5745 5760 bookmarks.setcurrent(repo, brev)
5746 5761 elif brev:
5747 5762 bookmarks.unsetcurrent(repo)
5748 5763
5749 5764 return ret
5750 5765
5751 5766 @command('verify', [])
5752 5767 def verify(ui, repo):
5753 5768 """verify the integrity of the repository
5754 5769
5755 5770 Verify the integrity of the current repository.
5756 5771
5757 5772 This will perform an extensive check of the repository's
5758 5773 integrity, validating the hashes and checksums of each entry in
5759 5774 the changelog, manifest, and tracked files, as well as the
5760 5775 integrity of their crosslinks and indices.
5761 5776
5762 5777 Returns 0 on success, 1 if errors are encountered.
5763 5778 """
5764 5779 return hg.verify(repo)
5765 5780
5766 5781 @command('version', [])
5767 5782 def version_(ui):
5768 5783 """output version and copyright information"""
5769 5784 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5770 5785 % util.version())
5771 5786 ui.status(_(
5772 5787 "(see http://mercurial.selenic.com for more information)\n"
5773 5788 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5774 5789 "This is free software; see the source for copying conditions. "
5775 5790 "There is NO\nwarranty; "
5776 5791 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5777 5792 ))
5778 5793
5779 5794 norepo = ("clone init version help debugcommands debugcomplete"
5780 5795 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5781 5796 " debugknown debuggetbundle debugbundle")
5782 5797 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5783 5798 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,175 +1,192 b''
1 1 # obsolete.py - obsolete markers handling
2 2 #
3 3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 4 # Logilab SA <contact@logilab.fr>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 """Obsolete markers handling
10 10
11 11 An obsolete marker maps an old changeset to a list of new
12 12 changesets. If the list of new changesets is empty, the old changeset
13 13 is said to be "killed". Otherwise, the old changeset is being
14 14 "replaced" by the new changesets.
15 15
16 16 Obsolete markers can be used to record and distribute changeset graph
17 17 transformations performed by history rewriting operations, and help
18 18 building new tools to reconciliate conflicting rewriting actions. To
19 19 facilitate conflicts resolution, markers include various annotations
20 20 besides old and news changeset identifiers, such as creation date or
21 21 author name.
22 22
23 23
24 24 Format
25 25 ------
26 26
27 27 Markers are stored in an append-only file stored in
28 28 '.hg/store/obsstore'.
29 29
30 30 The file starts with a version header:
31 31
32 32 - 1 unsigned byte: version number, starting at zero.
33 33
34 34
35 35 The header is followed by the markers. Each marker is made of:
36 36
37 37 - 1 unsigned byte: number of new changesets "R", could be zero.
38 38
39 39 - 1 unsigned 32-bits integer: metadata size "M" in bytes.
40 40
41 41 - 1 byte: a bit field. It is reserved for flags used in obsolete
42 42 markers common operations, to avoid repeated decoding of metadata
43 43 entries.
44 44
45 45 - 20 bytes: obsoleted changeset identifier.
46 46
47 47 - N*20 bytes: new changesets identifiers.
48 48
49 49 - M bytes: metadata as a sequence of nul-terminated strings. Each
50 50 string contains a key and a value, separated by a color ':', without
51 51 additional encoding. Keys cannot contain '\0' or ':' and values
52 52 cannot contain '\0'.
53 53 """
54 54 import struct
55 55 from mercurial import util
56 56 from i18n import _
57 57
58 58 _pack = struct.pack
59 59 _unpack = struct.unpack
60 60
61 61
62 62
63 63 # data used for parsing and writing
64 64 _fmversion = 0
65 65 _fmfixed = '>BIB20s'
66 66 _fmnode = '20s'
67 67 _fmfsize = struct.calcsize(_fmfixed)
68 68 _fnodesize = struct.calcsize(_fmnode)
69 69
70 70 def _readmarkers(data):
71 71 """Read and enumerate markers from raw data"""
72 72 off = 0
73 73 diskversion = _unpack('>B', data[off:off + 1])[0]
74 74 off += 1
75 75 if diskversion != _fmversion:
76 76 raise util.Abort(_('parsing obsolete marker: unknown version %r')
77 77 % diskversion)
78 78
79 79 # Loop on markers
80 80 l = len(data)
81 81 while off + _fmfsize <= l:
82 82 # read fixed part
83 83 cur = data[off:off + _fmfsize]
84 84 off += _fmfsize
85 85 nbsuc, mdsize, flags, pre = _unpack(_fmfixed, cur)
86 86 # read replacement
87 87 sucs = ()
88 88 if nbsuc:
89 89 s = (_fnodesize * nbsuc)
90 90 cur = data[off:off + s]
91 91 sucs = _unpack(_fmnode * nbsuc, cur)
92 92 off += s
93 93 # read metadata
94 94 # (metadata will be decoded on demand)
95 95 metadata = data[off:off + mdsize]
96 96 if len(metadata) != mdsize:
97 97 raise util.Abort(_('parsing obsolete marker: metadata is too '
98 98 'short, %d bytes expected, got %d')
99 99 % (len(metadata), mdsize))
100 100 off += mdsize
101 101 yield (pre, sucs, flags, metadata)
102 102
103 103 def encodemeta(meta):
104 104 """Return encoded metadata string to string mapping.
105 105
106 106 Assume no ':' in key and no '\0' in both key and value."""
107 107 for key, value in meta.iteritems():
108 108 if ':' in key or '\0' in key:
109 109 raise ValueError("':' and '\0' are forbidden in metadata key'")
110 110 if '\0' in value:
111 111 raise ValueError("':' are forbidden in metadata value'")
112 112 return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
113 113
114 114 def decodemeta(data):
115 115 """Return string to string dictionary from encoded version."""
116 116 d = {}
117 117 for l in data.split('\0'):
118 118 if l:
119 119 key, value = l.split(':')
120 120 d[key] = value
121 121 return d
122 122
123 123 class obsstore(object):
124 124 """Store obsolete markers
125 125
126 126 Markers can be accessed with two mappings:
127 127 - precursors: old -> set(new)
128 128 - successors: new -> set(old)
129 129 """
130 130
131 131 def __init__(self):
132 132 self._all = []
133 133 # new markers to serialize
134 134 self._new = []
135 135 self.precursors = {}
136 136 self.successors = {}
137 137
138 def create(self, prec, succs=(), flag=0, metadata=None):
139 """obsolete: add a new obsolete marker
140
141 * ensuring it is hashable
142 * check mandatory metadata
143 * encode metadata
144 """
145 if metadata is None:
146 metadata = {}
147 if len(prec) != 20:
148 raise ValueError(prec)
149 for succ in succs:
150 if len(succ) != 20:
151 raise ValueError(prec)
152 marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata))
153 self.add(marker)
154
138 155 def add(self, marker):
139 156 """Add a new marker to the store
140 157
141 158 This marker still needs to be written to disk"""
142 159 self._new.append(marker)
143 160 self._load(marker)
144 161
145 162 def loadmarkers(self, data):
146 163 """Load all markers in data, mark them as known."""
147 164 for marker in _readmarkers(data):
148 165 self._load(marker)
149 166
150 167 def flushmarkers(self, stream):
151 168 """Write all markers to a stream
152 169
153 170 After this operation, "new" markers are considered "known"."""
154 171 self._writemarkers(stream)
155 172 self._new[:] = []
156 173
157 174 def _load(self, marker):
158 175 self._all.append(marker)
159 176 pre, sucs = marker[:2]
160 177 self.precursors.setdefault(pre, set()).add(marker)
161 178 for suc in sucs:
162 179 self.successors.setdefault(suc, set()).add(marker)
163 180
164 181 def _writemarkers(self, stream):
165 182 # Kept separate from flushmarkers(), it will be reused for
166 183 # markers exchange.
167 184 stream.write(_pack('>B', _fmversion))
168 185 for marker in self._all:
169 186 pre, sucs, flags, metadata = marker
170 187 nbsuc = len(sucs)
171 188 format = _fmfixed + (_fmnode * nbsuc)
172 189 data = [nbsuc, len(metadata), flags, pre]
173 190 data.extend(sucs)
174 191 stream.write(_pack(format, *data))
175 192 stream.write(metadata)
@@ -1,274 +1,276 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 add
4 4 addremove
5 5 annotate
6 6 archive
7 7 backout
8 8 bisect
9 9 bookmarks
10 10 branch
11 11 branches
12 12 bundle
13 13 cat
14 14 clone
15 15 commit
16 16 copy
17 17 diff
18 18 export
19 19 forget
20 20 graft
21 21 grep
22 22 heads
23 23 help
24 24 identify
25 25 import
26 26 incoming
27 27 init
28 28 locate
29 29 log
30 30 manifest
31 31 merge
32 32 outgoing
33 33 parents
34 34 paths
35 35 phase
36 36 pull
37 37 push
38 38 recover
39 39 remove
40 40 rename
41 41 resolve
42 42 revert
43 43 rollback
44 44 root
45 45 serve
46 46 showconfig
47 47 status
48 48 summary
49 49 tag
50 50 tags
51 51 tip
52 52 unbundle
53 53 update
54 54 verify
55 55 version
56 56
57 57 Show all commands that start with "a"
58 58 $ hg debugcomplete a
59 59 add
60 60 addremove
61 61 annotate
62 62 archive
63 63
64 64 Do not show debug commands if there are other candidates
65 65 $ hg debugcomplete d
66 66 diff
67 67
68 68 Show debug commands if there are no other candidates
69 69 $ hg debugcomplete debug
70 70 debugancestor
71 71 debugbuilddag
72 72 debugbundle
73 73 debugcheckstate
74 74 debugcommands
75 75 debugcomplete
76 76 debugconfig
77 77 debugdag
78 78 debugdata
79 79 debugdate
80 80 debugdiscovery
81 81 debugfileset
82 82 debugfsinfo
83 83 debuggetbundle
84 84 debugignore
85 85 debugindex
86 86 debugindexdot
87 87 debuginstall
88 88 debugknown
89 debugobsolete
89 90 debugpushkey
90 91 debugpvec
91 92 debugrebuildstate
92 93 debugrename
93 94 debugrevlog
94 95 debugrevspec
95 96 debugsetparents
96 97 debugstate
97 98 debugsub
98 99 debugwalk
99 100 debugwireargs
100 101
101 102 Do not show the alias of a debug command if there are other candidates
102 103 (this should hide rawcommit)
103 104 $ hg debugcomplete r
104 105 recover
105 106 remove
106 107 rename
107 108 resolve
108 109 revert
109 110 rollback
110 111 root
111 112 Show the alias of a debug command if there are no other candidates
112 113 $ hg debugcomplete rawc
113 114
114 115
115 116 Show the global options
116 117 $ hg debugcomplete --options | sort
117 118 --config
118 119 --cwd
119 120 --debug
120 121 --debugger
121 122 --encoding
122 123 --encodingmode
123 124 --help
124 125 --noninteractive
125 126 --profile
126 127 --quiet
127 128 --repository
128 129 --time
129 130 --traceback
130 131 --verbose
131 132 --version
132 133 -R
133 134 -h
134 135 -q
135 136 -v
136 137 -y
137 138
138 139 Show the options for the "serve" command
139 140 $ hg debugcomplete --options serve | sort
140 141 --accesslog
141 142 --address
142 143 --certificate
143 144 --cmdserver
144 145 --config
145 146 --cwd
146 147 --daemon
147 148 --daemon-pipefds
148 149 --debug
149 150 --debugger
150 151 --encoding
151 152 --encodingmode
152 153 --errorlog
153 154 --help
154 155 --ipv6
155 156 --name
156 157 --noninteractive
157 158 --pid-file
158 159 --port
159 160 --prefix
160 161 --profile
161 162 --quiet
162 163 --repository
163 164 --stdio
164 165 --style
165 166 --templates
166 167 --time
167 168 --traceback
168 169 --verbose
169 170 --version
170 171 --web-conf
171 172 -6
172 173 -A
173 174 -E
174 175 -R
175 176 -a
176 177 -d
177 178 -h
178 179 -n
179 180 -p
180 181 -q
181 182 -t
182 183 -v
183 184 -y
184 185
185 186 Show an error if we use --options with an ambiguous abbreviation
186 187 $ hg debugcomplete --options s
187 188 hg: command 's' is ambiguous:
188 189 serve showconfig status summary
189 190 [255]
190 191
191 192 Show all commands + options
192 193 $ hg debugcommands
193 194 add: include, exclude, subrepos, dry-run
194 195 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
195 196 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
196 197 commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
197 198 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
198 199 export: output, switch-parent, rev, text, git, nodates
199 200 forget: include, exclude
200 201 init: ssh, remotecmd, insecure
201 202 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, style, template, include, exclude
202 203 merge: force, rev, preview, tool
203 204 phase: public, draft, secret, force, rev
204 205 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
205 206 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
206 207 remove: after, force, include, exclude
207 208 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
208 209 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
209 210 summary: remote
210 211 update: clean, check, date, rev
211 212 addremove: similarity, include, exclude, dry-run
212 213 archive: no-decode, prefix, rev, type, subrepos, include, exclude
213 214 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
214 215 bisect: reset, good, bad, skip, extend, command, noupdate
215 216 bookmarks: force, rev, delete, rename, inactive
216 217 branch: force, clean
217 218 branches: active, closed
218 219 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
219 220 cat: output, rev, decode, include, exclude
220 221 copy: after, force, include, exclude, dry-run
221 222 debugancestor:
222 223 debugbuilddag: mergeable-file, overwritten-file, new-file
223 224 debugbundle: all
224 225 debugcheckstate:
225 226 debugcommands:
226 227 debugcomplete: options
227 228 debugdag: tags, branches, dots, spaces
228 229 debugdata: changelog, manifest
229 230 debugdate: extended
230 231 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
231 232 debugfileset:
232 233 debugfsinfo:
233 234 debuggetbundle: head, common, type
234 235 debugignore:
235 236 debugindex: changelog, manifest, format
236 237 debugindexdot:
237 238 debuginstall:
238 239 debugknown:
240 debugobsolete: date, user
239 241 debugpushkey:
240 242 debugpvec:
241 243 debugrebuildstate: rev
242 244 debugrename: rev
243 245 debugrevlog: changelog, manifest, dump
244 246 debugrevspec:
245 247 debugsetparents:
246 248 debugstate: nodates, datesort
247 249 debugsub: rev
248 250 debugwalk: include, exclude
249 251 debugwireargs: three, four, five, ssh, remotecmd, insecure
250 252 graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
251 253 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
252 254 heads: rev, topo, active, closed, style, template
253 255 help: extension, command, keyword
254 256 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
255 257 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
256 258 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
257 259 locate: rev, print0, fullpath, include, exclude
258 260 manifest: rev, all
259 261 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
260 262 parents: rev, style, template
261 263 paths:
262 264 recover:
263 265 rename: after, force, include, exclude, dry-run
264 266 resolve: all, list, mark, unmark, no-status, tool, include, exclude
265 267 revert: all, date, rev, no-backup, include, exclude, dry-run
266 268 rollback: dry-run, force
267 269 root:
268 270 showconfig: untrusted
269 271 tag: force, local, rev, remove, edit, message, date, user
270 272 tags:
271 273 tip: patch, git, style, template
272 274 unbundle: update
273 275 verify:
274 276 version:
General Comments 0
You need to be logged in to leave comments. Login now