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