##// END OF EJS Templates
subrepos: abort commit by default if a subrepo is dirty (BC)...
Martin Geisler -
r15321:e174353e stable
parent child Browse files
Show More
@@ -1,5635 +1,5639 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import hex, bin, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _, gettext
11 11 import os, re, difflib, time, tempfile, errno
12 12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 13 import patch, help, url, encoding, templatekw, discovery
14 14 import archival, changegroup, cmdutil, hbisect
15 15 import sshserver, hgweb, hgweb.server, commandserver
16 16 import merge as mergemod
17 17 import minirst, revset, fileset
18 18 import dagparser, context, simplemerge
19 19 import random, setdiscovery, treediscovery, dagutil
20 20
21 21 table = {}
22 22
23 23 command = cmdutil.command(table)
24 24
25 25 # common command options
26 26
27 27 globalopts = [
28 28 ('R', 'repository', '',
29 29 _('repository root directory or name of overlay bundle file'),
30 30 _('REPO')),
31 31 ('', 'cwd', '',
32 32 _('change working directory'), _('DIR')),
33 33 ('y', 'noninteractive', None,
34 34 _('do not prompt, automatically pick the first choice for all prompts')),
35 35 ('q', 'quiet', None, _('suppress output')),
36 36 ('v', 'verbose', None, _('enable additional output')),
37 37 ('', 'config', [],
38 38 _('set/override config option (use \'section.name=value\')'),
39 39 _('CONFIG')),
40 40 ('', 'debug', None, _('enable debugging output')),
41 41 ('', 'debugger', None, _('start debugger')),
42 42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 43 _('ENCODE')),
44 44 ('', 'encodingmode', encoding.encodingmode,
45 45 _('set the charset encoding mode'), _('MODE')),
46 46 ('', 'traceback', None, _('always print a traceback on exception')),
47 47 ('', 'time', None, _('time how long the command takes')),
48 48 ('', 'profile', None, _('print command execution profile')),
49 49 ('', 'version', None, _('output version information and exit')),
50 50 ('h', 'help', None, _('display help and exit')),
51 51 ]
52 52
53 53 dryrunopts = [('n', 'dry-run', None,
54 54 _('do not perform actions, just print output'))]
55 55
56 56 remoteopts = [
57 57 ('e', 'ssh', '',
58 58 _('specify ssh command to use'), _('CMD')),
59 59 ('', 'remotecmd', '',
60 60 _('specify hg command to run on the remote side'), _('CMD')),
61 61 ('', 'insecure', None,
62 62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 63 ]
64 64
65 65 walkopts = [
66 66 ('I', 'include', [],
67 67 _('include names matching the given patterns'), _('PATTERN')),
68 68 ('X', 'exclude', [],
69 69 _('exclude names matching the given patterns'), _('PATTERN')),
70 70 ]
71 71
72 72 commitopts = [
73 73 ('m', 'message', '',
74 74 _('use text as commit message'), _('TEXT')),
75 75 ('l', 'logfile', '',
76 76 _('read commit message from file'), _('FILE')),
77 77 ]
78 78
79 79 commitopts2 = [
80 80 ('d', 'date', '',
81 81 _('record the specified date as commit date'), _('DATE')),
82 82 ('u', 'user', '',
83 83 _('record the specified user as committer'), _('USER')),
84 84 ]
85 85
86 86 templateopts = [
87 87 ('', 'style', '',
88 88 _('display using template map file'), _('STYLE')),
89 89 ('', 'template', '',
90 90 _('display with template'), _('TEMPLATE')),
91 91 ]
92 92
93 93 logopts = [
94 94 ('p', 'patch', None, _('show patch')),
95 95 ('g', 'git', None, _('use git extended diff format')),
96 96 ('l', 'limit', '',
97 97 _('limit number of changes displayed'), _('NUM')),
98 98 ('M', 'no-merges', None, _('do not show merges')),
99 99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 100 ] + templateopts
101 101
102 102 diffopts = [
103 103 ('a', 'text', None, _('treat all files as text')),
104 104 ('g', 'git', None, _('use git extended diff format')),
105 105 ('', 'nodates', None, _('omit dates from diff headers'))
106 106 ]
107 107
108 108 diffopts2 = [
109 109 ('p', 'show-function', None, _('show which function each change is in')),
110 110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 111 ('w', 'ignore-all-space', None,
112 112 _('ignore white space when comparing lines')),
113 113 ('b', 'ignore-space-change', None,
114 114 _('ignore changes in the amount of white space')),
115 115 ('B', 'ignore-blank-lines', None,
116 116 _('ignore changes whose lines are all blank')),
117 117 ('U', 'unified', '',
118 118 _('number of lines of context to show'), _('NUM')),
119 119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 120 ]
121 121
122 122 mergetoolopts = [
123 123 ('t', 'tool', '', _('specify merge tool')),
124 124 ]
125 125
126 126 similarityopts = [
127 127 ('s', 'similarity', '',
128 128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 129 ]
130 130
131 131 subrepoopts = [
132 132 ('S', 'subrepos', None,
133 133 _('recurse into subrepositories'))
134 134 ]
135 135
136 136 # Commands start here, listed alphabetically
137 137
138 138 @command('^add',
139 139 walkopts + subrepoopts + dryrunopts,
140 140 _('[OPTION]... [FILE]...'))
141 141 def add(ui, repo, *pats, **opts):
142 142 """add the specified files on the next commit
143 143
144 144 Schedule files to be version controlled and added to the
145 145 repository.
146 146
147 147 The files will be added to the repository at the next commit. To
148 148 undo an add before that, see :hg:`forget`.
149 149
150 150 If no names are given, add all files to the repository.
151 151
152 152 .. container:: verbose
153 153
154 154 An example showing how new (unknown) files are added
155 155 automatically by :hg:`add`::
156 156
157 157 $ ls
158 158 foo.c
159 159 $ hg status
160 160 ? foo.c
161 161 $ hg add
162 162 adding foo.c
163 163 $ hg status
164 164 A foo.c
165 165
166 166 Returns 0 if all files are successfully added.
167 167 """
168 168
169 169 m = scmutil.match(repo[None], pats, opts)
170 170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 171 opts.get('subrepos'), prefix="")
172 172 return rejected and 1 or 0
173 173
174 174 @command('addremove',
175 175 similarityopts + walkopts + dryrunopts,
176 176 _('[OPTION]... [FILE]...'))
177 177 def addremove(ui, repo, *pats, **opts):
178 178 """add all new files, delete all missing files
179 179
180 180 Add all new files and remove all missing files from the
181 181 repository.
182 182
183 183 New files are ignored if they match any of the patterns in
184 184 ``.hgignore``. As with add, these changes take effect at the next
185 185 commit.
186 186
187 187 Use the -s/--similarity option to detect renamed files. With a
188 188 parameter greater than 0, this compares every removed file with
189 189 every added file and records those similar enough as renames. This
190 190 option takes a percentage between 0 (disabled) and 100 (files must
191 191 be identical) as its parameter. Detecting renamed files this way
192 192 can be expensive. After using this option, :hg:`status -C` can be
193 193 used to check which files were identified as moved or renamed.
194 194
195 195 Returns 0 if all files are successfully added.
196 196 """
197 197 try:
198 198 sim = float(opts.get('similarity') or 100)
199 199 except ValueError:
200 200 raise util.Abort(_('similarity must be a number'))
201 201 if sim < 0 or sim > 100:
202 202 raise util.Abort(_('similarity must be between 0 and 100'))
203 203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204 204
205 205 @command('^annotate|blame',
206 206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 207 ('', 'follow', None,
208 208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 210 ('a', 'text', None, _('treat all files as text')),
211 211 ('u', 'user', None, _('list the author (long with -v)')),
212 212 ('f', 'file', None, _('list the filename')),
213 213 ('d', 'date', None, _('list the date (short with -q)')),
214 214 ('n', 'number', None, _('list the revision number (default)')),
215 215 ('c', 'changeset', None, _('list the changeset')),
216 216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 217 ] + walkopts,
218 218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 219 def annotate(ui, repo, *pats, **opts):
220 220 """show changeset information by line for each file
221 221
222 222 List changes in files, showing the revision id responsible for
223 223 each line
224 224
225 225 This command is useful for discovering when a change was made and
226 226 by whom.
227 227
228 228 Without the -a/--text option, annotate will avoid processing files
229 229 it detects as binary. With -a, annotate will annotate the file
230 230 anyway, although the results will probably be neither useful
231 231 nor desirable.
232 232
233 233 Returns 0 on success.
234 234 """
235 235 if opts.get('follow'):
236 236 # --follow is deprecated and now just an alias for -f/--file
237 237 # to mimic the behavior of Mercurial before version 1.5
238 238 opts['file'] = True
239 239
240 240 datefunc = ui.quiet and util.shortdate or util.datestr
241 241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242 242
243 243 if not pats:
244 244 raise util.Abort(_('at least one filename or pattern is required'))
245 245
246 246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 247 ('number', ' ', lambda x: str(x[0].rev())),
248 248 ('changeset', ' ', lambda x: short(x[0].node())),
249 249 ('date', ' ', getdate),
250 250 ('file', ' ', lambda x: x[0].path()),
251 251 ('line_number', ':', lambda x: str(x[1])),
252 252 ]
253 253
254 254 if (not opts.get('user') and not opts.get('changeset')
255 255 and not opts.get('date') and not opts.get('file')):
256 256 opts['number'] = True
257 257
258 258 linenumber = opts.get('line_number') is not None
259 259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261 261
262 262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264 264
265 265 def bad(x, y):
266 266 raise util.Abort("%s: %s" % (x, y))
267 267
268 268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 269 m = scmutil.match(ctx, pats, opts)
270 270 m.bad = bad
271 271 follow = not opts.get('no_follow')
272 272 for abs in ctx.walk(m):
273 273 fctx = ctx[abs]
274 274 if not opts.get('text') and util.binary(fctx.data()):
275 275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 276 continue
277 277
278 278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 279 pieces = []
280 280
281 281 for f, sep in funcmap:
282 282 l = [f(n) for n, dummy in lines]
283 283 if l:
284 284 sized = [(x, encoding.colwidth(x)) for x in l]
285 285 ml = max([w for x, w in sized])
286 286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 287 for x, w in sized])
288 288
289 289 if pieces:
290 290 for p, l in zip(zip(*pieces), lines):
291 291 ui.write("%s: %s" % ("".join(p), l[1]))
292 292
293 293 @command('archive',
294 294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 296 _('PREFIX')),
297 297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 299 ] + subrepoopts + walkopts,
300 300 _('[OPTION]... DEST'))
301 301 def archive(ui, repo, dest, **opts):
302 302 '''create an unversioned archive of a repository revision
303 303
304 304 By default, the revision used is the parent of the working
305 305 directory; use -r/--rev to specify a different revision.
306 306
307 307 The archive type is automatically detected based on file
308 308 extension (or override using -t/--type).
309 309
310 310 .. container:: verbose
311 311
312 312 Examples:
313 313
314 314 - create a zip file containing the 1.0 release::
315 315
316 316 hg archive -r 1.0 project-1.0.zip
317 317
318 318 - create a tarball excluding .hg files::
319 319
320 320 hg archive project.tar.gz -X ".hg*"
321 321
322 322 Valid types are:
323 323
324 324 :``files``: a directory full of files (default)
325 325 :``tar``: tar archive, uncompressed
326 326 :``tbz2``: tar archive, compressed using bzip2
327 327 :``tgz``: tar archive, compressed using gzip
328 328 :``uzip``: zip archive, uncompressed
329 329 :``zip``: zip archive, compressed using deflate
330 330
331 331 The exact name of the destination archive or directory is given
332 332 using a format string; see :hg:`help export` for details.
333 333
334 334 Each member added to an archive file has a directory prefix
335 335 prepended. Use -p/--prefix to specify a format string for the
336 336 prefix. The default is the basename of the archive, with suffixes
337 337 removed.
338 338
339 339 Returns 0 on success.
340 340 '''
341 341
342 342 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 343 if not ctx:
344 344 raise util.Abort(_('no working directory: please specify a revision'))
345 345 node = ctx.node()
346 346 dest = cmdutil.makefilename(repo, dest, node)
347 347 if os.path.realpath(dest) == repo.root:
348 348 raise util.Abort(_('repository root cannot be destination'))
349 349
350 350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 351 prefix = opts.get('prefix')
352 352
353 353 if dest == '-':
354 354 if kind == 'files':
355 355 raise util.Abort(_('cannot archive plain files to stdout'))
356 356 dest = cmdutil.makefileobj(repo, dest)
357 357 if not prefix:
358 358 prefix = os.path.basename(repo.root) + '-%h'
359 359
360 360 prefix = cmdutil.makefilename(repo, prefix, node)
361 361 matchfn = scmutil.match(ctx, [], opts)
362 362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 363 matchfn, prefix, subrepos=opts.get('subrepos'))
364 364
365 365 @command('backout',
366 366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 367 ('', 'parent', '',
368 368 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
369 369 ('r', 'rev', '', _('revision to backout'), _('REV')),
370 370 ] + mergetoolopts + walkopts + commitopts + commitopts2,
371 371 _('[OPTION]... [-r] REV'))
372 372 def backout(ui, repo, node=None, rev=None, **opts):
373 373 '''reverse effect of earlier changeset
374 374
375 375 Prepare a new changeset with the effect of REV undone in the
376 376 current working directory.
377 377
378 378 If REV is the parent of the working directory, then this new changeset
379 379 is committed automatically. Otherwise, hg needs to merge the
380 380 changes and the merged result is left uncommitted.
381 381
382 382 .. note::
383 383 backout cannot be used to fix either an unwanted or
384 384 incorrect merge.
385 385
386 386 .. container:: verbose
387 387
388 388 By default, the pending changeset will have one parent,
389 389 maintaining a linear history. With --merge, the pending
390 390 changeset will instead have two parents: the old parent of the
391 391 working directory and a new child of REV that simply undoes REV.
392 392
393 393 Before version 1.7, the behavior without --merge was equivalent
394 394 to specifying --merge followed by :hg:`update --clean .` to
395 395 cancel the merge and leave the child of REV as a head to be
396 396 merged separately.
397 397
398 398 See :hg:`help dates` for a list of formats valid for -d/--date.
399 399
400 400 Returns 0 on success.
401 401 '''
402 402 if rev and node:
403 403 raise util.Abort(_("please specify just one revision"))
404 404
405 405 if not rev:
406 406 rev = node
407 407
408 408 if not rev:
409 409 raise util.Abort(_("please specify a revision to backout"))
410 410
411 411 date = opts.get('date')
412 412 if date:
413 413 opts['date'] = util.parsedate(date)
414 414
415 415 cmdutil.bailifchanged(repo)
416 416 node = scmutil.revsingle(repo, rev).node()
417 417
418 418 op1, op2 = repo.dirstate.parents()
419 419 a = repo.changelog.ancestor(op1, node)
420 420 if a != node:
421 421 raise util.Abort(_('cannot backout change on a different branch'))
422 422
423 423 p1, p2 = repo.changelog.parents(node)
424 424 if p1 == nullid:
425 425 raise util.Abort(_('cannot backout a change with no parents'))
426 426 if p2 != nullid:
427 427 if not opts.get('parent'):
428 428 raise util.Abort(_('cannot backout a merge changeset'))
429 429 p = repo.lookup(opts['parent'])
430 430 if p not in (p1, p2):
431 431 raise util.Abort(_('%s is not a parent of %s') %
432 432 (short(p), short(node)))
433 433 parent = p
434 434 else:
435 435 if opts.get('parent'):
436 436 raise util.Abort(_('cannot use --parent on non-merge changeset'))
437 437 parent = p1
438 438
439 439 # the backout should appear on the same branch
440 440 branch = repo.dirstate.branch()
441 441 hg.clean(repo, node, show_stats=False)
442 442 repo.dirstate.setbranch(branch)
443 443 revert_opts = opts.copy()
444 444 revert_opts['date'] = None
445 445 revert_opts['all'] = True
446 446 revert_opts['rev'] = hex(parent)
447 447 revert_opts['no_backup'] = None
448 448 revert(ui, repo, **revert_opts)
449 449 if not opts.get('merge') and op1 != node:
450 450 try:
451 451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
452 452 return hg.update(repo, op1)
453 453 finally:
454 454 ui.setconfig('ui', 'forcemerge', '')
455 455
456 456 commit_opts = opts.copy()
457 457 commit_opts['addremove'] = False
458 458 if not commit_opts['message'] and not commit_opts['logfile']:
459 459 # we don't translate commit messages
460 460 commit_opts['message'] = "Backed out changeset %s" % short(node)
461 461 commit_opts['force_editor'] = True
462 462 commit(ui, repo, **commit_opts)
463 463 def nice(node):
464 464 return '%d:%s' % (repo.changelog.rev(node), short(node))
465 465 ui.status(_('changeset %s backs out changeset %s\n') %
466 466 (nice(repo.changelog.tip()), nice(node)))
467 467 if opts.get('merge') and op1 != node:
468 468 hg.clean(repo, op1, show_stats=False)
469 469 ui.status(_('merging with changeset %s\n')
470 470 % nice(repo.changelog.tip()))
471 471 try:
472 472 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
473 473 return hg.merge(repo, hex(repo.changelog.tip()))
474 474 finally:
475 475 ui.setconfig('ui', 'forcemerge', '')
476 476 return 0
477 477
478 478 @command('bisect',
479 479 [('r', 'reset', False, _('reset bisect state')),
480 480 ('g', 'good', False, _('mark changeset good')),
481 481 ('b', 'bad', False, _('mark changeset bad')),
482 482 ('s', 'skip', False, _('skip testing changeset')),
483 483 ('e', 'extend', False, _('extend the bisect range')),
484 484 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
485 485 ('U', 'noupdate', False, _('do not update to target'))],
486 486 _("[-gbsr] [-U] [-c CMD] [REV]"))
487 487 def bisect(ui, repo, rev=None, extra=None, command=None,
488 488 reset=None, good=None, bad=None, skip=None, extend=None,
489 489 noupdate=None):
490 490 """subdivision search of changesets
491 491
492 492 This command helps to find changesets which introduce problems. To
493 493 use, mark the earliest changeset you know exhibits the problem as
494 494 bad, then mark the latest changeset which is free from the problem
495 495 as good. Bisect will update your working directory to a revision
496 496 for testing (unless the -U/--noupdate option is specified). Once
497 497 you have performed tests, mark the working directory as good or
498 498 bad, and bisect will either update to another candidate changeset
499 499 or announce that it has found the bad revision.
500 500
501 501 As a shortcut, you can also use the revision argument to mark a
502 502 revision as good or bad without checking it out first.
503 503
504 504 If you supply a command, it will be used for automatic bisection.
505 505 Its exit status will be used to mark revisions as good or bad:
506 506 status 0 means good, 125 means to skip the revision, 127
507 507 (command not found) will abort the bisection, and any other
508 508 non-zero exit status means the revision is bad.
509 509
510 510 .. container:: verbose
511 511
512 512 Some examples:
513 513
514 514 - start a bisection with known bad revision 12, and good revision 34::
515 515
516 516 hg bisect --bad 34
517 517 hg bisect --good 12
518 518
519 519 - advance the current bisection by marking current revision as good or
520 520 bad::
521 521
522 522 hg bisect --good
523 523 hg bisect --bad
524 524
525 525 - mark the current revision, or a known revision, to be skipped (eg. if
526 526 that revision is not usable because of another issue)::
527 527
528 528 hg bisect --skip
529 529 hg bisect --skip 23
530 530
531 531 - forget the current bisection::
532 532
533 533 hg bisect --reset
534 534
535 535 - use 'make && make tests' to automatically find the first broken
536 536 revision::
537 537
538 538 hg bisect --reset
539 539 hg bisect --bad 34
540 540 hg bisect --good 12
541 541 hg bisect --command 'make && make tests'
542 542
543 543 - see all changesets whose states are already known in the current
544 544 bisection::
545 545
546 546 hg log -r "bisect(pruned)"
547 547
548 548 - see all changesets that took part in the current bisection::
549 549
550 550 hg log -r "bisect(range)"
551 551
552 552 - with the graphlog extension, you can even get a nice graph::
553 553
554 554 hg log --graph -r "bisect(range)"
555 555
556 556 See :hg:`help revsets` for more about the `bisect()` keyword.
557 557
558 558 Returns 0 on success.
559 559 """
560 560 def extendbisectrange(nodes, good):
561 561 # bisect is incomplete when it ends on a merge node and
562 562 # one of the parent was not checked.
563 563 parents = repo[nodes[0]].parents()
564 564 if len(parents) > 1:
565 565 side = good and state['bad'] or state['good']
566 566 num = len(set(i.node() for i in parents) & set(side))
567 567 if num == 1:
568 568 return parents[0].ancestor(parents[1])
569 569 return None
570 570
571 571 def print_result(nodes, good):
572 572 displayer = cmdutil.show_changeset(ui, repo, {})
573 573 if len(nodes) == 1:
574 574 # narrowed it down to a single revision
575 575 if good:
576 576 ui.write(_("The first good revision is:\n"))
577 577 else:
578 578 ui.write(_("The first bad revision is:\n"))
579 579 displayer.show(repo[nodes[0]])
580 580 extendnode = extendbisectrange(nodes, good)
581 581 if extendnode is not None:
582 582 ui.write(_('Not all ancestors of this changeset have been'
583 583 ' checked.\nUse bisect --extend to continue the '
584 584 'bisection from\nthe common ancestor, %s.\n')
585 585 % extendnode)
586 586 else:
587 587 # multiple possible revisions
588 588 if good:
589 589 ui.write(_("Due to skipped revisions, the first "
590 590 "good revision could be any of:\n"))
591 591 else:
592 592 ui.write(_("Due to skipped revisions, the first "
593 593 "bad revision could be any of:\n"))
594 594 for n in nodes:
595 595 displayer.show(repo[n])
596 596 displayer.close()
597 597
598 598 def check_state(state, interactive=True):
599 599 if not state['good'] or not state['bad']:
600 600 if (good or bad or skip or reset) and interactive:
601 601 return
602 602 if not state['good']:
603 603 raise util.Abort(_('cannot bisect (no known good revisions)'))
604 604 else:
605 605 raise util.Abort(_('cannot bisect (no known bad revisions)'))
606 606 return True
607 607
608 608 # backward compatibility
609 609 if rev in "good bad reset init".split():
610 610 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
611 611 cmd, rev, extra = rev, extra, None
612 612 if cmd == "good":
613 613 good = True
614 614 elif cmd == "bad":
615 615 bad = True
616 616 else:
617 617 reset = True
618 618 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
619 619 raise util.Abort(_('incompatible arguments'))
620 620
621 621 if reset:
622 622 p = repo.join("bisect.state")
623 623 if os.path.exists(p):
624 624 os.unlink(p)
625 625 return
626 626
627 627 state = hbisect.load_state(repo)
628 628
629 629 if command:
630 630 changesets = 1
631 631 try:
632 632 while changesets:
633 633 # update state
634 634 status = util.system(command, out=ui.fout)
635 635 if status == 125:
636 636 transition = "skip"
637 637 elif status == 0:
638 638 transition = "good"
639 639 # status < 0 means process was killed
640 640 elif status == 127:
641 641 raise util.Abort(_("failed to execute %s") % command)
642 642 elif status < 0:
643 643 raise util.Abort(_("%s killed") % command)
644 644 else:
645 645 transition = "bad"
646 646 ctx = scmutil.revsingle(repo, rev)
647 647 rev = None # clear for future iterations
648 648 state[transition].append(ctx.node())
649 649 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
650 650 check_state(state, interactive=False)
651 651 # bisect
652 652 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
653 653 # update to next check
654 654 cmdutil.bailifchanged(repo)
655 655 hg.clean(repo, nodes[0], show_stats=False)
656 656 finally:
657 657 hbisect.save_state(repo, state)
658 658 print_result(nodes, good)
659 659 return
660 660
661 661 # update state
662 662
663 663 if rev:
664 664 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
665 665 else:
666 666 nodes = [repo.lookup('.')]
667 667
668 668 if good or bad or skip:
669 669 if good:
670 670 state['good'] += nodes
671 671 elif bad:
672 672 state['bad'] += nodes
673 673 elif skip:
674 674 state['skip'] += nodes
675 675 hbisect.save_state(repo, state)
676 676
677 677 if not check_state(state):
678 678 return
679 679
680 680 # actually bisect
681 681 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
682 682 if extend:
683 683 if not changesets:
684 684 extendnode = extendbisectrange(nodes, good)
685 685 if extendnode is not None:
686 686 ui.write(_("Extending search to changeset %d:%s\n"
687 687 % (extendnode.rev(), extendnode)))
688 688 if noupdate:
689 689 return
690 690 cmdutil.bailifchanged(repo)
691 691 return hg.clean(repo, extendnode.node())
692 692 raise util.Abort(_("nothing to extend"))
693 693
694 694 if changesets == 0:
695 695 print_result(nodes, good)
696 696 else:
697 697 assert len(nodes) == 1 # only a single node can be tested next
698 698 node = nodes[0]
699 699 # compute the approximate number of remaining tests
700 700 tests, size = 0, 2
701 701 while size <= changesets:
702 702 tests, size = tests + 1, size * 2
703 703 rev = repo.changelog.rev(node)
704 704 ui.write(_("Testing changeset %d:%s "
705 705 "(%d changesets remaining, ~%d tests)\n")
706 706 % (rev, short(node), changesets, tests))
707 707 if not noupdate:
708 708 cmdutil.bailifchanged(repo)
709 709 return hg.clean(repo, node)
710 710
711 711 @command('bookmarks',
712 712 [('f', 'force', False, _('force')),
713 713 ('r', 'rev', '', _('revision'), _('REV')),
714 714 ('d', 'delete', False, _('delete a given bookmark')),
715 715 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
716 716 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
717 717 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
718 718 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
719 719 rename=None, inactive=False):
720 720 '''track a line of development with movable markers
721 721
722 722 Bookmarks are pointers to certain commits that move when
723 723 committing. Bookmarks are local. They can be renamed, copied and
724 724 deleted. It is possible to use bookmark names in :hg:`merge` and
725 725 :hg:`update` to merge and update respectively to a given bookmark.
726 726
727 727 You can use :hg:`bookmark NAME` to set a bookmark on the working
728 728 directory's parent revision with the given name. If you specify
729 729 a revision using -r REV (where REV may be an existing bookmark),
730 730 the bookmark is assigned to that revision.
731 731
732 732 Bookmarks can be pushed and pulled between repositories (see :hg:`help
733 733 push` and :hg:`help pull`). This requires both the local and remote
734 734 repositories to support bookmarks. For versions prior to 1.8, this means
735 735 the bookmarks extension must be enabled.
736 736 '''
737 737 hexfn = ui.debugflag and hex or short
738 738 marks = repo._bookmarks
739 739 cur = repo.changectx('.').node()
740 740
741 741 if rename:
742 742 if rename not in marks:
743 743 raise util.Abort(_("bookmark '%s' does not exist") % rename)
744 744 if mark in marks and not force:
745 745 raise util.Abort(_("bookmark '%s' already exists "
746 746 "(use -f to force)") % mark)
747 747 if mark is None:
748 748 raise util.Abort(_("new bookmark name required"))
749 749 marks[mark] = marks[rename]
750 750 if repo._bookmarkcurrent == rename and not inactive:
751 751 bookmarks.setcurrent(repo, mark)
752 752 del marks[rename]
753 753 bookmarks.write(repo)
754 754 return
755 755
756 756 if delete:
757 757 if mark is None:
758 758 raise util.Abort(_("bookmark name required"))
759 759 if mark not in marks:
760 760 raise util.Abort(_("bookmark '%s' does not exist") % mark)
761 761 if mark == repo._bookmarkcurrent:
762 762 bookmarks.setcurrent(repo, None)
763 763 del marks[mark]
764 764 bookmarks.write(repo)
765 765 return
766 766
767 767 if mark is not None:
768 768 if "\n" in mark:
769 769 raise util.Abort(_("bookmark name cannot contain newlines"))
770 770 mark = mark.strip()
771 771 if not mark:
772 772 raise util.Abort(_("bookmark names cannot consist entirely of "
773 773 "whitespace"))
774 774 if inactive and mark == repo._bookmarkcurrent:
775 775 bookmarks.setcurrent(repo, None)
776 776 return
777 777 if mark in marks and not force:
778 778 raise util.Abort(_("bookmark '%s' already exists "
779 779 "(use -f to force)") % mark)
780 780 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
781 781 and not force):
782 782 raise util.Abort(
783 783 _("a bookmark cannot have the name of an existing branch"))
784 784 if rev:
785 785 marks[mark] = repo.lookup(rev)
786 786 else:
787 787 marks[mark] = repo.changectx('.').node()
788 788 if not inactive and repo.changectx('.').node() == marks[mark]:
789 789 bookmarks.setcurrent(repo, mark)
790 790 bookmarks.write(repo)
791 791 return
792 792
793 793 if mark is None:
794 794 if rev:
795 795 raise util.Abort(_("bookmark name required"))
796 796 if len(marks) == 0:
797 797 ui.status(_("no bookmarks set\n"))
798 798 else:
799 799 for bmark, n in sorted(marks.iteritems()):
800 800 current = repo._bookmarkcurrent
801 801 if bmark == current and n == cur:
802 802 prefix, label = '*', 'bookmarks.current'
803 803 else:
804 804 prefix, label = ' ', ''
805 805
806 806 if ui.quiet:
807 807 ui.write("%s\n" % bmark, label=label)
808 808 else:
809 809 ui.write(" %s %-25s %d:%s\n" % (
810 810 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
811 811 label=label)
812 812 return
813 813
814 814 @command('branch',
815 815 [('f', 'force', None,
816 816 _('set branch name even if it shadows an existing branch')),
817 817 ('C', 'clean', None, _('reset branch name to parent branch name'))],
818 818 _('[-fC] [NAME]'))
819 819 def branch(ui, repo, label=None, **opts):
820 820 """set or show the current branch name
821 821
822 822 With no argument, show the current branch name. With one argument,
823 823 set the working directory branch name (the branch will not exist
824 824 in the repository until the next commit). Standard practice
825 825 recommends that primary development take place on the 'default'
826 826 branch.
827 827
828 828 Unless -f/--force is specified, branch will not let you set a
829 829 branch name that already exists, even if it's inactive.
830 830
831 831 Use -C/--clean to reset the working directory branch to that of
832 832 the parent of the working directory, negating a previous branch
833 833 change.
834 834
835 835 Use the command :hg:`update` to switch to an existing branch. Use
836 836 :hg:`commit --close-branch` to mark this branch as closed.
837 837
838 838 .. note::
839 839 Branch names are permanent. Use :hg:`bookmark` to create a
840 840 light-weight bookmark instead. See :hg:`help glossary` for more
841 841 information about named branches and bookmarks.
842 842
843 843 Returns 0 on success.
844 844 """
845 845
846 846 if opts.get('clean'):
847 847 label = repo[None].p1().branch()
848 848 repo.dirstate.setbranch(label)
849 849 ui.status(_('reset working directory to branch %s\n') % label)
850 850 elif label:
851 851 if not opts.get('force') and label in repo.branchtags():
852 852 if label not in [p.branch() for p in repo.parents()]:
853 853 raise util.Abort(_('a branch of the same name already exists'),
854 854 # i18n: "it" refers to an existing branch
855 855 hint=_("use 'hg update' to switch to it"))
856 856 repo.dirstate.setbranch(label)
857 857 ui.status(_('marked working directory as branch %s\n') % label)
858 858 else:
859 859 ui.write("%s\n" % repo.dirstate.branch())
860 860
861 861 @command('branches',
862 862 [('a', 'active', False, _('show only branches that have unmerged heads')),
863 863 ('c', 'closed', False, _('show normal and closed branches'))],
864 864 _('[-ac]'))
865 865 def branches(ui, repo, active=False, closed=False):
866 866 """list repository named branches
867 867
868 868 List the repository's named branches, indicating which ones are
869 869 inactive. If -c/--closed is specified, also list branches which have
870 870 been marked closed (see :hg:`commit --close-branch`).
871 871
872 872 If -a/--active is specified, only show active branches. A branch
873 873 is considered active if it contains repository heads.
874 874
875 875 Use the command :hg:`update` to switch to an existing branch.
876 876
877 877 Returns 0.
878 878 """
879 879
880 880 hexfunc = ui.debugflag and hex or short
881 881 activebranches = [repo[n].branch() for n in repo.heads()]
882 882 def testactive(tag, node):
883 883 realhead = tag in activebranches
884 884 open = node in repo.branchheads(tag, closed=False)
885 885 return realhead and open
886 886 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
887 887 for tag, node in repo.branchtags().items()],
888 888 reverse=True)
889 889
890 890 for isactive, node, tag in branches:
891 891 if (not active) or isactive:
892 892 if ui.quiet:
893 893 ui.write("%s\n" % tag)
894 894 else:
895 895 hn = repo.lookup(node)
896 896 if isactive:
897 897 label = 'branches.active'
898 898 notice = ''
899 899 elif hn not in repo.branchheads(tag, closed=False):
900 900 if not closed:
901 901 continue
902 902 label = 'branches.closed'
903 903 notice = _(' (closed)')
904 904 else:
905 905 label = 'branches.inactive'
906 906 notice = _(' (inactive)')
907 907 if tag == repo.dirstate.branch():
908 908 label = 'branches.current'
909 909 rev = str(node).rjust(31 - encoding.colwidth(tag))
910 910 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
911 911 tag = ui.label(tag, label)
912 912 ui.write("%s %s%s\n" % (tag, rev, notice))
913 913
914 914 @command('bundle',
915 915 [('f', 'force', None, _('run even when the destination is unrelated')),
916 916 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
917 917 _('REV')),
918 918 ('b', 'branch', [], _('a specific branch you would like to bundle'),
919 919 _('BRANCH')),
920 920 ('', 'base', [],
921 921 _('a base changeset assumed to be available at the destination'),
922 922 _('REV')),
923 923 ('a', 'all', None, _('bundle all changesets in the repository')),
924 924 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
925 925 ] + remoteopts,
926 926 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
927 927 def bundle(ui, repo, fname, dest=None, **opts):
928 928 """create a changegroup file
929 929
930 930 Generate a compressed changegroup file collecting changesets not
931 931 known to be in another repository.
932 932
933 933 If you omit the destination repository, then hg assumes the
934 934 destination will have all the nodes you specify with --base
935 935 parameters. To create a bundle containing all changesets, use
936 936 -a/--all (or --base null).
937 937
938 938 You can change compression method with the -t/--type option.
939 939 The available compression methods are: none, bzip2, and
940 940 gzip (by default, bundles are compressed using bzip2).
941 941
942 942 The bundle file can then be transferred using conventional means
943 943 and applied to another repository with the unbundle or pull
944 944 command. This is useful when direct push and pull are not
945 945 available or when exporting an entire repository is undesirable.
946 946
947 947 Applying bundles preserves all changeset contents including
948 948 permissions, copy/rename information, and revision history.
949 949
950 950 Returns 0 on success, 1 if no changes found.
951 951 """
952 952 revs = None
953 953 if 'rev' in opts:
954 954 revs = scmutil.revrange(repo, opts['rev'])
955 955
956 956 if opts.get('all'):
957 957 base = ['null']
958 958 else:
959 959 base = scmutil.revrange(repo, opts.get('base'))
960 960 if base:
961 961 if dest:
962 962 raise util.Abort(_("--base is incompatible with specifying "
963 963 "a destination"))
964 964 common = [repo.lookup(rev) for rev in base]
965 965 heads = revs and map(repo.lookup, revs) or revs
966 966 else:
967 967 dest = ui.expandpath(dest or 'default-push', dest or 'default')
968 968 dest, branches = hg.parseurl(dest, opts.get('branch'))
969 969 other = hg.peer(repo, opts, dest)
970 970 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
971 971 heads = revs and map(repo.lookup, revs) or revs
972 972 common, outheads = discovery.findcommonoutgoing(repo, other,
973 973 onlyheads=heads,
974 974 force=opts.get('force'))
975 975
976 976 cg = repo.getbundle('bundle', common=common, heads=heads)
977 977 if not cg:
978 978 ui.status(_("no changes found\n"))
979 979 return 1
980 980
981 981 bundletype = opts.get('type', 'bzip2').lower()
982 982 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
983 983 bundletype = btypes.get(bundletype)
984 984 if bundletype not in changegroup.bundletypes:
985 985 raise util.Abort(_('unknown bundle type specified with --type'))
986 986
987 987 changegroup.writebundle(cg, fname, bundletype)
988 988
989 989 @command('cat',
990 990 [('o', 'output', '',
991 991 _('print output to file with formatted name'), _('FORMAT')),
992 992 ('r', 'rev', '', _('print the given revision'), _('REV')),
993 993 ('', 'decode', None, _('apply any matching decode filter')),
994 994 ] + walkopts,
995 995 _('[OPTION]... FILE...'))
996 996 def cat(ui, repo, file1, *pats, **opts):
997 997 """output the current or given revision of files
998 998
999 999 Print the specified files as they were at the given revision. If
1000 1000 no revision is given, the parent of the working directory is used,
1001 1001 or tip if no revision is checked out.
1002 1002
1003 1003 Output may be to a file, in which case the name of the file is
1004 1004 given using a format string. The formatting rules are the same as
1005 1005 for the export command, with the following additions:
1006 1006
1007 1007 :``%s``: basename of file being printed
1008 1008 :``%d``: dirname of file being printed, or '.' if in repository root
1009 1009 :``%p``: root-relative path name of file being printed
1010 1010
1011 1011 Returns 0 on success.
1012 1012 """
1013 1013 ctx = scmutil.revsingle(repo, opts.get('rev'))
1014 1014 err = 1
1015 1015 m = scmutil.match(ctx, (file1,) + pats, opts)
1016 1016 for abs in ctx.walk(m):
1017 1017 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1018 1018 pathname=abs)
1019 1019 data = ctx[abs].data()
1020 1020 if opts.get('decode'):
1021 1021 data = repo.wwritedata(abs, data)
1022 1022 fp.write(data)
1023 1023 fp.close()
1024 1024 err = 0
1025 1025 return err
1026 1026
1027 1027 @command('^clone',
1028 1028 [('U', 'noupdate', None,
1029 1029 _('the clone will include an empty working copy (only a repository)')),
1030 1030 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1031 1031 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1032 1032 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1033 1033 ('', 'pull', None, _('use pull protocol to copy metadata')),
1034 1034 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1035 1035 ] + remoteopts,
1036 1036 _('[OPTION]... SOURCE [DEST]'))
1037 1037 def clone(ui, source, dest=None, **opts):
1038 1038 """make a copy of an existing repository
1039 1039
1040 1040 Create a copy of an existing repository in a new directory.
1041 1041
1042 1042 If no destination directory name is specified, it defaults to the
1043 1043 basename of the source.
1044 1044
1045 1045 The location of the source is added to the new repository's
1046 1046 ``.hg/hgrc`` file, as the default to be used for future pulls.
1047 1047
1048 1048 Only local paths and ``ssh://`` URLs are supported as
1049 1049 destinations. For ``ssh://`` destinations, no working directory or
1050 1050 ``.hg/hgrc`` will be created on the remote side.
1051 1051
1052 1052 To pull only a subset of changesets, specify one or more revisions
1053 1053 identifiers with -r/--rev or branches with -b/--branch. The
1054 1054 resulting clone will contain only the specified changesets and
1055 1055 their ancestors. These options (or 'clone src#rev dest') imply
1056 1056 --pull, even for local source repositories. Note that specifying a
1057 1057 tag will include the tagged changeset but not the changeset
1058 1058 containing the tag.
1059 1059
1060 1060 To check out a particular version, use -u/--update, or
1061 1061 -U/--noupdate to create a clone with no working directory.
1062 1062
1063 1063 .. container:: verbose
1064 1064
1065 1065 For efficiency, hardlinks are used for cloning whenever the
1066 1066 source and destination are on the same filesystem (note this
1067 1067 applies only to the repository data, not to the working
1068 1068 directory). Some filesystems, such as AFS, implement hardlinking
1069 1069 incorrectly, but do not report errors. In these cases, use the
1070 1070 --pull option to avoid hardlinking.
1071 1071
1072 1072 In some cases, you can clone repositories and the working
1073 1073 directory using full hardlinks with ::
1074 1074
1075 1075 $ cp -al REPO REPOCLONE
1076 1076
1077 1077 This is the fastest way to clone, but it is not always safe. The
1078 1078 operation is not atomic (making sure REPO is not modified during
1079 1079 the operation is up to you) and you have to make sure your
1080 1080 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1081 1081 so). Also, this is not compatible with certain extensions that
1082 1082 place their metadata under the .hg directory, such as mq.
1083 1083
1084 1084 Mercurial will update the working directory to the first applicable
1085 1085 revision from this list:
1086 1086
1087 1087 a) null if -U or the source repository has no changesets
1088 1088 b) if -u . and the source repository is local, the first parent of
1089 1089 the source repository's working directory
1090 1090 c) the changeset specified with -u (if a branch name, this means the
1091 1091 latest head of that branch)
1092 1092 d) the changeset specified with -r
1093 1093 e) the tipmost head specified with -b
1094 1094 f) the tipmost head specified with the url#branch source syntax
1095 1095 g) the tipmost head of the default branch
1096 1096 h) tip
1097 1097
1098 1098 Examples:
1099 1099
1100 1100 - clone a remote repository to a new directory named hg/::
1101 1101
1102 1102 hg clone http://selenic.com/hg
1103 1103
1104 1104 - create a lightweight local clone::
1105 1105
1106 1106 hg clone project/ project-feature/
1107 1107
1108 1108 - clone from an absolute path on an ssh server (note double-slash)::
1109 1109
1110 1110 hg clone ssh://user@server//home/projects/alpha/
1111 1111
1112 1112 - do a high-speed clone over a LAN while checking out a
1113 1113 specified version::
1114 1114
1115 1115 hg clone --uncompressed http://server/repo -u 1.5
1116 1116
1117 1117 - create a repository without changesets after a particular revision::
1118 1118
1119 1119 hg clone -r 04e544 experimental/ good/
1120 1120
1121 1121 - clone (and track) a particular named branch::
1122 1122
1123 1123 hg clone http://selenic.com/hg#stable
1124 1124
1125 1125 See :hg:`help urls` for details on specifying URLs.
1126 1126
1127 1127 Returns 0 on success.
1128 1128 """
1129 1129 if opts.get('noupdate') and opts.get('updaterev'):
1130 1130 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1131 1131
1132 1132 r = hg.clone(ui, opts, source, dest,
1133 1133 pull=opts.get('pull'),
1134 1134 stream=opts.get('uncompressed'),
1135 1135 rev=opts.get('rev'),
1136 1136 update=opts.get('updaterev') or not opts.get('noupdate'),
1137 1137 branch=opts.get('branch'))
1138 1138
1139 1139 return r is None
1140 1140
1141 1141 @command('^commit|ci',
1142 1142 [('A', 'addremove', None,
1143 1143 _('mark new/missing files as added/removed before committing')),
1144 1144 ('', 'close-branch', None,
1145 1145 _('mark a branch as closed, hiding it from the branch list')),
1146 ] + walkopts + commitopts + commitopts2,
1146 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1147 1147 _('[OPTION]... [FILE]...'))
1148 1148 def commit(ui, repo, *pats, **opts):
1149 1149 """commit the specified files or all outstanding changes
1150 1150
1151 1151 Commit changes to the given files into the repository. Unlike a
1152 1152 centralized SCM, this operation is a local operation. See
1153 1153 :hg:`push` for a way to actively distribute your changes.
1154 1154
1155 1155 If a list of files is omitted, all changes reported by :hg:`status`
1156 1156 will be committed.
1157 1157
1158 1158 If you are committing the result of a merge, do not provide any
1159 1159 filenames or -I/-X filters.
1160 1160
1161 1161 If no commit message is specified, Mercurial starts your
1162 1162 configured editor where you can enter a message. In case your
1163 1163 commit fails, you will find a backup of your message in
1164 1164 ``.hg/last-message.txt``.
1165 1165
1166 1166 See :hg:`help dates` for a list of formats valid for -d/--date.
1167 1167
1168 1168 Returns 0 on success, 1 if nothing changed.
1169 1169 """
1170 if opts.get('subrepos'):
1171 # Let --subrepos on the command line overide config setting.
1172 ui.setconfig('ui', 'commitsubrepos', True)
1173
1170 1174 extra = {}
1171 1175 if opts.get('close_branch'):
1172 1176 if repo['.'].node() not in repo.branchheads():
1173 1177 # The topo heads set is included in the branch heads set of the
1174 1178 # current branch, so it's sufficient to test branchheads
1175 1179 raise util.Abort(_('can only close branch heads'))
1176 1180 extra['close'] = 1
1177 1181 e = cmdutil.commiteditor
1178 1182 if opts.get('force_editor'):
1179 1183 e = cmdutil.commitforceeditor
1180 1184
1181 1185 def commitfunc(ui, repo, message, match, opts):
1182 1186 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1183 1187 editor=e, extra=extra)
1184 1188
1185 1189 branch = repo[None].branch()
1186 1190 bheads = repo.branchheads(branch)
1187 1191
1188 1192 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1189 1193 if not node:
1190 1194 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1191 1195 if stat[3]:
1192 1196 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1193 1197 % len(stat[3]))
1194 1198 else:
1195 1199 ui.status(_("nothing changed\n"))
1196 1200 return 1
1197 1201
1198 1202 ctx = repo[node]
1199 1203 parents = ctx.parents()
1200 1204
1201 1205 if (bheads and node not in bheads and not
1202 1206 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1203 1207 ui.status(_('created new head\n'))
1204 1208 # The message is not printed for initial roots. For the other
1205 1209 # changesets, it is printed in the following situations:
1206 1210 #
1207 1211 # Par column: for the 2 parents with ...
1208 1212 # N: null or no parent
1209 1213 # B: parent is on another named branch
1210 1214 # C: parent is a regular non head changeset
1211 1215 # H: parent was a branch head of the current branch
1212 1216 # Msg column: whether we print "created new head" message
1213 1217 # In the following, it is assumed that there already exists some
1214 1218 # initial branch heads of the current branch, otherwise nothing is
1215 1219 # printed anyway.
1216 1220 #
1217 1221 # Par Msg Comment
1218 1222 # NN y additional topo root
1219 1223 #
1220 1224 # BN y additional branch root
1221 1225 # CN y additional topo head
1222 1226 # HN n usual case
1223 1227 #
1224 1228 # BB y weird additional branch root
1225 1229 # CB y branch merge
1226 1230 # HB n merge with named branch
1227 1231 #
1228 1232 # CC y additional head from merge
1229 1233 # CH n merge with a head
1230 1234 #
1231 1235 # HH n head merge: head count decreases
1232 1236
1233 1237 if not opts.get('close_branch'):
1234 1238 for r in parents:
1235 1239 if r.extra().get('close') and r.branch() == branch:
1236 1240 ui.status(_('reopening closed branch head %d\n') % r)
1237 1241
1238 1242 if ui.debugflag:
1239 1243 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1240 1244 elif ui.verbose:
1241 1245 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1242 1246
1243 1247 @command('copy|cp',
1244 1248 [('A', 'after', None, _('record a copy that has already occurred')),
1245 1249 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1246 1250 ] + walkopts + dryrunopts,
1247 1251 _('[OPTION]... [SOURCE]... DEST'))
1248 1252 def copy(ui, repo, *pats, **opts):
1249 1253 """mark files as copied for the next commit
1250 1254
1251 1255 Mark dest as having copies of source files. If dest is a
1252 1256 directory, copies are put in that directory. If dest is a file,
1253 1257 the source must be a single file.
1254 1258
1255 1259 By default, this command copies the contents of files as they
1256 1260 exist in the working directory. If invoked with -A/--after, the
1257 1261 operation is recorded, but no copying is performed.
1258 1262
1259 1263 This command takes effect with the next commit. To undo a copy
1260 1264 before that, see :hg:`revert`.
1261 1265
1262 1266 Returns 0 on success, 1 if errors are encountered.
1263 1267 """
1264 1268 wlock = repo.wlock(False)
1265 1269 try:
1266 1270 return cmdutil.copy(ui, repo, pats, opts)
1267 1271 finally:
1268 1272 wlock.release()
1269 1273
1270 1274 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1271 1275 def debugancestor(ui, repo, *args):
1272 1276 """find the ancestor revision of two revisions in a given index"""
1273 1277 if len(args) == 3:
1274 1278 index, rev1, rev2 = args
1275 1279 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1276 1280 lookup = r.lookup
1277 1281 elif len(args) == 2:
1278 1282 if not repo:
1279 1283 raise util.Abort(_("there is no Mercurial repository here "
1280 1284 "(.hg not found)"))
1281 1285 rev1, rev2 = args
1282 1286 r = repo.changelog
1283 1287 lookup = repo.lookup
1284 1288 else:
1285 1289 raise util.Abort(_('either two or three arguments required'))
1286 1290 a = r.ancestor(lookup(rev1), lookup(rev2))
1287 1291 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1288 1292
1289 1293 @command('debugbuilddag',
1290 1294 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1291 1295 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1292 1296 ('n', 'new-file', None, _('add new file at each rev'))],
1293 1297 _('[OPTION]... [TEXT]'))
1294 1298 def debugbuilddag(ui, repo, text=None,
1295 1299 mergeable_file=False,
1296 1300 overwritten_file=False,
1297 1301 new_file=False):
1298 1302 """builds a repo with a given DAG from scratch in the current empty repo
1299 1303
1300 1304 The description of the DAG is read from stdin if not given on the
1301 1305 command line.
1302 1306
1303 1307 Elements:
1304 1308
1305 1309 - "+n" is a linear run of n nodes based on the current default parent
1306 1310 - "." is a single node based on the current default parent
1307 1311 - "$" resets the default parent to null (implied at the start);
1308 1312 otherwise the default parent is always the last node created
1309 1313 - "<p" sets the default parent to the backref p
1310 1314 - "*p" is a fork at parent p, which is a backref
1311 1315 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1312 1316 - "/p2" is a merge of the preceding node and p2
1313 1317 - ":tag" defines a local tag for the preceding node
1314 1318 - "@branch" sets the named branch for subsequent nodes
1315 1319 - "#...\\n" is a comment up to the end of the line
1316 1320
1317 1321 Whitespace between the above elements is ignored.
1318 1322
1319 1323 A backref is either
1320 1324
1321 1325 - a number n, which references the node curr-n, where curr is the current
1322 1326 node, or
1323 1327 - the name of a local tag you placed earlier using ":tag", or
1324 1328 - empty to denote the default parent.
1325 1329
1326 1330 All string valued-elements are either strictly alphanumeric, or must
1327 1331 be enclosed in double quotes ("..."), with "\\" as escape character.
1328 1332 """
1329 1333
1330 1334 if text is None:
1331 1335 ui.status(_("reading DAG from stdin\n"))
1332 1336 text = ui.fin.read()
1333 1337
1334 1338 cl = repo.changelog
1335 1339 if len(cl) > 0:
1336 1340 raise util.Abort(_('repository is not empty'))
1337 1341
1338 1342 # determine number of revs in DAG
1339 1343 total = 0
1340 1344 for type, data in dagparser.parsedag(text):
1341 1345 if type == 'n':
1342 1346 total += 1
1343 1347
1344 1348 if mergeable_file:
1345 1349 linesperrev = 2
1346 1350 # make a file with k lines per rev
1347 1351 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1348 1352 initialmergedlines.append("")
1349 1353
1350 1354 tags = []
1351 1355
1352 1356 tr = repo.transaction("builddag")
1353 1357 try:
1354 1358
1355 1359 at = -1
1356 1360 atbranch = 'default'
1357 1361 nodeids = []
1358 1362 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1359 1363 for type, data in dagparser.parsedag(text):
1360 1364 if type == 'n':
1361 1365 ui.note('node %s\n' % str(data))
1362 1366 id, ps = data
1363 1367
1364 1368 files = []
1365 1369 fctxs = {}
1366 1370
1367 1371 p2 = None
1368 1372 if mergeable_file:
1369 1373 fn = "mf"
1370 1374 p1 = repo[ps[0]]
1371 1375 if len(ps) > 1:
1372 1376 p2 = repo[ps[1]]
1373 1377 pa = p1.ancestor(p2)
1374 1378 base, local, other = [x[fn].data() for x in pa, p1, p2]
1375 1379 m3 = simplemerge.Merge3Text(base, local, other)
1376 1380 ml = [l.strip() for l in m3.merge_lines()]
1377 1381 ml.append("")
1378 1382 elif at > 0:
1379 1383 ml = p1[fn].data().split("\n")
1380 1384 else:
1381 1385 ml = initialmergedlines
1382 1386 ml[id * linesperrev] += " r%i" % id
1383 1387 mergedtext = "\n".join(ml)
1384 1388 files.append(fn)
1385 1389 fctxs[fn] = context.memfilectx(fn, mergedtext)
1386 1390
1387 1391 if overwritten_file:
1388 1392 fn = "of"
1389 1393 files.append(fn)
1390 1394 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1391 1395
1392 1396 if new_file:
1393 1397 fn = "nf%i" % id
1394 1398 files.append(fn)
1395 1399 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1396 1400 if len(ps) > 1:
1397 1401 if not p2:
1398 1402 p2 = repo[ps[1]]
1399 1403 for fn in p2:
1400 1404 if fn.startswith("nf"):
1401 1405 files.append(fn)
1402 1406 fctxs[fn] = p2[fn]
1403 1407
1404 1408 def fctxfn(repo, cx, path):
1405 1409 return fctxs.get(path)
1406 1410
1407 1411 if len(ps) == 0 or ps[0] < 0:
1408 1412 pars = [None, None]
1409 1413 elif len(ps) == 1:
1410 1414 pars = [nodeids[ps[0]], None]
1411 1415 else:
1412 1416 pars = [nodeids[p] for p in ps]
1413 1417 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1414 1418 date=(id, 0),
1415 1419 user="debugbuilddag",
1416 1420 extra={'branch': atbranch})
1417 1421 nodeid = repo.commitctx(cx)
1418 1422 nodeids.append(nodeid)
1419 1423 at = id
1420 1424 elif type == 'l':
1421 1425 id, name = data
1422 1426 ui.note('tag %s\n' % name)
1423 1427 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1424 1428 elif type == 'a':
1425 1429 ui.note('branch %s\n' % data)
1426 1430 atbranch = data
1427 1431 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1428 1432 tr.close()
1429 1433 finally:
1430 1434 ui.progress(_('building'), None)
1431 1435 tr.release()
1432 1436
1433 1437 if tags:
1434 1438 repo.opener.write("localtags", "".join(tags))
1435 1439
1436 1440 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1437 1441 def debugbundle(ui, bundlepath, all=None, **opts):
1438 1442 """lists the contents of a bundle"""
1439 1443 f = url.open(ui, bundlepath)
1440 1444 try:
1441 1445 gen = changegroup.readbundle(f, bundlepath)
1442 1446 if all:
1443 1447 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1444 1448
1445 1449 def showchunks(named):
1446 1450 ui.write("\n%s\n" % named)
1447 1451 chain = None
1448 1452 while True:
1449 1453 chunkdata = gen.deltachunk(chain)
1450 1454 if not chunkdata:
1451 1455 break
1452 1456 node = chunkdata['node']
1453 1457 p1 = chunkdata['p1']
1454 1458 p2 = chunkdata['p2']
1455 1459 cs = chunkdata['cs']
1456 1460 deltabase = chunkdata['deltabase']
1457 1461 delta = chunkdata['delta']
1458 1462 ui.write("%s %s %s %s %s %s\n" %
1459 1463 (hex(node), hex(p1), hex(p2),
1460 1464 hex(cs), hex(deltabase), len(delta)))
1461 1465 chain = node
1462 1466
1463 1467 chunkdata = gen.changelogheader()
1464 1468 showchunks("changelog")
1465 1469 chunkdata = gen.manifestheader()
1466 1470 showchunks("manifest")
1467 1471 while True:
1468 1472 chunkdata = gen.filelogheader()
1469 1473 if not chunkdata:
1470 1474 break
1471 1475 fname = chunkdata['filename']
1472 1476 showchunks(fname)
1473 1477 else:
1474 1478 chunkdata = gen.changelogheader()
1475 1479 chain = None
1476 1480 while True:
1477 1481 chunkdata = gen.deltachunk(chain)
1478 1482 if not chunkdata:
1479 1483 break
1480 1484 node = chunkdata['node']
1481 1485 ui.write("%s\n" % hex(node))
1482 1486 chain = node
1483 1487 finally:
1484 1488 f.close()
1485 1489
1486 1490 @command('debugcheckstate', [], '')
1487 1491 def debugcheckstate(ui, repo):
1488 1492 """validate the correctness of the current dirstate"""
1489 1493 parent1, parent2 = repo.dirstate.parents()
1490 1494 m1 = repo[parent1].manifest()
1491 1495 m2 = repo[parent2].manifest()
1492 1496 errors = 0
1493 1497 for f in repo.dirstate:
1494 1498 state = repo.dirstate[f]
1495 1499 if state in "nr" and f not in m1:
1496 1500 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1497 1501 errors += 1
1498 1502 if state in "a" and f in m1:
1499 1503 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1500 1504 errors += 1
1501 1505 if state in "m" and f not in m1 and f not in m2:
1502 1506 ui.warn(_("%s in state %s, but not in either manifest\n") %
1503 1507 (f, state))
1504 1508 errors += 1
1505 1509 for f in m1:
1506 1510 state = repo.dirstate[f]
1507 1511 if state not in "nrm":
1508 1512 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1509 1513 errors += 1
1510 1514 if errors:
1511 1515 error = _(".hg/dirstate inconsistent with current parent's manifest")
1512 1516 raise util.Abort(error)
1513 1517
1514 1518 @command('debugcommands', [], _('[COMMAND]'))
1515 1519 def debugcommands(ui, cmd='', *args):
1516 1520 """list all available commands and options"""
1517 1521 for cmd, vals in sorted(table.iteritems()):
1518 1522 cmd = cmd.split('|')[0].strip('^')
1519 1523 opts = ', '.join([i[1] for i in vals[1]])
1520 1524 ui.write('%s: %s\n' % (cmd, opts))
1521 1525
1522 1526 @command('debugcomplete',
1523 1527 [('o', 'options', None, _('show the command options'))],
1524 1528 _('[-o] CMD'))
1525 1529 def debugcomplete(ui, cmd='', **opts):
1526 1530 """returns the completion list associated with the given command"""
1527 1531
1528 1532 if opts.get('options'):
1529 1533 options = []
1530 1534 otables = [globalopts]
1531 1535 if cmd:
1532 1536 aliases, entry = cmdutil.findcmd(cmd, table, False)
1533 1537 otables.append(entry[1])
1534 1538 for t in otables:
1535 1539 for o in t:
1536 1540 if "(DEPRECATED)" in o[3]:
1537 1541 continue
1538 1542 if o[0]:
1539 1543 options.append('-%s' % o[0])
1540 1544 options.append('--%s' % o[1])
1541 1545 ui.write("%s\n" % "\n".join(options))
1542 1546 return
1543 1547
1544 1548 cmdlist = cmdutil.findpossible(cmd, table)
1545 1549 if ui.verbose:
1546 1550 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1547 1551 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1548 1552
1549 1553 @command('debugdag',
1550 1554 [('t', 'tags', None, _('use tags as labels')),
1551 1555 ('b', 'branches', None, _('annotate with branch names')),
1552 1556 ('', 'dots', None, _('use dots for runs')),
1553 1557 ('s', 'spaces', None, _('separate elements by spaces'))],
1554 1558 _('[OPTION]... [FILE [REV]...]'))
1555 1559 def debugdag(ui, repo, file_=None, *revs, **opts):
1556 1560 """format the changelog or an index DAG as a concise textual description
1557 1561
1558 1562 If you pass a revlog index, the revlog's DAG is emitted. If you list
1559 1563 revision numbers, they get labelled in the output as rN.
1560 1564
1561 1565 Otherwise, the changelog DAG of the current repo is emitted.
1562 1566 """
1563 1567 spaces = opts.get('spaces')
1564 1568 dots = opts.get('dots')
1565 1569 if file_:
1566 1570 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1567 1571 revs = set((int(r) for r in revs))
1568 1572 def events():
1569 1573 for r in rlog:
1570 1574 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1571 1575 if r in revs:
1572 1576 yield 'l', (r, "r%i" % r)
1573 1577 elif repo:
1574 1578 cl = repo.changelog
1575 1579 tags = opts.get('tags')
1576 1580 branches = opts.get('branches')
1577 1581 if tags:
1578 1582 labels = {}
1579 1583 for l, n in repo.tags().items():
1580 1584 labels.setdefault(cl.rev(n), []).append(l)
1581 1585 def events():
1582 1586 b = "default"
1583 1587 for r in cl:
1584 1588 if branches:
1585 1589 newb = cl.read(cl.node(r))[5]['branch']
1586 1590 if newb != b:
1587 1591 yield 'a', newb
1588 1592 b = newb
1589 1593 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1590 1594 if tags:
1591 1595 ls = labels.get(r)
1592 1596 if ls:
1593 1597 for l in ls:
1594 1598 yield 'l', (r, l)
1595 1599 else:
1596 1600 raise util.Abort(_('need repo for changelog dag'))
1597 1601
1598 1602 for line in dagparser.dagtextlines(events(),
1599 1603 addspaces=spaces,
1600 1604 wraplabels=True,
1601 1605 wrapannotations=True,
1602 1606 wrapnonlinear=dots,
1603 1607 usedots=dots,
1604 1608 maxlinewidth=70):
1605 1609 ui.write(line)
1606 1610 ui.write("\n")
1607 1611
1608 1612 @command('debugdata',
1609 1613 [('c', 'changelog', False, _('open changelog')),
1610 1614 ('m', 'manifest', False, _('open manifest'))],
1611 1615 _('-c|-m|FILE REV'))
1612 1616 def debugdata(ui, repo, file_, rev = None, **opts):
1613 1617 """dump the contents of a data file revision"""
1614 1618 if opts.get('changelog') or opts.get('manifest'):
1615 1619 file_, rev = None, file_
1616 1620 elif rev is None:
1617 1621 raise error.CommandError('debugdata', _('invalid arguments'))
1618 1622 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1619 1623 try:
1620 1624 ui.write(r.revision(r.lookup(rev)))
1621 1625 except KeyError:
1622 1626 raise util.Abort(_('invalid revision identifier %s') % rev)
1623 1627
1624 1628 @command('debugdate',
1625 1629 [('e', 'extended', None, _('try extended date formats'))],
1626 1630 _('[-e] DATE [RANGE]'))
1627 1631 def debugdate(ui, date, range=None, **opts):
1628 1632 """parse and display a date"""
1629 1633 if opts["extended"]:
1630 1634 d = util.parsedate(date, util.extendeddateformats)
1631 1635 else:
1632 1636 d = util.parsedate(date)
1633 1637 ui.write("internal: %s %s\n" % d)
1634 1638 ui.write("standard: %s\n" % util.datestr(d))
1635 1639 if range:
1636 1640 m = util.matchdate(range)
1637 1641 ui.write("match: %s\n" % m(d[0]))
1638 1642
1639 1643 @command('debugdiscovery',
1640 1644 [('', 'old', None, _('use old-style discovery')),
1641 1645 ('', 'nonheads', None,
1642 1646 _('use old-style discovery with non-heads included')),
1643 1647 ] + remoteopts,
1644 1648 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1645 1649 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1646 1650 """runs the changeset discovery protocol in isolation"""
1647 1651 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1648 1652 remote = hg.peer(repo, opts, remoteurl)
1649 1653 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1650 1654
1651 1655 # make sure tests are repeatable
1652 1656 random.seed(12323)
1653 1657
1654 1658 def doit(localheads, remoteheads):
1655 1659 if opts.get('old'):
1656 1660 if localheads:
1657 1661 raise util.Abort('cannot use localheads with old style discovery')
1658 1662 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1659 1663 force=True)
1660 1664 common = set(common)
1661 1665 if not opts.get('nonheads'):
1662 1666 ui.write("unpruned common: %s\n" % " ".join([short(n)
1663 1667 for n in common]))
1664 1668 dag = dagutil.revlogdag(repo.changelog)
1665 1669 all = dag.ancestorset(dag.internalizeall(common))
1666 1670 common = dag.externalizeall(dag.headsetofconnecteds(all))
1667 1671 else:
1668 1672 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1669 1673 common = set(common)
1670 1674 rheads = set(hds)
1671 1675 lheads = set(repo.heads())
1672 1676 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1673 1677 if lheads <= common:
1674 1678 ui.write("local is subset\n")
1675 1679 elif rheads <= common:
1676 1680 ui.write("remote is subset\n")
1677 1681
1678 1682 serverlogs = opts.get('serverlog')
1679 1683 if serverlogs:
1680 1684 for filename in serverlogs:
1681 1685 logfile = open(filename, 'r')
1682 1686 try:
1683 1687 line = logfile.readline()
1684 1688 while line:
1685 1689 parts = line.strip().split(';')
1686 1690 op = parts[1]
1687 1691 if op == 'cg':
1688 1692 pass
1689 1693 elif op == 'cgss':
1690 1694 doit(parts[2].split(' '), parts[3].split(' '))
1691 1695 elif op == 'unb':
1692 1696 doit(parts[3].split(' '), parts[2].split(' '))
1693 1697 line = logfile.readline()
1694 1698 finally:
1695 1699 logfile.close()
1696 1700
1697 1701 else:
1698 1702 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1699 1703 opts.get('remote_head'))
1700 1704 localrevs = opts.get('local_head')
1701 1705 doit(localrevs, remoterevs)
1702 1706
1703 1707 @command('debugfileset', [], ('REVSPEC'))
1704 1708 def debugfileset(ui, repo, expr):
1705 1709 '''parse and apply a fileset specification'''
1706 1710 if ui.verbose:
1707 1711 tree = fileset.parse(expr)[0]
1708 1712 ui.note(tree, "\n")
1709 1713
1710 1714 for f in fileset.getfileset(repo[None], expr):
1711 1715 ui.write("%s\n" % f)
1712 1716
1713 1717 @command('debugfsinfo', [], _('[PATH]'))
1714 1718 def debugfsinfo(ui, path = "."):
1715 1719 """show information detected about current filesystem"""
1716 1720 util.writefile('.debugfsinfo', '')
1717 1721 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1718 1722 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1719 1723 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1720 1724 and 'yes' or 'no'))
1721 1725 os.unlink('.debugfsinfo')
1722 1726
1723 1727 @command('debuggetbundle',
1724 1728 [('H', 'head', [], _('id of head node'), _('ID')),
1725 1729 ('C', 'common', [], _('id of common node'), _('ID')),
1726 1730 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1727 1731 _('REPO FILE [-H|-C ID]...'))
1728 1732 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1729 1733 """retrieves a bundle from a repo
1730 1734
1731 1735 Every ID must be a full-length hex node id string. Saves the bundle to the
1732 1736 given file.
1733 1737 """
1734 1738 repo = hg.peer(ui, opts, repopath)
1735 1739 if not repo.capable('getbundle'):
1736 1740 raise util.Abort("getbundle() not supported by target repository")
1737 1741 args = {}
1738 1742 if common:
1739 1743 args['common'] = [bin(s) for s in common]
1740 1744 if head:
1741 1745 args['heads'] = [bin(s) for s in head]
1742 1746 bundle = repo.getbundle('debug', **args)
1743 1747
1744 1748 bundletype = opts.get('type', 'bzip2').lower()
1745 1749 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1746 1750 bundletype = btypes.get(bundletype)
1747 1751 if bundletype not in changegroup.bundletypes:
1748 1752 raise util.Abort(_('unknown bundle type specified with --type'))
1749 1753 changegroup.writebundle(bundle, bundlepath, bundletype)
1750 1754
1751 1755 @command('debugignore', [], '')
1752 1756 def debugignore(ui, repo, *values, **opts):
1753 1757 """display the combined ignore pattern"""
1754 1758 ignore = repo.dirstate._ignore
1755 1759 includepat = getattr(ignore, 'includepat', None)
1756 1760 if includepat is not None:
1757 1761 ui.write("%s\n" % includepat)
1758 1762 else:
1759 1763 raise util.Abort(_("no ignore patterns found"))
1760 1764
1761 1765 @command('debugindex',
1762 1766 [('c', 'changelog', False, _('open changelog')),
1763 1767 ('m', 'manifest', False, _('open manifest')),
1764 1768 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1765 1769 _('[-f FORMAT] -c|-m|FILE'))
1766 1770 def debugindex(ui, repo, file_ = None, **opts):
1767 1771 """dump the contents of an index file"""
1768 1772 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1769 1773 format = opts.get('format', 0)
1770 1774 if format not in (0, 1):
1771 1775 raise util.Abort(_("unknown format %d") % format)
1772 1776
1773 1777 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1774 1778 if generaldelta:
1775 1779 basehdr = ' delta'
1776 1780 else:
1777 1781 basehdr = ' base'
1778 1782
1779 1783 if format == 0:
1780 1784 ui.write(" rev offset length " + basehdr + " linkrev"
1781 1785 " nodeid p1 p2\n")
1782 1786 elif format == 1:
1783 1787 ui.write(" rev flag offset length"
1784 1788 " size " + basehdr + " link p1 p2 nodeid\n")
1785 1789
1786 1790 for i in r:
1787 1791 node = r.node(i)
1788 1792 if generaldelta:
1789 1793 base = r.deltaparent(i)
1790 1794 else:
1791 1795 base = r.chainbase(i)
1792 1796 if format == 0:
1793 1797 try:
1794 1798 pp = r.parents(node)
1795 1799 except:
1796 1800 pp = [nullid, nullid]
1797 1801 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1798 1802 i, r.start(i), r.length(i), base, r.linkrev(i),
1799 1803 short(node), short(pp[0]), short(pp[1])))
1800 1804 elif format == 1:
1801 1805 pr = r.parentrevs(i)
1802 1806 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1803 1807 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1804 1808 base, r.linkrev(i), pr[0], pr[1], short(node)))
1805 1809
1806 1810 @command('debugindexdot', [], _('FILE'))
1807 1811 def debugindexdot(ui, repo, file_):
1808 1812 """dump an index DAG as a graphviz dot file"""
1809 1813 r = None
1810 1814 if repo:
1811 1815 filelog = repo.file(file_)
1812 1816 if len(filelog):
1813 1817 r = filelog
1814 1818 if not r:
1815 1819 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1816 1820 ui.write("digraph G {\n")
1817 1821 for i in r:
1818 1822 node = r.node(i)
1819 1823 pp = r.parents(node)
1820 1824 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1821 1825 if pp[1] != nullid:
1822 1826 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1823 1827 ui.write("}\n")
1824 1828
1825 1829 @command('debuginstall', [], '')
1826 1830 def debuginstall(ui):
1827 1831 '''test Mercurial installation
1828 1832
1829 1833 Returns 0 on success.
1830 1834 '''
1831 1835
1832 1836 def writetemp(contents):
1833 1837 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1834 1838 f = os.fdopen(fd, "wb")
1835 1839 f.write(contents)
1836 1840 f.close()
1837 1841 return name
1838 1842
1839 1843 problems = 0
1840 1844
1841 1845 # encoding
1842 1846 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1843 1847 try:
1844 1848 encoding.fromlocal("test")
1845 1849 except util.Abort, inst:
1846 1850 ui.write(" %s\n" % inst)
1847 1851 ui.write(_(" (check that your locale is properly set)\n"))
1848 1852 problems += 1
1849 1853
1850 1854 # compiled modules
1851 1855 ui.status(_("Checking installed modules (%s)...\n")
1852 1856 % os.path.dirname(__file__))
1853 1857 try:
1854 1858 import bdiff, mpatch, base85, osutil
1855 1859 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1856 1860 except Exception, inst:
1857 1861 ui.write(" %s\n" % inst)
1858 1862 ui.write(_(" One or more extensions could not be found"))
1859 1863 ui.write(_(" (check that you compiled the extensions)\n"))
1860 1864 problems += 1
1861 1865
1862 1866 # templates
1863 1867 import templater
1864 1868 p = templater.templatepath()
1865 1869 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1866 1870 try:
1867 1871 templater.templater(templater.templatepath("map-cmdline.default"))
1868 1872 except Exception, inst:
1869 1873 ui.write(" %s\n" % inst)
1870 1874 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1871 1875 problems += 1
1872 1876
1873 1877 # editor
1874 1878 ui.status(_("Checking commit editor...\n"))
1875 1879 editor = ui.geteditor()
1876 1880 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1877 1881 if not cmdpath:
1878 1882 if editor == 'vi':
1879 1883 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1880 1884 ui.write(_(" (specify a commit editor in your configuration"
1881 1885 " file)\n"))
1882 1886 else:
1883 1887 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1884 1888 ui.write(_(" (specify a commit editor in your configuration"
1885 1889 " file)\n"))
1886 1890 problems += 1
1887 1891
1888 1892 # check username
1889 1893 ui.status(_("Checking username...\n"))
1890 1894 try:
1891 1895 ui.username()
1892 1896 except util.Abort, e:
1893 1897 ui.write(" %s\n" % e)
1894 1898 ui.write(_(" (specify a username in your configuration file)\n"))
1895 1899 problems += 1
1896 1900
1897 1901 if not problems:
1898 1902 ui.status(_("No problems detected\n"))
1899 1903 else:
1900 1904 ui.write(_("%s problems detected,"
1901 1905 " please check your install!\n") % problems)
1902 1906
1903 1907 return problems
1904 1908
1905 1909 @command('debugknown', [], _('REPO ID...'))
1906 1910 def debugknown(ui, repopath, *ids, **opts):
1907 1911 """test whether node ids are known to a repo
1908 1912
1909 1913 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1910 1914 indicating unknown/known.
1911 1915 """
1912 1916 repo = hg.peer(ui, opts, repopath)
1913 1917 if not repo.capable('known'):
1914 1918 raise util.Abort("known() not supported by target repository")
1915 1919 flags = repo.known([bin(s) for s in ids])
1916 1920 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1917 1921
1918 1922 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1919 1923 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1920 1924 '''access the pushkey key/value protocol
1921 1925
1922 1926 With two args, list the keys in the given namespace.
1923 1927
1924 1928 With five args, set a key to new if it currently is set to old.
1925 1929 Reports success or failure.
1926 1930 '''
1927 1931
1928 1932 target = hg.peer(ui, {}, repopath)
1929 1933 if keyinfo:
1930 1934 key, old, new = keyinfo
1931 1935 r = target.pushkey(namespace, key, old, new)
1932 1936 ui.status(str(r) + '\n')
1933 1937 return not r
1934 1938 else:
1935 1939 for k, v in target.listkeys(namespace).iteritems():
1936 1940 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1937 1941 v.encode('string-escape')))
1938 1942
1939 1943 @command('debugrebuildstate',
1940 1944 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1941 1945 _('[-r REV] [REV]'))
1942 1946 def debugrebuildstate(ui, repo, rev="tip"):
1943 1947 """rebuild the dirstate as it would look like for the given revision"""
1944 1948 ctx = scmutil.revsingle(repo, rev)
1945 1949 wlock = repo.wlock()
1946 1950 try:
1947 1951 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1948 1952 finally:
1949 1953 wlock.release()
1950 1954
1951 1955 @command('debugrename',
1952 1956 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1953 1957 _('[-r REV] FILE'))
1954 1958 def debugrename(ui, repo, file1, *pats, **opts):
1955 1959 """dump rename information"""
1956 1960
1957 1961 ctx = scmutil.revsingle(repo, opts.get('rev'))
1958 1962 m = scmutil.match(ctx, (file1,) + pats, opts)
1959 1963 for abs in ctx.walk(m):
1960 1964 fctx = ctx[abs]
1961 1965 o = fctx.filelog().renamed(fctx.filenode())
1962 1966 rel = m.rel(abs)
1963 1967 if o:
1964 1968 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1965 1969 else:
1966 1970 ui.write(_("%s not renamed\n") % rel)
1967 1971
1968 1972 @command('debugrevlog',
1969 1973 [('c', 'changelog', False, _('open changelog')),
1970 1974 ('m', 'manifest', False, _('open manifest')),
1971 1975 ('d', 'dump', False, _('dump index data'))],
1972 1976 _('-c|-m|FILE'))
1973 1977 def debugrevlog(ui, repo, file_ = None, **opts):
1974 1978 """show data and statistics about a revlog"""
1975 1979 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1976 1980
1977 1981 if opts.get("dump"):
1978 1982 numrevs = len(r)
1979 1983 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1980 1984 " rawsize totalsize compression heads\n")
1981 1985 ts = 0
1982 1986 heads = set()
1983 1987 for rev in xrange(numrevs):
1984 1988 dbase = r.deltaparent(rev)
1985 1989 if dbase == -1:
1986 1990 dbase = rev
1987 1991 cbase = r.chainbase(rev)
1988 1992 p1, p2 = r.parentrevs(rev)
1989 1993 rs = r.rawsize(rev)
1990 1994 ts = ts + rs
1991 1995 heads -= set(r.parentrevs(rev))
1992 1996 heads.add(rev)
1993 1997 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1994 1998 (rev, p1, p2, r.start(rev), r.end(rev),
1995 1999 r.start(dbase), r.start(cbase),
1996 2000 r.start(p1), r.start(p2),
1997 2001 rs, ts, ts / r.end(rev), len(heads)))
1998 2002 return 0
1999 2003
2000 2004 v = r.version
2001 2005 format = v & 0xFFFF
2002 2006 flags = []
2003 2007 gdelta = False
2004 2008 if v & revlog.REVLOGNGINLINEDATA:
2005 2009 flags.append('inline')
2006 2010 if v & revlog.REVLOGGENERALDELTA:
2007 2011 gdelta = True
2008 2012 flags.append('generaldelta')
2009 2013 if not flags:
2010 2014 flags = ['(none)']
2011 2015
2012 2016 nummerges = 0
2013 2017 numfull = 0
2014 2018 numprev = 0
2015 2019 nump1 = 0
2016 2020 nump2 = 0
2017 2021 numother = 0
2018 2022 nump1prev = 0
2019 2023 nump2prev = 0
2020 2024 chainlengths = []
2021 2025
2022 2026 datasize = [None, 0, 0L]
2023 2027 fullsize = [None, 0, 0L]
2024 2028 deltasize = [None, 0, 0L]
2025 2029
2026 2030 def addsize(size, l):
2027 2031 if l[0] is None or size < l[0]:
2028 2032 l[0] = size
2029 2033 if size > l[1]:
2030 2034 l[1] = size
2031 2035 l[2] += size
2032 2036
2033 2037 numrevs = len(r)
2034 2038 for rev in xrange(numrevs):
2035 2039 p1, p2 = r.parentrevs(rev)
2036 2040 delta = r.deltaparent(rev)
2037 2041 if format > 0:
2038 2042 addsize(r.rawsize(rev), datasize)
2039 2043 if p2 != nullrev:
2040 2044 nummerges += 1
2041 2045 size = r.length(rev)
2042 2046 if delta == nullrev:
2043 2047 chainlengths.append(0)
2044 2048 numfull += 1
2045 2049 addsize(size, fullsize)
2046 2050 else:
2047 2051 chainlengths.append(chainlengths[delta] + 1)
2048 2052 addsize(size, deltasize)
2049 2053 if delta == rev - 1:
2050 2054 numprev += 1
2051 2055 if delta == p1:
2052 2056 nump1prev += 1
2053 2057 elif delta == p2:
2054 2058 nump2prev += 1
2055 2059 elif delta == p1:
2056 2060 nump1 += 1
2057 2061 elif delta == p2:
2058 2062 nump2 += 1
2059 2063 elif delta != nullrev:
2060 2064 numother += 1
2061 2065
2062 2066 numdeltas = numrevs - numfull
2063 2067 numoprev = numprev - nump1prev - nump2prev
2064 2068 totalrawsize = datasize[2]
2065 2069 datasize[2] /= numrevs
2066 2070 fulltotal = fullsize[2]
2067 2071 fullsize[2] /= numfull
2068 2072 deltatotal = deltasize[2]
2069 2073 deltasize[2] /= numrevs - numfull
2070 2074 totalsize = fulltotal + deltatotal
2071 2075 avgchainlen = sum(chainlengths) / numrevs
2072 2076 compratio = totalrawsize / totalsize
2073 2077
2074 2078 basedfmtstr = '%%%dd\n'
2075 2079 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2076 2080
2077 2081 def dfmtstr(max):
2078 2082 return basedfmtstr % len(str(max))
2079 2083 def pcfmtstr(max, padding=0):
2080 2084 return basepcfmtstr % (len(str(max)), ' ' * padding)
2081 2085
2082 2086 def pcfmt(value, total):
2083 2087 return (value, 100 * float(value) / total)
2084 2088
2085 2089 ui.write('format : %d\n' % format)
2086 2090 ui.write('flags : %s\n' % ', '.join(flags))
2087 2091
2088 2092 ui.write('\n')
2089 2093 fmt = pcfmtstr(totalsize)
2090 2094 fmt2 = dfmtstr(totalsize)
2091 2095 ui.write('revisions : ' + fmt2 % numrevs)
2092 2096 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2093 2097 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2094 2098 ui.write('revisions : ' + fmt2 % numrevs)
2095 2099 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2096 2100 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2097 2101 ui.write('revision size : ' + fmt2 % totalsize)
2098 2102 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2099 2103 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2100 2104
2101 2105 ui.write('\n')
2102 2106 fmt = dfmtstr(max(avgchainlen, compratio))
2103 2107 ui.write('avg chain length : ' + fmt % avgchainlen)
2104 2108 ui.write('compression ratio : ' + fmt % compratio)
2105 2109
2106 2110 if format > 0:
2107 2111 ui.write('\n')
2108 2112 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2109 2113 % tuple(datasize))
2110 2114 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2111 2115 % tuple(fullsize))
2112 2116 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2113 2117 % tuple(deltasize))
2114 2118
2115 2119 if numdeltas > 0:
2116 2120 ui.write('\n')
2117 2121 fmt = pcfmtstr(numdeltas)
2118 2122 fmt2 = pcfmtstr(numdeltas, 4)
2119 2123 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2120 2124 if numprev > 0:
2121 2125 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2122 2126 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2123 2127 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2124 2128 if gdelta:
2125 2129 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2126 2130 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2127 2131 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2128 2132
2129 2133 @command('debugrevspec', [], ('REVSPEC'))
2130 2134 def debugrevspec(ui, repo, expr):
2131 2135 '''parse and apply a revision specification'''
2132 2136 if ui.verbose:
2133 2137 tree = revset.parse(expr)[0]
2134 2138 ui.note(tree, "\n")
2135 2139 newtree = revset.findaliases(ui, tree)
2136 2140 if newtree != tree:
2137 2141 ui.note(newtree, "\n")
2138 2142 func = revset.match(ui, expr)
2139 2143 for c in func(repo, range(len(repo))):
2140 2144 ui.write("%s\n" % c)
2141 2145
2142 2146 @command('debugsetparents', [], _('REV1 [REV2]'))
2143 2147 def debugsetparents(ui, repo, rev1, rev2=None):
2144 2148 """manually set the parents of the current working directory
2145 2149
2146 2150 This is useful for writing repository conversion tools, but should
2147 2151 be used with care.
2148 2152
2149 2153 Returns 0 on success.
2150 2154 """
2151 2155
2152 2156 r1 = scmutil.revsingle(repo, rev1).node()
2153 2157 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2154 2158
2155 2159 wlock = repo.wlock()
2156 2160 try:
2157 2161 repo.dirstate.setparents(r1, r2)
2158 2162 finally:
2159 2163 wlock.release()
2160 2164
2161 2165 @command('debugstate',
2162 2166 [('', 'nodates', None, _('do not display the saved mtime')),
2163 2167 ('', 'datesort', None, _('sort by saved mtime'))],
2164 2168 _('[OPTION]...'))
2165 2169 def debugstate(ui, repo, nodates=None, datesort=None):
2166 2170 """show the contents of the current dirstate"""
2167 2171 timestr = ""
2168 2172 showdate = not nodates
2169 2173 if datesort:
2170 2174 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2171 2175 else:
2172 2176 keyfunc = None # sort by filename
2173 2177 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2174 2178 if showdate:
2175 2179 if ent[3] == -1:
2176 2180 # Pad or slice to locale representation
2177 2181 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2178 2182 time.localtime(0)))
2179 2183 timestr = 'unset'
2180 2184 timestr = (timestr[:locale_len] +
2181 2185 ' ' * (locale_len - len(timestr)))
2182 2186 else:
2183 2187 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2184 2188 time.localtime(ent[3]))
2185 2189 if ent[1] & 020000:
2186 2190 mode = 'lnk'
2187 2191 else:
2188 2192 mode = '%3o' % (ent[1] & 0777)
2189 2193 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2190 2194 for f in repo.dirstate.copies():
2191 2195 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2192 2196
2193 2197 @command('debugsub',
2194 2198 [('r', 'rev', '',
2195 2199 _('revision to check'), _('REV'))],
2196 2200 _('[-r REV] [REV]'))
2197 2201 def debugsub(ui, repo, rev=None):
2198 2202 ctx = scmutil.revsingle(repo, rev, None)
2199 2203 for k, v in sorted(ctx.substate.items()):
2200 2204 ui.write('path %s\n' % k)
2201 2205 ui.write(' source %s\n' % v[0])
2202 2206 ui.write(' revision %s\n' % v[1])
2203 2207
2204 2208 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2205 2209 def debugwalk(ui, repo, *pats, **opts):
2206 2210 """show how files match on given patterns"""
2207 2211 m = scmutil.match(repo[None], pats, opts)
2208 2212 items = list(repo.walk(m))
2209 2213 if not items:
2210 2214 return
2211 2215 fmt = 'f %%-%ds %%-%ds %%s' % (
2212 2216 max([len(abs) for abs in items]),
2213 2217 max([len(m.rel(abs)) for abs in items]))
2214 2218 for abs in items:
2215 2219 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2216 2220 ui.write("%s\n" % line.rstrip())
2217 2221
2218 2222 @command('debugwireargs',
2219 2223 [('', 'three', '', 'three'),
2220 2224 ('', 'four', '', 'four'),
2221 2225 ('', 'five', '', 'five'),
2222 2226 ] + remoteopts,
2223 2227 _('REPO [OPTIONS]... [ONE [TWO]]'))
2224 2228 def debugwireargs(ui, repopath, *vals, **opts):
2225 2229 repo = hg.peer(ui, opts, repopath)
2226 2230 for opt in remoteopts:
2227 2231 del opts[opt[1]]
2228 2232 args = {}
2229 2233 for k, v in opts.iteritems():
2230 2234 if v:
2231 2235 args[k] = v
2232 2236 # run twice to check that we don't mess up the stream for the next command
2233 2237 res1 = repo.debugwireargs(*vals, **args)
2234 2238 res2 = repo.debugwireargs(*vals, **args)
2235 2239 ui.write("%s\n" % res1)
2236 2240 if res1 != res2:
2237 2241 ui.warn("%s\n" % res2)
2238 2242
2239 2243 @command('^diff',
2240 2244 [('r', 'rev', [], _('revision'), _('REV')),
2241 2245 ('c', 'change', '', _('change made by revision'), _('REV'))
2242 2246 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2243 2247 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2244 2248 def diff(ui, repo, *pats, **opts):
2245 2249 """diff repository (or selected files)
2246 2250
2247 2251 Show differences between revisions for the specified files.
2248 2252
2249 2253 Differences between files are shown using the unified diff format.
2250 2254
2251 2255 .. note::
2252 2256 diff may generate unexpected results for merges, as it will
2253 2257 default to comparing against the working directory's first
2254 2258 parent changeset if no revisions are specified.
2255 2259
2256 2260 When two revision arguments are given, then changes are shown
2257 2261 between those revisions. If only one revision is specified then
2258 2262 that revision is compared to the working directory, and, when no
2259 2263 revisions are specified, the working directory files are compared
2260 2264 to its parent.
2261 2265
2262 2266 Alternatively you can specify -c/--change with a revision to see
2263 2267 the changes in that changeset relative to its first parent.
2264 2268
2265 2269 Without the -a/--text option, diff will avoid generating diffs of
2266 2270 files it detects as binary. With -a, diff will generate a diff
2267 2271 anyway, probably with undesirable results.
2268 2272
2269 2273 Use the -g/--git option to generate diffs in the git extended diff
2270 2274 format. For more information, read :hg:`help diffs`.
2271 2275
2272 2276 .. container:: verbose
2273 2277
2274 2278 Examples:
2275 2279
2276 2280 - compare a file in the current working directory to its parent::
2277 2281
2278 2282 hg diff foo.c
2279 2283
2280 2284 - compare two historical versions of a directory, with rename info::
2281 2285
2282 2286 hg diff --git -r 1.0:1.2 lib/
2283 2287
2284 2288 - get change stats relative to the last change on some date::
2285 2289
2286 2290 hg diff --stat -r "date('may 2')"
2287 2291
2288 2292 - diff all newly-added files that contain a keyword::
2289 2293
2290 2294 hg diff "set:added() and grep(GNU)"
2291 2295
2292 2296 - compare a revision and its parents::
2293 2297
2294 2298 hg diff -c 9353 # compare against first parent
2295 2299 hg diff -r 9353^:9353 # same using revset syntax
2296 2300 hg diff -r 9353^2:9353 # compare against the second parent
2297 2301
2298 2302 Returns 0 on success.
2299 2303 """
2300 2304
2301 2305 revs = opts.get('rev')
2302 2306 change = opts.get('change')
2303 2307 stat = opts.get('stat')
2304 2308 reverse = opts.get('reverse')
2305 2309
2306 2310 if revs and change:
2307 2311 msg = _('cannot specify --rev and --change at the same time')
2308 2312 raise util.Abort(msg)
2309 2313 elif change:
2310 2314 node2 = scmutil.revsingle(repo, change, None).node()
2311 2315 node1 = repo[node2].p1().node()
2312 2316 else:
2313 2317 node1, node2 = scmutil.revpair(repo, revs)
2314 2318
2315 2319 if reverse:
2316 2320 node1, node2 = node2, node1
2317 2321
2318 2322 diffopts = patch.diffopts(ui, opts)
2319 2323 m = scmutil.match(repo[node2], pats, opts)
2320 2324 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2321 2325 listsubrepos=opts.get('subrepos'))
2322 2326
2323 2327 @command('^export',
2324 2328 [('o', 'output', '',
2325 2329 _('print output to file with formatted name'), _('FORMAT')),
2326 2330 ('', 'switch-parent', None, _('diff against the second parent')),
2327 2331 ('r', 'rev', [], _('revisions to export'), _('REV')),
2328 2332 ] + diffopts,
2329 2333 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2330 2334 def export(ui, repo, *changesets, **opts):
2331 2335 """dump the header and diffs for one or more changesets
2332 2336
2333 2337 Print the changeset header and diffs for one or more revisions.
2334 2338
2335 2339 The information shown in the changeset header is: author, date,
2336 2340 branch name (if non-default), changeset hash, parent(s) and commit
2337 2341 comment.
2338 2342
2339 2343 .. note::
2340 2344 export may generate unexpected diff output for merge
2341 2345 changesets, as it will compare the merge changeset against its
2342 2346 first parent only.
2343 2347
2344 2348 Output may be to a file, in which case the name of the file is
2345 2349 given using a format string. The formatting rules are as follows:
2346 2350
2347 2351 :``%%``: literal "%" character
2348 2352 :``%H``: changeset hash (40 hexadecimal digits)
2349 2353 :``%N``: number of patches being generated
2350 2354 :``%R``: changeset revision number
2351 2355 :``%b``: basename of the exporting repository
2352 2356 :``%h``: short-form changeset hash (12 hexadecimal digits)
2353 2357 :``%m``: first line of the commit message (only alphanumeric characters)
2354 2358 :``%n``: zero-padded sequence number, starting at 1
2355 2359 :``%r``: zero-padded changeset revision number
2356 2360
2357 2361 Without the -a/--text option, export will avoid generating diffs
2358 2362 of files it detects as binary. With -a, export will generate a
2359 2363 diff anyway, probably with undesirable results.
2360 2364
2361 2365 Use the -g/--git option to generate diffs in the git extended diff
2362 2366 format. See :hg:`help diffs` for more information.
2363 2367
2364 2368 With the --switch-parent option, the diff will be against the
2365 2369 second parent. It can be useful to review a merge.
2366 2370
2367 2371 .. container:: verbose
2368 2372
2369 2373 Examples:
2370 2374
2371 2375 - use export and import to transplant a bugfix to the current
2372 2376 branch::
2373 2377
2374 2378 hg export -r 9353 | hg import -
2375 2379
2376 2380 - export all the changesets between two revisions to a file with
2377 2381 rename information::
2378 2382
2379 2383 hg export --git -r 123:150 > changes.txt
2380 2384
2381 2385 - split outgoing changes into a series of patches with
2382 2386 descriptive names::
2383 2387
2384 2388 hg export -r "outgoing()" -o "%n-%m.patch"
2385 2389
2386 2390 Returns 0 on success.
2387 2391 """
2388 2392 changesets += tuple(opts.get('rev', []))
2389 2393 if not changesets:
2390 2394 raise util.Abort(_("export requires at least one changeset"))
2391 2395 revs = scmutil.revrange(repo, changesets)
2392 2396 if len(revs) > 1:
2393 2397 ui.note(_('exporting patches:\n'))
2394 2398 else:
2395 2399 ui.note(_('exporting patch:\n'))
2396 2400 cmdutil.export(repo, revs, template=opts.get('output'),
2397 2401 switch_parent=opts.get('switch_parent'),
2398 2402 opts=patch.diffopts(ui, opts))
2399 2403
2400 2404 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2401 2405 def forget(ui, repo, *pats, **opts):
2402 2406 """forget the specified files on the next commit
2403 2407
2404 2408 Mark the specified files so they will no longer be tracked
2405 2409 after the next commit.
2406 2410
2407 2411 This only removes files from the current branch, not from the
2408 2412 entire project history, and it does not delete them from the
2409 2413 working directory.
2410 2414
2411 2415 To undo a forget before the next commit, see :hg:`add`.
2412 2416
2413 2417 .. container:: verbose
2414 2418
2415 2419 Examples:
2416 2420
2417 2421 - forget newly-added binary files::
2418 2422
2419 2423 hg forget "set:added() and binary()"
2420 2424
2421 2425 - forget files that would be excluded by .hgignore::
2422 2426
2423 2427 hg forget "set:hgignore()"
2424 2428
2425 2429 Returns 0 on success.
2426 2430 """
2427 2431
2428 2432 if not pats:
2429 2433 raise util.Abort(_('no files specified'))
2430 2434
2431 2435 m = scmutil.match(repo[None], pats, opts)
2432 2436 s = repo.status(match=m, clean=True)
2433 2437 forget = sorted(s[0] + s[1] + s[3] + s[6])
2434 2438 errs = 0
2435 2439
2436 2440 for f in m.files():
2437 2441 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2438 2442 if os.path.exists(m.rel(f)):
2439 2443 ui.warn(_('not removing %s: file is already untracked\n')
2440 2444 % m.rel(f))
2441 2445 errs = 1
2442 2446
2443 2447 for f in forget:
2444 2448 if ui.verbose or not m.exact(f):
2445 2449 ui.status(_('removing %s\n') % m.rel(f))
2446 2450
2447 2451 repo[None].forget(forget)
2448 2452 return errs
2449 2453
2450 2454 @command(
2451 2455 'graft',
2452 2456 [('c', 'continue', False, _('resume interrupted graft')),
2453 2457 ('e', 'edit', False, _('invoke editor on commit messages')),
2454 2458 ('D', 'currentdate', False,
2455 2459 _('record the current date as commit date')),
2456 2460 ('U', 'currentuser', False,
2457 2461 _('record the current user as committer'), _('DATE'))]
2458 2462 + commitopts2 + mergetoolopts,
2459 2463 _('[OPTION]... REVISION...'))
2460 2464 def graft(ui, repo, *revs, **opts):
2461 2465 '''copy changes from other branches onto the current branch
2462 2466
2463 2467 This command uses Mercurial's merge logic to copy individual
2464 2468 changes from other branches without merging branches in the
2465 2469 history graph. This is sometimes known as 'backporting' or
2466 2470 'cherry-picking'. By default, graft will copy user, date, and
2467 2471 description from the source changesets.
2468 2472
2469 2473 Changesets that are ancestors of the current revision, that have
2470 2474 already been grafted, or that are merges will be skipped.
2471 2475
2472 2476 If a graft merge results in conflicts, the graft process is
2473 2477 aborted so that the current merge can be manually resolved. Once
2474 2478 all conflicts are addressed, the graft process can be continued
2475 2479 with the -c/--continue option.
2476 2480
2477 2481 .. note::
2478 2482 The -c/--continue option does not reapply earlier options.
2479 2483
2480 2484 .. container:: verbose
2481 2485
2482 2486 Examples:
2483 2487
2484 2488 - copy a single change to the stable branch and edit its description::
2485 2489
2486 2490 hg update stable
2487 2491 hg graft --edit 9393
2488 2492
2489 2493 - graft a range of changesets with one exception, updating dates::
2490 2494
2491 2495 hg graft -D "2085::2093 and not 2091"
2492 2496
2493 2497 - continue a graft after resolving conflicts::
2494 2498
2495 2499 hg graft -c
2496 2500
2497 2501 - show the source of a grafted changeset::
2498 2502
2499 2503 hg log --debug -r tip
2500 2504
2501 2505 Returns 0 on successful completion.
2502 2506 '''
2503 2507
2504 2508 if not opts.get('user') and opts.get('currentuser'):
2505 2509 opts['user'] = ui.username()
2506 2510 if not opts.get('date') and opts.get('currentdate'):
2507 2511 opts['date'] = "%d %d" % util.makedate()
2508 2512
2509 2513 editor = None
2510 2514 if opts.get('edit'):
2511 2515 editor = cmdutil.commitforceeditor
2512 2516
2513 2517 cont = False
2514 2518 if opts['continue']:
2515 2519 cont = True
2516 2520 if revs:
2517 2521 raise util.Abort(_("can't specify --continue and revisions"))
2518 2522 # read in unfinished revisions
2519 2523 try:
2520 2524 nodes = repo.opener.read('graftstate').splitlines()
2521 2525 revs = [repo[node].rev() for node in nodes]
2522 2526 except IOError, inst:
2523 2527 if inst.errno != errno.ENOENT:
2524 2528 raise
2525 2529 raise util.Abort(_("no graft state found, can't continue"))
2526 2530 else:
2527 2531 cmdutil.bailifchanged(repo)
2528 2532 if not revs:
2529 2533 raise util.Abort(_('no revisions specified'))
2530 2534 revs = scmutil.revrange(repo, revs)
2531 2535
2532 2536 # check for merges
2533 2537 for ctx in repo.set('%ld and merge()', revs):
2534 2538 ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev())
2535 2539 revs.remove(ctx.rev())
2536 2540 if not revs:
2537 2541 return -1
2538 2542
2539 2543 # check for ancestors of dest branch
2540 2544 for ctx in repo.set('::. and %ld', revs):
2541 2545 ui.warn(_('skipping ancestor revision %s\n') % ctx.rev())
2542 2546 revs.remove(ctx.rev())
2543 2547 if not revs:
2544 2548 return -1
2545 2549
2546 2550 # check ancestors for earlier grafts
2547 2551 ui.debug('scanning for existing transplants')
2548 2552 for ctx in repo.set("::. - ::%ld", revs):
2549 2553 n = ctx.extra().get('source')
2550 2554 if n and n in repo:
2551 2555 r = repo[n].rev()
2552 2556 ui.warn(_('skipping already grafted revision %s\n') % r)
2553 2557 revs.remove(r)
2554 2558 if not revs:
2555 2559 return -1
2556 2560
2557 2561 for pos, ctx in enumerate(repo.set("%ld", revs)):
2558 2562 current = repo['.']
2559 2563 ui.status('grafting revision %s', ctx.rev())
2560 2564
2561 2565 # we don't merge the first commit when continuing
2562 2566 if not cont:
2563 2567 # perform the graft merge with p1(rev) as 'ancestor'
2564 2568 try:
2565 2569 # ui.forcemerge is an internal variable, do not document
2566 2570 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2567 2571 stats = mergemod.update(repo, ctx.node(), True, True, False,
2568 2572 ctx.p1().node())
2569 2573 finally:
2570 2574 ui.setconfig('ui', 'forcemerge', '')
2571 2575 # drop the second merge parent
2572 2576 repo.dirstate.setparents(current.node(), nullid)
2573 2577 repo.dirstate.write()
2574 2578 # fix up dirstate for copies and renames
2575 2579 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2576 2580 # report any conflicts
2577 2581 if stats and stats[3] > 0:
2578 2582 # write out state for --continue
2579 2583 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2580 2584 repo.opener.write('graftstate', ''.join(nodelines))
2581 2585 raise util.Abort(
2582 2586 _("unresolved conflicts, can't continue"),
2583 2587 hint=_('use hg resolve and hg graft --continue'))
2584 2588 else:
2585 2589 cont = False
2586 2590
2587 2591 # commit
2588 2592 extra = {'source': ctx.hex()}
2589 2593 user = ctx.user()
2590 2594 if opts.get('user'):
2591 2595 user = opts['user']
2592 2596 date = ctx.date()
2593 2597 if opts.get('date'):
2594 2598 date = opts['date']
2595 2599 repo.commit(text=ctx.description(), user=user,
2596 2600 date=date, extra=extra, editor=editor)
2597 2601
2598 2602 # remove state when we complete successfully
2599 2603 if os.path.exists(repo.join('graftstate')):
2600 2604 util.unlinkpath(repo.join('graftstate'))
2601 2605
2602 2606 return 0
2603 2607
2604 2608 @command('grep',
2605 2609 [('0', 'print0', None, _('end fields with NUL')),
2606 2610 ('', 'all', None, _('print all revisions that match')),
2607 2611 ('a', 'text', None, _('treat all files as text')),
2608 2612 ('f', 'follow', None,
2609 2613 _('follow changeset history,'
2610 2614 ' or file history across copies and renames')),
2611 2615 ('i', 'ignore-case', None, _('ignore case when matching')),
2612 2616 ('l', 'files-with-matches', None,
2613 2617 _('print only filenames and revisions that match')),
2614 2618 ('n', 'line-number', None, _('print matching line numbers')),
2615 2619 ('r', 'rev', [],
2616 2620 _('only search files changed within revision range'), _('REV')),
2617 2621 ('u', 'user', None, _('list the author (long with -v)')),
2618 2622 ('d', 'date', None, _('list the date (short with -q)')),
2619 2623 ] + walkopts,
2620 2624 _('[OPTION]... PATTERN [FILE]...'))
2621 2625 def grep(ui, repo, pattern, *pats, **opts):
2622 2626 """search for a pattern in specified files and revisions
2623 2627
2624 2628 Search revisions of files for a regular expression.
2625 2629
2626 2630 This command behaves differently than Unix grep. It only accepts
2627 2631 Python/Perl regexps. It searches repository history, not the
2628 2632 working directory. It always prints the revision number in which a
2629 2633 match appears.
2630 2634
2631 2635 By default, grep only prints output for the first revision of a
2632 2636 file in which it finds a match. To get it to print every revision
2633 2637 that contains a change in match status ("-" for a match that
2634 2638 becomes a non-match, or "+" for a non-match that becomes a match),
2635 2639 use the --all flag.
2636 2640
2637 2641 Returns 0 if a match is found, 1 otherwise.
2638 2642 """
2639 2643 reflags = 0
2640 2644 if opts.get('ignore_case'):
2641 2645 reflags |= re.I
2642 2646 try:
2643 2647 regexp = re.compile(pattern, reflags)
2644 2648 except re.error, inst:
2645 2649 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2646 2650 return 1
2647 2651 sep, eol = ':', '\n'
2648 2652 if opts.get('print0'):
2649 2653 sep = eol = '\0'
2650 2654
2651 2655 getfile = util.lrucachefunc(repo.file)
2652 2656
2653 2657 def matchlines(body):
2654 2658 begin = 0
2655 2659 linenum = 0
2656 2660 while True:
2657 2661 match = regexp.search(body, begin)
2658 2662 if not match:
2659 2663 break
2660 2664 mstart, mend = match.span()
2661 2665 linenum += body.count('\n', begin, mstart) + 1
2662 2666 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2663 2667 begin = body.find('\n', mend) + 1 or len(body) + 1
2664 2668 lend = begin - 1
2665 2669 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2666 2670
2667 2671 class linestate(object):
2668 2672 def __init__(self, line, linenum, colstart, colend):
2669 2673 self.line = line
2670 2674 self.linenum = linenum
2671 2675 self.colstart = colstart
2672 2676 self.colend = colend
2673 2677
2674 2678 def __hash__(self):
2675 2679 return hash((self.linenum, self.line))
2676 2680
2677 2681 def __eq__(self, other):
2678 2682 return self.line == other.line
2679 2683
2680 2684 matches = {}
2681 2685 copies = {}
2682 2686 def grepbody(fn, rev, body):
2683 2687 matches[rev].setdefault(fn, [])
2684 2688 m = matches[rev][fn]
2685 2689 for lnum, cstart, cend, line in matchlines(body):
2686 2690 s = linestate(line, lnum, cstart, cend)
2687 2691 m.append(s)
2688 2692
2689 2693 def difflinestates(a, b):
2690 2694 sm = difflib.SequenceMatcher(None, a, b)
2691 2695 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2692 2696 if tag == 'insert':
2693 2697 for i in xrange(blo, bhi):
2694 2698 yield ('+', b[i])
2695 2699 elif tag == 'delete':
2696 2700 for i in xrange(alo, ahi):
2697 2701 yield ('-', a[i])
2698 2702 elif tag == 'replace':
2699 2703 for i in xrange(alo, ahi):
2700 2704 yield ('-', a[i])
2701 2705 for i in xrange(blo, bhi):
2702 2706 yield ('+', b[i])
2703 2707
2704 2708 def display(fn, ctx, pstates, states):
2705 2709 rev = ctx.rev()
2706 2710 datefunc = ui.quiet and util.shortdate or util.datestr
2707 2711 found = False
2708 2712 filerevmatches = {}
2709 2713 def binary():
2710 2714 flog = getfile(fn)
2711 2715 return util.binary(flog.read(ctx.filenode(fn)))
2712 2716
2713 2717 if opts.get('all'):
2714 2718 iter = difflinestates(pstates, states)
2715 2719 else:
2716 2720 iter = [('', l) for l in states]
2717 2721 for change, l in iter:
2718 2722 cols = [fn, str(rev)]
2719 2723 before, match, after = None, None, None
2720 2724 if opts.get('line_number'):
2721 2725 cols.append(str(l.linenum))
2722 2726 if opts.get('all'):
2723 2727 cols.append(change)
2724 2728 if opts.get('user'):
2725 2729 cols.append(ui.shortuser(ctx.user()))
2726 2730 if opts.get('date'):
2727 2731 cols.append(datefunc(ctx.date()))
2728 2732 if opts.get('files_with_matches'):
2729 2733 c = (fn, rev)
2730 2734 if c in filerevmatches:
2731 2735 continue
2732 2736 filerevmatches[c] = 1
2733 2737 else:
2734 2738 before = l.line[:l.colstart]
2735 2739 match = l.line[l.colstart:l.colend]
2736 2740 after = l.line[l.colend:]
2737 2741 ui.write(sep.join(cols))
2738 2742 if before is not None:
2739 2743 if not opts.get('text') and binary():
2740 2744 ui.write(sep + " Binary file matches")
2741 2745 else:
2742 2746 ui.write(sep + before)
2743 2747 ui.write(match, label='grep.match')
2744 2748 ui.write(after)
2745 2749 ui.write(eol)
2746 2750 found = True
2747 2751 return found
2748 2752
2749 2753 skip = {}
2750 2754 revfiles = {}
2751 2755 matchfn = scmutil.match(repo[None], pats, opts)
2752 2756 found = False
2753 2757 follow = opts.get('follow')
2754 2758
2755 2759 def prep(ctx, fns):
2756 2760 rev = ctx.rev()
2757 2761 pctx = ctx.p1()
2758 2762 parent = pctx.rev()
2759 2763 matches.setdefault(rev, {})
2760 2764 matches.setdefault(parent, {})
2761 2765 files = revfiles.setdefault(rev, [])
2762 2766 for fn in fns:
2763 2767 flog = getfile(fn)
2764 2768 try:
2765 2769 fnode = ctx.filenode(fn)
2766 2770 except error.LookupError:
2767 2771 continue
2768 2772
2769 2773 copied = flog.renamed(fnode)
2770 2774 copy = follow and copied and copied[0]
2771 2775 if copy:
2772 2776 copies.setdefault(rev, {})[fn] = copy
2773 2777 if fn in skip:
2774 2778 if copy:
2775 2779 skip[copy] = True
2776 2780 continue
2777 2781 files.append(fn)
2778 2782
2779 2783 if fn not in matches[rev]:
2780 2784 grepbody(fn, rev, flog.read(fnode))
2781 2785
2782 2786 pfn = copy or fn
2783 2787 if pfn not in matches[parent]:
2784 2788 try:
2785 2789 fnode = pctx.filenode(pfn)
2786 2790 grepbody(pfn, parent, flog.read(fnode))
2787 2791 except error.LookupError:
2788 2792 pass
2789 2793
2790 2794 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2791 2795 rev = ctx.rev()
2792 2796 parent = ctx.p1().rev()
2793 2797 for fn in sorted(revfiles.get(rev, [])):
2794 2798 states = matches[rev][fn]
2795 2799 copy = copies.get(rev, {}).get(fn)
2796 2800 if fn in skip:
2797 2801 if copy:
2798 2802 skip[copy] = True
2799 2803 continue
2800 2804 pstates = matches.get(parent, {}).get(copy or fn, [])
2801 2805 if pstates or states:
2802 2806 r = display(fn, ctx, pstates, states)
2803 2807 found = found or r
2804 2808 if r and not opts.get('all'):
2805 2809 skip[fn] = True
2806 2810 if copy:
2807 2811 skip[copy] = True
2808 2812 del matches[rev]
2809 2813 del revfiles[rev]
2810 2814
2811 2815 return not found
2812 2816
2813 2817 @command('heads',
2814 2818 [('r', 'rev', '',
2815 2819 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2816 2820 ('t', 'topo', False, _('show topological heads only')),
2817 2821 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2818 2822 ('c', 'closed', False, _('show normal and closed branch heads')),
2819 2823 ] + templateopts,
2820 2824 _('[-ac] [-r STARTREV] [REV]...'))
2821 2825 def heads(ui, repo, *branchrevs, **opts):
2822 2826 """show current repository heads or show branch heads
2823 2827
2824 2828 With no arguments, show all repository branch heads.
2825 2829
2826 2830 Repository "heads" are changesets with no child changesets. They are
2827 2831 where development generally takes place and are the usual targets
2828 2832 for update and merge operations. Branch heads are changesets that have
2829 2833 no child changeset on the same branch.
2830 2834
2831 2835 If one or more REVs are given, only branch heads on the branches
2832 2836 associated with the specified changesets are shown. This means
2833 2837 that you can use :hg:`heads foo` to see the heads on a branch
2834 2838 named ``foo``.
2835 2839
2836 2840 If -c/--closed is specified, also show branch heads marked closed
2837 2841 (see :hg:`commit --close-branch`).
2838 2842
2839 2843 If STARTREV is specified, only those heads that are descendants of
2840 2844 STARTREV will be displayed.
2841 2845
2842 2846 If -t/--topo is specified, named branch mechanics will be ignored and only
2843 2847 changesets without children will be shown.
2844 2848
2845 2849 Returns 0 if matching heads are found, 1 if not.
2846 2850 """
2847 2851
2848 2852 start = None
2849 2853 if 'rev' in opts:
2850 2854 start = scmutil.revsingle(repo, opts['rev'], None).node()
2851 2855
2852 2856 if opts.get('topo'):
2853 2857 heads = [repo[h] for h in repo.heads(start)]
2854 2858 else:
2855 2859 heads = []
2856 2860 for branch in repo.branchmap():
2857 2861 heads += repo.branchheads(branch, start, opts.get('closed'))
2858 2862 heads = [repo[h] for h in heads]
2859 2863
2860 2864 if branchrevs:
2861 2865 branches = set(repo[br].branch() for br in branchrevs)
2862 2866 heads = [h for h in heads if h.branch() in branches]
2863 2867
2864 2868 if opts.get('active') and branchrevs:
2865 2869 dagheads = repo.heads(start)
2866 2870 heads = [h for h in heads if h.node() in dagheads]
2867 2871
2868 2872 if branchrevs:
2869 2873 haveheads = set(h.branch() for h in heads)
2870 2874 if branches - haveheads:
2871 2875 headless = ', '.join(b for b in branches - haveheads)
2872 2876 msg = _('no open branch heads found on branches %s')
2873 2877 if opts.get('rev'):
2874 2878 msg += _(' (started at %s)' % opts['rev'])
2875 2879 ui.warn((msg + '\n') % headless)
2876 2880
2877 2881 if not heads:
2878 2882 return 1
2879 2883
2880 2884 heads = sorted(heads, key=lambda x: -x.rev())
2881 2885 displayer = cmdutil.show_changeset(ui, repo, opts)
2882 2886 for ctx in heads:
2883 2887 displayer.show(ctx)
2884 2888 displayer.close()
2885 2889
2886 2890 @command('help',
2887 2891 [('e', 'extension', None, _('show only help for extensions')),
2888 2892 ('c', 'command', None, _('show only help for commands'))],
2889 2893 _('[-ec] [TOPIC]'))
2890 2894 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2891 2895 """show help for a given topic or a help overview
2892 2896
2893 2897 With no arguments, print a list of commands with short help messages.
2894 2898
2895 2899 Given a topic, extension, or command name, print help for that
2896 2900 topic.
2897 2901
2898 2902 Returns 0 if successful.
2899 2903 """
2900 2904
2901 2905 textwidth = min(ui.termwidth(), 80) - 2
2902 2906
2903 2907 def optrst(options):
2904 2908 data = []
2905 2909 multioccur = False
2906 2910 for option in options:
2907 2911 if len(option) == 5:
2908 2912 shortopt, longopt, default, desc, optlabel = option
2909 2913 else:
2910 2914 shortopt, longopt, default, desc = option
2911 2915 optlabel = _("VALUE") # default label
2912 2916
2913 2917 if _("DEPRECATED") in desc and not ui.verbose:
2914 2918 continue
2915 2919
2916 2920 so = ''
2917 2921 if shortopt:
2918 2922 so = '-' + shortopt
2919 2923 lo = '--' + longopt
2920 2924 if default:
2921 2925 desc += _(" (default: %s)") % default
2922 2926
2923 2927 if isinstance(default, list):
2924 2928 lo += " %s [+]" % optlabel
2925 2929 multioccur = True
2926 2930 elif (default is not None) and not isinstance(default, bool):
2927 2931 lo += " %s" % optlabel
2928 2932
2929 2933 data.append((so, lo, desc))
2930 2934
2931 2935 rst = minirst.maketable(data, 1)
2932 2936
2933 2937 if multioccur:
2934 2938 rst += _("\n[+] marked option can be specified multiple times\n")
2935 2939
2936 2940 return rst
2937 2941
2938 2942 # list all option lists
2939 2943 def opttext(optlist, width):
2940 2944 rst = ''
2941 2945 if not optlist:
2942 2946 return ''
2943 2947
2944 2948 for title, options in optlist:
2945 2949 rst += '\n%s\n' % title
2946 2950 if options:
2947 2951 rst += "\n"
2948 2952 rst += optrst(options)
2949 2953 rst += '\n'
2950 2954
2951 2955 return '\n' + minirst.format(rst, width)
2952 2956
2953 2957 def addglobalopts(optlist, aliases):
2954 2958 if ui.quiet:
2955 2959 return []
2956 2960
2957 2961 if ui.verbose:
2958 2962 optlist.append((_("global options:"), globalopts))
2959 2963 if name == 'shortlist':
2960 2964 optlist.append((_('use "hg help" for the full list '
2961 2965 'of commands'), ()))
2962 2966 else:
2963 2967 if name == 'shortlist':
2964 2968 msg = _('use "hg help" for the full list of commands '
2965 2969 'or "hg -v" for details')
2966 2970 elif name and not full:
2967 2971 msg = _('use "hg help %s" to show the full help text' % name)
2968 2972 elif aliases:
2969 2973 msg = _('use "hg -v help%s" to show builtin aliases and '
2970 2974 'global options') % (name and " " + name or "")
2971 2975 else:
2972 2976 msg = _('use "hg -v help %s" to show more info') % name
2973 2977 optlist.append((msg, ()))
2974 2978
2975 2979 def helpcmd(name):
2976 2980 try:
2977 2981 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2978 2982 except error.AmbiguousCommand, inst:
2979 2983 # py3k fix: except vars can't be used outside the scope of the
2980 2984 # except block, nor can be used inside a lambda. python issue4617
2981 2985 prefix = inst.args[0]
2982 2986 select = lambda c: c.lstrip('^').startswith(prefix)
2983 2987 helplist(select)
2984 2988 return
2985 2989
2986 2990 # check if it's an invalid alias and display its error if it is
2987 2991 if getattr(entry[0], 'badalias', False):
2988 2992 if not unknowncmd:
2989 2993 entry[0](ui)
2990 2994 return
2991 2995
2992 2996 rst = ""
2993 2997
2994 2998 # synopsis
2995 2999 if len(entry) > 2:
2996 3000 if entry[2].startswith('hg'):
2997 3001 rst += "%s\n" % entry[2]
2998 3002 else:
2999 3003 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3000 3004 else:
3001 3005 rst += 'hg %s\n' % aliases[0]
3002 3006
3003 3007 # aliases
3004 3008 if full and not ui.quiet and len(aliases) > 1:
3005 3009 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3006 3010
3007 3011 # description
3008 3012 doc = gettext(entry[0].__doc__)
3009 3013 if not doc:
3010 3014 doc = _("(no help text available)")
3011 3015 if util.safehasattr(entry[0], 'definition'): # aliased command
3012 3016 if entry[0].definition.startswith('!'): # shell alias
3013 3017 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3014 3018 else:
3015 3019 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3016 3020 if ui.quiet or not full:
3017 3021 doc = doc.splitlines()[0]
3018 3022 rst += "\n" + doc + "\n"
3019 3023
3020 3024 # check if this command shadows a non-trivial (multi-line)
3021 3025 # extension help text
3022 3026 try:
3023 3027 mod = extensions.find(name)
3024 3028 doc = gettext(mod.__doc__) or ''
3025 3029 if '\n' in doc.strip():
3026 3030 msg = _('use "hg help -e %s" to show help for '
3027 3031 'the %s extension') % (name, name)
3028 3032 rst += '\n%s\n' % msg
3029 3033 except KeyError:
3030 3034 pass
3031 3035
3032 3036 # options
3033 3037 if not ui.quiet and entry[1]:
3034 3038 rst += '\noptions:\n\n'
3035 3039 rst += optrst(entry[1])
3036 3040
3037 3041 if ui.verbose:
3038 3042 rst += '\nglobal options:\n\n'
3039 3043 rst += optrst(globalopts)
3040 3044
3041 3045 keep = ui.verbose and ['verbose'] or []
3042 3046 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3043 3047 ui.write(formatted)
3044 3048
3045 3049 if not ui.verbose:
3046 3050 if not full:
3047 3051 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3048 3052 % name)
3049 3053 elif not ui.quiet:
3050 3054 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3051 3055
3052 3056
3053 3057 def helplist(select=None):
3054 3058 # list of commands
3055 3059 if name == "shortlist":
3056 3060 header = _('basic commands:\n\n')
3057 3061 else:
3058 3062 header = _('list of commands:\n\n')
3059 3063
3060 3064 h = {}
3061 3065 cmds = {}
3062 3066 for c, e in table.iteritems():
3063 3067 f = c.split("|", 1)[0]
3064 3068 if select and not select(f):
3065 3069 continue
3066 3070 if (not select and name != 'shortlist' and
3067 3071 e[0].__module__ != __name__):
3068 3072 continue
3069 3073 if name == "shortlist" and not f.startswith("^"):
3070 3074 continue
3071 3075 f = f.lstrip("^")
3072 3076 if not ui.debugflag and f.startswith("debug"):
3073 3077 continue
3074 3078 doc = e[0].__doc__
3075 3079 if doc and 'DEPRECATED' in doc and not ui.verbose:
3076 3080 continue
3077 3081 doc = gettext(doc)
3078 3082 if not doc:
3079 3083 doc = _("(no help text available)")
3080 3084 h[f] = doc.splitlines()[0].rstrip()
3081 3085 cmds[f] = c.lstrip("^")
3082 3086
3083 3087 if not h:
3084 3088 ui.status(_('no commands defined\n'))
3085 3089 return
3086 3090
3087 3091 ui.status(header)
3088 3092 fns = sorted(h)
3089 3093 m = max(map(len, fns))
3090 3094 for f in fns:
3091 3095 if ui.verbose:
3092 3096 commands = cmds[f].replace("|",", ")
3093 3097 ui.write(" %s:\n %s\n"%(commands, h[f]))
3094 3098 else:
3095 3099 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3096 3100 initindent=' %-*s ' % (m, f),
3097 3101 hangindent=' ' * (m + 4))))
3098 3102
3099 3103 if not name:
3100 3104 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3101 3105 if text:
3102 3106 ui.write("\n%s" % minirst.format(text, textwidth))
3103 3107
3104 3108 ui.write(_("\nadditional help topics:\n\n"))
3105 3109 topics = []
3106 3110 for names, header, doc in help.helptable:
3107 3111 topics.append((sorted(names, key=len, reverse=True)[0], header))
3108 3112 topics_len = max([len(s[0]) for s in topics])
3109 3113 for t, desc in topics:
3110 3114 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3111 3115
3112 3116 optlist = []
3113 3117 addglobalopts(optlist, True)
3114 3118 ui.write(opttext(optlist, textwidth))
3115 3119
3116 3120 def helptopic(name):
3117 3121 for names, header, doc in help.helptable:
3118 3122 if name in names:
3119 3123 break
3120 3124 else:
3121 3125 raise error.UnknownCommand(name)
3122 3126
3123 3127 # description
3124 3128 if not doc:
3125 3129 doc = _("(no help text available)")
3126 3130 if util.safehasattr(doc, '__call__'):
3127 3131 doc = doc()
3128 3132
3129 3133 ui.write("%s\n\n" % header)
3130 3134 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3131 3135 try:
3132 3136 cmdutil.findcmd(name, table)
3133 3137 ui.write(_('\nuse "hg help -c %s" to see help for '
3134 3138 'the %s command\n') % (name, name))
3135 3139 except error.UnknownCommand:
3136 3140 pass
3137 3141
3138 3142 def helpext(name):
3139 3143 try:
3140 3144 mod = extensions.find(name)
3141 3145 doc = gettext(mod.__doc__) or _('no help text available')
3142 3146 except KeyError:
3143 3147 mod = None
3144 3148 doc = extensions.disabledext(name)
3145 3149 if not doc:
3146 3150 raise error.UnknownCommand(name)
3147 3151
3148 3152 if '\n' not in doc:
3149 3153 head, tail = doc, ""
3150 3154 else:
3151 3155 head, tail = doc.split('\n', 1)
3152 3156 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3153 3157 if tail:
3154 3158 ui.write(minirst.format(tail, textwidth))
3155 3159 ui.status('\n')
3156 3160
3157 3161 if mod:
3158 3162 try:
3159 3163 ct = mod.cmdtable
3160 3164 except AttributeError:
3161 3165 ct = {}
3162 3166 modcmds = set([c.split('|', 1)[0] for c in ct])
3163 3167 helplist(modcmds.__contains__)
3164 3168 else:
3165 3169 ui.write(_('use "hg help extensions" for information on enabling '
3166 3170 'extensions\n'))
3167 3171
3168 3172 def helpextcmd(name):
3169 3173 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3170 3174 doc = gettext(mod.__doc__).splitlines()[0]
3171 3175
3172 3176 msg = help.listexts(_("'%s' is provided by the following "
3173 3177 "extension:") % cmd, {ext: doc}, indent=4)
3174 3178 ui.write(minirst.format(msg, textwidth))
3175 3179 ui.write('\n')
3176 3180 ui.write(_('use "hg help extensions" for information on enabling '
3177 3181 'extensions\n'))
3178 3182
3179 3183 if name and name != 'shortlist':
3180 3184 i = None
3181 3185 if unknowncmd:
3182 3186 queries = (helpextcmd,)
3183 3187 elif opts.get('extension'):
3184 3188 queries = (helpext,)
3185 3189 elif opts.get('command'):
3186 3190 queries = (helpcmd,)
3187 3191 else:
3188 3192 queries = (helptopic, helpcmd, helpext, helpextcmd)
3189 3193 for f in queries:
3190 3194 try:
3191 3195 f(name)
3192 3196 i = None
3193 3197 break
3194 3198 except error.UnknownCommand, inst:
3195 3199 i = inst
3196 3200 if i:
3197 3201 raise i
3198 3202 else:
3199 3203 # program name
3200 3204 ui.status(_("Mercurial Distributed SCM\n"))
3201 3205 ui.status('\n')
3202 3206 helplist()
3203 3207
3204 3208
3205 3209 @command('identify|id',
3206 3210 [('r', 'rev', '',
3207 3211 _('identify the specified revision'), _('REV')),
3208 3212 ('n', 'num', None, _('show local revision number')),
3209 3213 ('i', 'id', None, _('show global revision id')),
3210 3214 ('b', 'branch', None, _('show branch')),
3211 3215 ('t', 'tags', None, _('show tags')),
3212 3216 ('B', 'bookmarks', None, _('show bookmarks'))],
3213 3217 _('[-nibtB] [-r REV] [SOURCE]'))
3214 3218 def identify(ui, repo, source=None, rev=None,
3215 3219 num=None, id=None, branch=None, tags=None, bookmarks=None):
3216 3220 """identify the working copy or specified revision
3217 3221
3218 3222 Print a summary identifying the repository state at REV using one or
3219 3223 two parent hash identifiers, followed by a "+" if the working
3220 3224 directory has uncommitted changes, the branch name (if not default),
3221 3225 a list of tags, and a list of bookmarks.
3222 3226
3223 3227 When REV is not given, print a summary of the current state of the
3224 3228 repository.
3225 3229
3226 3230 Specifying a path to a repository root or Mercurial bundle will
3227 3231 cause lookup to operate on that repository/bundle.
3228 3232
3229 3233 .. container:: verbose
3230 3234
3231 3235 Examples:
3232 3236
3233 3237 - generate a build identifier for the working directory::
3234 3238
3235 3239 hg id --id > build-id.dat
3236 3240
3237 3241 - find the revision corresponding to a tag::
3238 3242
3239 3243 hg id -n -r 1.3
3240 3244
3241 3245 - check the most recent revision of a remote repository::
3242 3246
3243 3247 hg id -r tip http://selenic.com/hg/
3244 3248
3245 3249 Returns 0 if successful.
3246 3250 """
3247 3251
3248 3252 if not repo and not source:
3249 3253 raise util.Abort(_("there is no Mercurial repository here "
3250 3254 "(.hg not found)"))
3251 3255
3252 3256 hexfunc = ui.debugflag and hex or short
3253 3257 default = not (num or id or branch or tags or bookmarks)
3254 3258 output = []
3255 3259 revs = []
3256 3260
3257 3261 if source:
3258 3262 source, branches = hg.parseurl(ui.expandpath(source))
3259 3263 repo = hg.peer(ui, {}, source)
3260 3264 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3261 3265
3262 3266 if not repo.local():
3263 3267 if num or branch or tags:
3264 3268 raise util.Abort(
3265 3269 _("can't query remote revision number, branch, or tags"))
3266 3270 if not rev and revs:
3267 3271 rev = revs[0]
3268 3272 if not rev:
3269 3273 rev = "tip"
3270 3274
3271 3275 remoterev = repo.lookup(rev)
3272 3276 if default or id:
3273 3277 output = [hexfunc(remoterev)]
3274 3278
3275 3279 def getbms():
3276 3280 bms = []
3277 3281
3278 3282 if 'bookmarks' in repo.listkeys('namespaces'):
3279 3283 hexremoterev = hex(remoterev)
3280 3284 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3281 3285 if bmr == hexremoterev]
3282 3286
3283 3287 return bms
3284 3288
3285 3289 if bookmarks:
3286 3290 output.extend(getbms())
3287 3291 elif default and not ui.quiet:
3288 3292 # multiple bookmarks for a single parent separated by '/'
3289 3293 bm = '/'.join(getbms())
3290 3294 if bm:
3291 3295 output.append(bm)
3292 3296 else:
3293 3297 if not rev:
3294 3298 ctx = repo[None]
3295 3299 parents = ctx.parents()
3296 3300 changed = ""
3297 3301 if default or id or num:
3298 3302 changed = util.any(repo.status()) and "+" or ""
3299 3303 if default or id:
3300 3304 output = ["%s%s" %
3301 3305 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3302 3306 if num:
3303 3307 output.append("%s%s" %
3304 3308 ('+'.join([str(p.rev()) for p in parents]), changed))
3305 3309 else:
3306 3310 ctx = scmutil.revsingle(repo, rev)
3307 3311 if default or id:
3308 3312 output = [hexfunc(ctx.node())]
3309 3313 if num:
3310 3314 output.append(str(ctx.rev()))
3311 3315
3312 3316 if default and not ui.quiet:
3313 3317 b = ctx.branch()
3314 3318 if b != 'default':
3315 3319 output.append("(%s)" % b)
3316 3320
3317 3321 # multiple tags for a single parent separated by '/'
3318 3322 t = '/'.join(ctx.tags())
3319 3323 if t:
3320 3324 output.append(t)
3321 3325
3322 3326 # multiple bookmarks for a single parent separated by '/'
3323 3327 bm = '/'.join(ctx.bookmarks())
3324 3328 if bm:
3325 3329 output.append(bm)
3326 3330 else:
3327 3331 if branch:
3328 3332 output.append(ctx.branch())
3329 3333
3330 3334 if tags:
3331 3335 output.extend(ctx.tags())
3332 3336
3333 3337 if bookmarks:
3334 3338 output.extend(ctx.bookmarks())
3335 3339
3336 3340 ui.write("%s\n" % ' '.join(output))
3337 3341
3338 3342 @command('import|patch',
3339 3343 [('p', 'strip', 1,
3340 3344 _('directory strip option for patch. This has the same '
3341 3345 'meaning as the corresponding patch option'), _('NUM')),
3342 3346 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3343 3347 ('e', 'edit', False, _('invoke editor on commit messages')),
3344 3348 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3345 3349 ('', 'no-commit', None,
3346 3350 _("don't commit, just update the working directory")),
3347 3351 ('', 'bypass', None,
3348 3352 _("apply patch without touching the working directory")),
3349 3353 ('', 'exact', None,
3350 3354 _('apply patch to the nodes from which it was generated')),
3351 3355 ('', 'import-branch', None,
3352 3356 _('use any branch information in patch (implied by --exact)'))] +
3353 3357 commitopts + commitopts2 + similarityopts,
3354 3358 _('[OPTION]... PATCH...'))
3355 3359 def import_(ui, repo, patch1, *patches, **opts):
3356 3360 """import an ordered set of patches
3357 3361
3358 3362 Import a list of patches and commit them individually (unless
3359 3363 --no-commit is specified).
3360 3364
3361 3365 If there are outstanding changes in the working directory, import
3362 3366 will abort unless given the -f/--force flag.
3363 3367
3364 3368 You can import a patch straight from a mail message. Even patches
3365 3369 as attachments work (to use the body part, it must have type
3366 3370 text/plain or text/x-patch). From and Subject headers of email
3367 3371 message are used as default committer and commit message. All
3368 3372 text/plain body parts before first diff are added to commit
3369 3373 message.
3370 3374
3371 3375 If the imported patch was generated by :hg:`export`, user and
3372 3376 description from patch override values from message headers and
3373 3377 body. Values given on command line with -m/--message and -u/--user
3374 3378 override these.
3375 3379
3376 3380 If --exact is specified, import will set the working directory to
3377 3381 the parent of each patch before applying it, and will abort if the
3378 3382 resulting changeset has a different ID than the one recorded in
3379 3383 the patch. This may happen due to character set problems or other
3380 3384 deficiencies in the text patch format.
3381 3385
3382 3386 Use --bypass to apply and commit patches directly to the
3383 3387 repository, not touching the working directory. Without --exact,
3384 3388 patches will be applied on top of the working directory parent
3385 3389 revision.
3386 3390
3387 3391 With -s/--similarity, hg will attempt to discover renames and
3388 3392 copies in the patch in the same way as 'addremove'.
3389 3393
3390 3394 To read a patch from standard input, use "-" as the patch name. If
3391 3395 a URL is specified, the patch will be downloaded from it.
3392 3396 See :hg:`help dates` for a list of formats valid for -d/--date.
3393 3397
3394 3398 .. container:: verbose
3395 3399
3396 3400 Examples:
3397 3401
3398 3402 - import a traditional patch from a website and detect renames::
3399 3403
3400 3404 hg import -s 80 http://example.com/bugfix.patch
3401 3405
3402 3406 - import a changeset from an hgweb server::
3403 3407
3404 3408 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3405 3409
3406 3410 - import all the patches in an Unix-style mbox::
3407 3411
3408 3412 hg import incoming-patches.mbox
3409 3413
3410 3414 - attempt to exactly restore an exported changeset (not always
3411 3415 possible)::
3412 3416
3413 3417 hg import --exact proposed-fix.patch
3414 3418
3415 3419 Returns 0 on success.
3416 3420 """
3417 3421 patches = (patch1,) + patches
3418 3422
3419 3423 date = opts.get('date')
3420 3424 if date:
3421 3425 opts['date'] = util.parsedate(date)
3422 3426
3423 3427 editor = cmdutil.commiteditor
3424 3428 if opts.get('edit'):
3425 3429 editor = cmdutil.commitforceeditor
3426 3430
3427 3431 update = not opts.get('bypass')
3428 3432 if not update and opts.get('no_commit'):
3429 3433 raise util.Abort(_('cannot use --no-commit with --bypass'))
3430 3434 try:
3431 3435 sim = float(opts.get('similarity') or 0)
3432 3436 except ValueError:
3433 3437 raise util.Abort(_('similarity must be a number'))
3434 3438 if sim < 0 or sim > 100:
3435 3439 raise util.Abort(_('similarity must be between 0 and 100'))
3436 3440 if sim and not update:
3437 3441 raise util.Abort(_('cannot use --similarity with --bypass'))
3438 3442
3439 3443 if (opts.get('exact') or not opts.get('force')) and update:
3440 3444 cmdutil.bailifchanged(repo)
3441 3445
3442 3446 base = opts["base"]
3443 3447 strip = opts["strip"]
3444 3448 wlock = lock = tr = None
3445 3449 msgs = []
3446 3450
3447 3451 def checkexact(repo, n, nodeid):
3448 3452 if opts.get('exact') and hex(n) != nodeid:
3449 3453 repo.rollback()
3450 3454 raise util.Abort(_('patch is damaged or loses information'))
3451 3455
3452 3456 def tryone(ui, hunk, parents):
3453 3457 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3454 3458 patch.extract(ui, hunk)
3455 3459
3456 3460 if not tmpname:
3457 3461 return (None, None)
3458 3462 msg = _('applied to working directory')
3459 3463
3460 3464 try:
3461 3465 cmdline_message = cmdutil.logmessage(ui, opts)
3462 3466 if cmdline_message:
3463 3467 # pickup the cmdline msg
3464 3468 message = cmdline_message
3465 3469 elif message:
3466 3470 # pickup the patch msg
3467 3471 message = message.strip()
3468 3472 else:
3469 3473 # launch the editor
3470 3474 message = None
3471 3475 ui.debug('message:\n%s\n' % message)
3472 3476
3473 3477 if len(parents) == 1:
3474 3478 parents.append(repo[nullid])
3475 3479 if opts.get('exact'):
3476 3480 if not nodeid or not p1:
3477 3481 raise util.Abort(_('not a Mercurial patch'))
3478 3482 p1 = repo[p1]
3479 3483 p2 = repo[p2 or nullid]
3480 3484 elif p2:
3481 3485 try:
3482 3486 p1 = repo[p1]
3483 3487 p2 = repo[p2]
3484 3488 except error.RepoError:
3485 3489 p1, p2 = parents
3486 3490 else:
3487 3491 p1, p2 = parents
3488 3492
3489 3493 n = None
3490 3494 if update:
3491 3495 if opts.get('exact') and p1 != parents[0]:
3492 3496 hg.clean(repo, p1.node())
3493 3497 if p1 != parents[0] and p2 != parents[1]:
3494 3498 repo.dirstate.setparents(p1.node(), p2.node())
3495 3499
3496 3500 if opts.get('exact') or opts.get('import_branch'):
3497 3501 repo.dirstate.setbranch(branch or 'default')
3498 3502
3499 3503 files = set()
3500 3504 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3501 3505 eolmode=None, similarity=sim / 100.0)
3502 3506 files = list(files)
3503 3507 if opts.get('no_commit'):
3504 3508 if message:
3505 3509 msgs.append(message)
3506 3510 else:
3507 3511 if opts.get('exact'):
3508 3512 m = None
3509 3513 else:
3510 3514 m = scmutil.matchfiles(repo, files or [])
3511 3515 n = repo.commit(message, opts.get('user') or user,
3512 3516 opts.get('date') or date, match=m,
3513 3517 editor=editor)
3514 3518 checkexact(repo, n, nodeid)
3515 3519 else:
3516 3520 if opts.get('exact') or opts.get('import_branch'):
3517 3521 branch = branch or 'default'
3518 3522 else:
3519 3523 branch = p1.branch()
3520 3524 store = patch.filestore()
3521 3525 try:
3522 3526 files = set()
3523 3527 try:
3524 3528 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3525 3529 files, eolmode=None)
3526 3530 except patch.PatchError, e:
3527 3531 raise util.Abort(str(e))
3528 3532 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3529 3533 message,
3530 3534 opts.get('user') or user,
3531 3535 opts.get('date') or date,
3532 3536 branch, files, store,
3533 3537 editor=cmdutil.commiteditor)
3534 3538 repo.savecommitmessage(memctx.description())
3535 3539 n = memctx.commit()
3536 3540 checkexact(repo, n, nodeid)
3537 3541 finally:
3538 3542 store.close()
3539 3543 if n:
3540 3544 # i18n: refers to a short changeset id
3541 3545 msg = _('created %s') % short(n)
3542 3546 return (msg, n)
3543 3547 finally:
3544 3548 os.unlink(tmpname)
3545 3549
3546 3550 try:
3547 3551 try:
3548 3552 wlock = repo.wlock()
3549 3553 lock = repo.lock()
3550 3554 tr = repo.transaction('import')
3551 3555 parents = repo.parents()
3552 3556 for patchurl in patches:
3553 3557 if patchurl == '-':
3554 3558 ui.status(_('applying patch from stdin\n'))
3555 3559 patchfile = ui.fin
3556 3560 patchurl = 'stdin' # for error message
3557 3561 else:
3558 3562 patchurl = os.path.join(base, patchurl)
3559 3563 ui.status(_('applying %s\n') % patchurl)
3560 3564 patchfile = url.open(ui, patchurl)
3561 3565
3562 3566 haspatch = False
3563 3567 for hunk in patch.split(patchfile):
3564 3568 (msg, node) = tryone(ui, hunk, parents)
3565 3569 if msg:
3566 3570 haspatch = True
3567 3571 ui.note(msg + '\n')
3568 3572 if update or opts.get('exact'):
3569 3573 parents = repo.parents()
3570 3574 else:
3571 3575 parents = [repo[node]]
3572 3576
3573 3577 if not haspatch:
3574 3578 raise util.Abort(_('%s: no diffs found') % patchurl)
3575 3579
3576 3580 tr.close()
3577 3581 if msgs:
3578 3582 repo.savecommitmessage('\n* * *\n'.join(msgs))
3579 3583 except:
3580 3584 # wlock.release() indirectly calls dirstate.write(): since
3581 3585 # we're crashing, we do not want to change the working dir
3582 3586 # parent after all, so make sure it writes nothing
3583 3587 repo.dirstate.invalidate()
3584 3588 raise
3585 3589 finally:
3586 3590 if tr:
3587 3591 tr.release()
3588 3592 release(lock, wlock)
3589 3593
3590 3594 @command('incoming|in',
3591 3595 [('f', 'force', None,
3592 3596 _('run even if remote repository is unrelated')),
3593 3597 ('n', 'newest-first', None, _('show newest record first')),
3594 3598 ('', 'bundle', '',
3595 3599 _('file to store the bundles into'), _('FILE')),
3596 3600 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3597 3601 ('B', 'bookmarks', False, _("compare bookmarks")),
3598 3602 ('b', 'branch', [],
3599 3603 _('a specific branch you would like to pull'), _('BRANCH')),
3600 3604 ] + logopts + remoteopts + subrepoopts,
3601 3605 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3602 3606 def incoming(ui, repo, source="default", **opts):
3603 3607 """show new changesets found in source
3604 3608
3605 3609 Show new changesets found in the specified path/URL or the default
3606 3610 pull location. These are the changesets that would have been pulled
3607 3611 if a pull at the time you issued this command.
3608 3612
3609 3613 For remote repository, using --bundle avoids downloading the
3610 3614 changesets twice if the incoming is followed by a pull.
3611 3615
3612 3616 See pull for valid source format details.
3613 3617
3614 3618 Returns 0 if there are incoming changes, 1 otherwise.
3615 3619 """
3616 3620 if opts.get('bundle') and opts.get('subrepos'):
3617 3621 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3618 3622
3619 3623 if opts.get('bookmarks'):
3620 3624 source, branches = hg.parseurl(ui.expandpath(source),
3621 3625 opts.get('branch'))
3622 3626 other = hg.peer(repo, opts, source)
3623 3627 if 'bookmarks' not in other.listkeys('namespaces'):
3624 3628 ui.warn(_("remote doesn't support bookmarks\n"))
3625 3629 return 0
3626 3630 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3627 3631 return bookmarks.diff(ui, repo, other)
3628 3632
3629 3633 repo._subtoppath = ui.expandpath(source)
3630 3634 try:
3631 3635 return hg.incoming(ui, repo, source, opts)
3632 3636 finally:
3633 3637 del repo._subtoppath
3634 3638
3635 3639
3636 3640 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3637 3641 def init(ui, dest=".", **opts):
3638 3642 """create a new repository in the given directory
3639 3643
3640 3644 Initialize a new repository in the given directory. If the given
3641 3645 directory does not exist, it will be created.
3642 3646
3643 3647 If no directory is given, the current directory is used.
3644 3648
3645 3649 It is possible to specify an ``ssh://`` URL as the destination.
3646 3650 See :hg:`help urls` for more information.
3647 3651
3648 3652 Returns 0 on success.
3649 3653 """
3650 3654 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3651 3655
3652 3656 @command('locate',
3653 3657 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3654 3658 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3655 3659 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3656 3660 ] + walkopts,
3657 3661 _('[OPTION]... [PATTERN]...'))
3658 3662 def locate(ui, repo, *pats, **opts):
3659 3663 """locate files matching specific patterns
3660 3664
3661 3665 Print files under Mercurial control in the working directory whose
3662 3666 names match the given patterns.
3663 3667
3664 3668 By default, this command searches all directories in the working
3665 3669 directory. To search just the current directory and its
3666 3670 subdirectories, use "--include .".
3667 3671
3668 3672 If no patterns are given to match, this command prints the names
3669 3673 of all files under Mercurial control in the working directory.
3670 3674
3671 3675 If you want to feed the output of this command into the "xargs"
3672 3676 command, use the -0 option to both this command and "xargs". This
3673 3677 will avoid the problem of "xargs" treating single filenames that
3674 3678 contain whitespace as multiple filenames.
3675 3679
3676 3680 Returns 0 if a match is found, 1 otherwise.
3677 3681 """
3678 3682 end = opts.get('print0') and '\0' or '\n'
3679 3683 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3680 3684
3681 3685 ret = 1
3682 3686 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3683 3687 m.bad = lambda x, y: False
3684 3688 for abs in repo[rev].walk(m):
3685 3689 if not rev and abs not in repo.dirstate:
3686 3690 continue
3687 3691 if opts.get('fullpath'):
3688 3692 ui.write(repo.wjoin(abs), end)
3689 3693 else:
3690 3694 ui.write(((pats and m.rel(abs)) or abs), end)
3691 3695 ret = 0
3692 3696
3693 3697 return ret
3694 3698
3695 3699 @command('^log|history',
3696 3700 [('f', 'follow', None,
3697 3701 _('follow changeset history, or file history across copies and renames')),
3698 3702 ('', 'follow-first', None,
3699 3703 _('only follow the first parent of merge changesets')),
3700 3704 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3701 3705 ('C', 'copies', None, _('show copied files')),
3702 3706 ('k', 'keyword', [],
3703 3707 _('do case-insensitive search for a given text'), _('TEXT')),
3704 3708 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3705 3709 ('', 'removed', None, _('include revisions where files were removed')),
3706 3710 ('m', 'only-merges', None, _('show only merges')),
3707 3711 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3708 3712 ('', 'only-branch', [],
3709 3713 _('show only changesets within the given named branch (DEPRECATED)'),
3710 3714 _('BRANCH')),
3711 3715 ('b', 'branch', [],
3712 3716 _('show changesets within the given named branch'), _('BRANCH')),
3713 3717 ('P', 'prune', [],
3714 3718 _('do not display revision or any of its ancestors'), _('REV')),
3715 3719 ('', 'hidden', False, _('show hidden changesets')),
3716 3720 ] + logopts + walkopts,
3717 3721 _('[OPTION]... [FILE]'))
3718 3722 def log(ui, repo, *pats, **opts):
3719 3723 """show revision history of entire repository or files
3720 3724
3721 3725 Print the revision history of the specified files or the entire
3722 3726 project.
3723 3727
3724 3728 If no revision range is specified, the default is ``tip:0`` unless
3725 3729 --follow is set, in which case the working directory parent is
3726 3730 used as the starting revision.
3727 3731
3728 3732 File history is shown without following rename or copy history of
3729 3733 files. Use -f/--follow with a filename to follow history across
3730 3734 renames and copies. --follow without a filename will only show
3731 3735 ancestors or descendants of the starting revision.
3732 3736
3733 3737 By default this command prints revision number and changeset id,
3734 3738 tags, non-trivial parents, user, date and time, and a summary for
3735 3739 each commit. When the -v/--verbose switch is used, the list of
3736 3740 changed files and full commit message are shown.
3737 3741
3738 3742 .. note::
3739 3743 log -p/--patch may generate unexpected diff output for merge
3740 3744 changesets, as it will only compare the merge changeset against
3741 3745 its first parent. Also, only files different from BOTH parents
3742 3746 will appear in files:.
3743 3747
3744 3748 .. note::
3745 3749 for performance reasons, log FILE may omit duplicate changes
3746 3750 made on branches and will not show deletions. To see all
3747 3751 changes including duplicates and deletions, use the --removed
3748 3752 switch.
3749 3753
3750 3754 .. container:: verbose
3751 3755
3752 3756 Some examples:
3753 3757
3754 3758 - changesets with full descriptions and file lists::
3755 3759
3756 3760 hg log -v
3757 3761
3758 3762 - changesets ancestral to the working directory::
3759 3763
3760 3764 hg log -f
3761 3765
3762 3766 - last 10 commits on the current branch::
3763 3767
3764 3768 hg log -l 10 -b .
3765 3769
3766 3770 - changesets showing all modifications of a file, including removals::
3767 3771
3768 3772 hg log --removed file.c
3769 3773
3770 3774 - all changesets that touch a directory, with diffs, excluding merges::
3771 3775
3772 3776 hg log -Mp lib/
3773 3777
3774 3778 - all revision numbers that match a keyword::
3775 3779
3776 3780 hg log -k bug --template "{rev}\\n"
3777 3781
3778 3782 - check if a given changeset is included is a tagged release::
3779 3783
3780 3784 hg log -r "a21ccf and ancestor(1.9)"
3781 3785
3782 3786 - find all changesets by some user in a date range::
3783 3787
3784 3788 hg log -k alice -d "may 2008 to jul 2008"
3785 3789
3786 3790 - summary of all changesets after the last tag::
3787 3791
3788 3792 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3789 3793
3790 3794 See :hg:`help dates` for a list of formats valid for -d/--date.
3791 3795
3792 3796 See :hg:`help revisions` and :hg:`help revsets` for more about
3793 3797 specifying revisions.
3794 3798
3795 3799 Returns 0 on success.
3796 3800 """
3797 3801
3798 3802 matchfn = scmutil.match(repo[None], pats, opts)
3799 3803 limit = cmdutil.loglimit(opts)
3800 3804 count = 0
3801 3805
3802 3806 endrev = None
3803 3807 if opts.get('copies') and opts.get('rev'):
3804 3808 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3805 3809
3806 3810 df = False
3807 3811 if opts["date"]:
3808 3812 df = util.matchdate(opts["date"])
3809 3813
3810 3814 branches = opts.get('branch', []) + opts.get('only_branch', [])
3811 3815 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3812 3816
3813 3817 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3814 3818 def prep(ctx, fns):
3815 3819 rev = ctx.rev()
3816 3820 parents = [p for p in repo.changelog.parentrevs(rev)
3817 3821 if p != nullrev]
3818 3822 if opts.get('no_merges') and len(parents) == 2:
3819 3823 return
3820 3824 if opts.get('only_merges') and len(parents) != 2:
3821 3825 return
3822 3826 if opts.get('branch') and ctx.branch() not in opts['branch']:
3823 3827 return
3824 3828 if not opts.get('hidden') and ctx.hidden():
3825 3829 return
3826 3830 if df and not df(ctx.date()[0]):
3827 3831 return
3828 3832 if opts['user'] and not [k for k in opts['user']
3829 3833 if k.lower() in ctx.user().lower()]:
3830 3834 return
3831 3835 if opts.get('keyword'):
3832 3836 for k in [kw.lower() for kw in opts['keyword']]:
3833 3837 if (k in ctx.user().lower() or
3834 3838 k in ctx.description().lower() or
3835 3839 k in " ".join(ctx.files()).lower()):
3836 3840 break
3837 3841 else:
3838 3842 return
3839 3843
3840 3844 copies = None
3841 3845 if opts.get('copies') and rev:
3842 3846 copies = []
3843 3847 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3844 3848 for fn in ctx.files():
3845 3849 rename = getrenamed(fn, rev)
3846 3850 if rename:
3847 3851 copies.append((fn, rename[0]))
3848 3852
3849 3853 revmatchfn = None
3850 3854 if opts.get('patch') or opts.get('stat'):
3851 3855 if opts.get('follow') or opts.get('follow_first'):
3852 3856 # note: this might be wrong when following through merges
3853 3857 revmatchfn = scmutil.match(repo[None], fns, default='path')
3854 3858 else:
3855 3859 revmatchfn = matchfn
3856 3860
3857 3861 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3858 3862
3859 3863 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3860 3864 if count == limit:
3861 3865 break
3862 3866 if displayer.flush(ctx.rev()):
3863 3867 count += 1
3864 3868 displayer.close()
3865 3869
3866 3870 @command('manifest',
3867 3871 [('r', 'rev', '', _('revision to display'), _('REV')),
3868 3872 ('', 'all', False, _("list files from all revisions"))],
3869 3873 _('[-r REV]'))
3870 3874 def manifest(ui, repo, node=None, rev=None, **opts):
3871 3875 """output the current or given revision of the project manifest
3872 3876
3873 3877 Print a list of version controlled files for the given revision.
3874 3878 If no revision is given, the first parent of the working directory
3875 3879 is used, or the null revision if no revision is checked out.
3876 3880
3877 3881 With -v, print file permissions, symlink and executable bits.
3878 3882 With --debug, print file revision hashes.
3879 3883
3880 3884 If option --all is specified, the list of all files from all revisions
3881 3885 is printed. This includes deleted and renamed files.
3882 3886
3883 3887 Returns 0 on success.
3884 3888 """
3885 3889 if opts.get('all'):
3886 3890 if rev or node:
3887 3891 raise util.Abort(_("can't specify a revision with --all"))
3888 3892
3889 3893 res = []
3890 3894 prefix = "data/"
3891 3895 suffix = ".i"
3892 3896 plen = len(prefix)
3893 3897 slen = len(suffix)
3894 3898 lock = repo.lock()
3895 3899 try:
3896 3900 for fn, b, size in repo.store.datafiles():
3897 3901 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3898 3902 res.append(fn[plen:-slen])
3899 3903 finally:
3900 3904 lock.release()
3901 3905 for f in sorted(res):
3902 3906 ui.write("%s\n" % f)
3903 3907 return
3904 3908
3905 3909 if rev and node:
3906 3910 raise util.Abort(_("please specify just one revision"))
3907 3911
3908 3912 if not node:
3909 3913 node = rev
3910 3914
3911 3915 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3912 3916 ctx = scmutil.revsingle(repo, node)
3913 3917 for f in ctx:
3914 3918 if ui.debugflag:
3915 3919 ui.write("%40s " % hex(ctx.manifest()[f]))
3916 3920 if ui.verbose:
3917 3921 ui.write(decor[ctx.flags(f)])
3918 3922 ui.write("%s\n" % f)
3919 3923
3920 3924 @command('^merge',
3921 3925 [('f', 'force', None, _('force a merge with outstanding changes')),
3922 3926 ('r', 'rev', '', _('revision to merge'), _('REV')),
3923 3927 ('P', 'preview', None,
3924 3928 _('review revisions to merge (no merge is performed)'))
3925 3929 ] + mergetoolopts,
3926 3930 _('[-P] [-f] [[-r] REV]'))
3927 3931 def merge(ui, repo, node=None, **opts):
3928 3932 """merge working directory with another revision
3929 3933
3930 3934 The current working directory is updated with all changes made in
3931 3935 the requested revision since the last common predecessor revision.
3932 3936
3933 3937 Files that changed between either parent are marked as changed for
3934 3938 the next commit and a commit must be performed before any further
3935 3939 updates to the repository are allowed. The next commit will have
3936 3940 two parents.
3937 3941
3938 3942 ``--tool`` can be used to specify the merge tool used for file
3939 3943 merges. It overrides the HGMERGE environment variable and your
3940 3944 configuration files. See :hg:`help merge-tools` for options.
3941 3945
3942 3946 If no revision is specified, the working directory's parent is a
3943 3947 head revision, and the current branch contains exactly one other
3944 3948 head, the other head is merged with by default. Otherwise, an
3945 3949 explicit revision with which to merge with must be provided.
3946 3950
3947 3951 :hg:`resolve` must be used to resolve unresolved files.
3948 3952
3949 3953 To undo an uncommitted merge, use :hg:`update --clean .` which
3950 3954 will check out a clean copy of the original merge parent, losing
3951 3955 all changes.
3952 3956
3953 3957 Returns 0 on success, 1 if there are unresolved files.
3954 3958 """
3955 3959
3956 3960 if opts.get('rev') and node:
3957 3961 raise util.Abort(_("please specify just one revision"))
3958 3962 if not node:
3959 3963 node = opts.get('rev')
3960 3964
3961 3965 if not node:
3962 3966 branch = repo[None].branch()
3963 3967 bheads = repo.branchheads(branch)
3964 3968 if len(bheads) > 2:
3965 3969 raise util.Abort(_("branch '%s' has %d heads - "
3966 3970 "please merge with an explicit rev")
3967 3971 % (branch, len(bheads)),
3968 3972 hint=_("run 'hg heads .' to see heads"))
3969 3973
3970 3974 parent = repo.dirstate.p1()
3971 3975 if len(bheads) == 1:
3972 3976 if len(repo.heads()) > 1:
3973 3977 raise util.Abort(_("branch '%s' has one head - "
3974 3978 "please merge with an explicit rev")
3975 3979 % branch,
3976 3980 hint=_("run 'hg heads' to see all heads"))
3977 3981 msg = _('there is nothing to merge')
3978 3982 if parent != repo.lookup(repo[None].branch()):
3979 3983 msg = _('%s - use "hg update" instead') % msg
3980 3984 raise util.Abort(msg)
3981 3985
3982 3986 if parent not in bheads:
3983 3987 raise util.Abort(_('working directory not at a head revision'),
3984 3988 hint=_("use 'hg update' or merge with an "
3985 3989 "explicit revision"))
3986 3990 node = parent == bheads[0] and bheads[-1] or bheads[0]
3987 3991 else:
3988 3992 node = scmutil.revsingle(repo, node).node()
3989 3993
3990 3994 if opts.get('preview'):
3991 3995 # find nodes that are ancestors of p2 but not of p1
3992 3996 p1 = repo.lookup('.')
3993 3997 p2 = repo.lookup(node)
3994 3998 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3995 3999
3996 4000 displayer = cmdutil.show_changeset(ui, repo, opts)
3997 4001 for node in nodes:
3998 4002 displayer.show(repo[node])
3999 4003 displayer.close()
4000 4004 return 0
4001 4005
4002 4006 try:
4003 4007 # ui.forcemerge is an internal variable, do not document
4004 4008 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4005 4009 return hg.merge(repo, node, force=opts.get('force'))
4006 4010 finally:
4007 4011 ui.setconfig('ui', 'forcemerge', '')
4008 4012
4009 4013 @command('outgoing|out',
4010 4014 [('f', 'force', None, _('run even when the destination is unrelated')),
4011 4015 ('r', 'rev', [],
4012 4016 _('a changeset intended to be included in the destination'), _('REV')),
4013 4017 ('n', 'newest-first', None, _('show newest record first')),
4014 4018 ('B', 'bookmarks', False, _('compare bookmarks')),
4015 4019 ('b', 'branch', [], _('a specific branch you would like to push'),
4016 4020 _('BRANCH')),
4017 4021 ] + logopts + remoteopts + subrepoopts,
4018 4022 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4019 4023 def outgoing(ui, repo, dest=None, **opts):
4020 4024 """show changesets not found in the destination
4021 4025
4022 4026 Show changesets not found in the specified destination repository
4023 4027 or the default push location. These are the changesets that would
4024 4028 be pushed if a push was requested.
4025 4029
4026 4030 See pull for details of valid destination formats.
4027 4031
4028 4032 Returns 0 if there are outgoing changes, 1 otherwise.
4029 4033 """
4030 4034
4031 4035 if opts.get('bookmarks'):
4032 4036 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4033 4037 dest, branches = hg.parseurl(dest, opts.get('branch'))
4034 4038 other = hg.peer(repo, opts, dest)
4035 4039 if 'bookmarks' not in other.listkeys('namespaces'):
4036 4040 ui.warn(_("remote doesn't support bookmarks\n"))
4037 4041 return 0
4038 4042 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4039 4043 return bookmarks.diff(ui, other, repo)
4040 4044
4041 4045 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4042 4046 try:
4043 4047 return hg.outgoing(ui, repo, dest, opts)
4044 4048 finally:
4045 4049 del repo._subtoppath
4046 4050
4047 4051 @command('parents',
4048 4052 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4049 4053 ] + templateopts,
4050 4054 _('[-r REV] [FILE]'))
4051 4055 def parents(ui, repo, file_=None, **opts):
4052 4056 """show the parents of the working directory or revision
4053 4057
4054 4058 Print the working directory's parent revisions. If a revision is
4055 4059 given via -r/--rev, the parent of that revision will be printed.
4056 4060 If a file argument is given, the revision in which the file was
4057 4061 last changed (before the working directory revision or the
4058 4062 argument to --rev if given) is printed.
4059 4063
4060 4064 Returns 0 on success.
4061 4065 """
4062 4066
4063 4067 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4064 4068
4065 4069 if file_:
4066 4070 m = scmutil.match(ctx, (file_,), opts)
4067 4071 if m.anypats() or len(m.files()) != 1:
4068 4072 raise util.Abort(_('can only specify an explicit filename'))
4069 4073 file_ = m.files()[0]
4070 4074 filenodes = []
4071 4075 for cp in ctx.parents():
4072 4076 if not cp:
4073 4077 continue
4074 4078 try:
4075 4079 filenodes.append(cp.filenode(file_))
4076 4080 except error.LookupError:
4077 4081 pass
4078 4082 if not filenodes:
4079 4083 raise util.Abort(_("'%s' not found in manifest!") % file_)
4080 4084 fl = repo.file(file_)
4081 4085 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4082 4086 else:
4083 4087 p = [cp.node() for cp in ctx.parents()]
4084 4088
4085 4089 displayer = cmdutil.show_changeset(ui, repo, opts)
4086 4090 for n in p:
4087 4091 if n != nullid:
4088 4092 displayer.show(repo[n])
4089 4093 displayer.close()
4090 4094
4091 4095 @command('paths', [], _('[NAME]'))
4092 4096 def paths(ui, repo, search=None):
4093 4097 """show aliases for remote repositories
4094 4098
4095 4099 Show definition of symbolic path name NAME. If no name is given,
4096 4100 show definition of all available names.
4097 4101
4098 4102 Option -q/--quiet suppresses all output when searching for NAME
4099 4103 and shows only the path names when listing all definitions.
4100 4104
4101 4105 Path names are defined in the [paths] section of your
4102 4106 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4103 4107 repository, ``.hg/hgrc`` is used, too.
4104 4108
4105 4109 The path names ``default`` and ``default-push`` have a special
4106 4110 meaning. When performing a push or pull operation, they are used
4107 4111 as fallbacks if no location is specified on the command-line.
4108 4112 When ``default-push`` is set, it will be used for push and
4109 4113 ``default`` will be used for pull; otherwise ``default`` is used
4110 4114 as the fallback for both. When cloning a repository, the clone
4111 4115 source is written as ``default`` in ``.hg/hgrc``. Note that
4112 4116 ``default`` and ``default-push`` apply to all inbound (e.g.
4113 4117 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4114 4118 :hg:`bundle`) operations.
4115 4119
4116 4120 See :hg:`help urls` for more information.
4117 4121
4118 4122 Returns 0 on success.
4119 4123 """
4120 4124 if search:
4121 4125 for name, path in ui.configitems("paths"):
4122 4126 if name == search:
4123 4127 ui.status("%s\n" % util.hidepassword(path))
4124 4128 return
4125 4129 if not ui.quiet:
4126 4130 ui.warn(_("not found!\n"))
4127 4131 return 1
4128 4132 else:
4129 4133 for name, path in ui.configitems("paths"):
4130 4134 if ui.quiet:
4131 4135 ui.write("%s\n" % name)
4132 4136 else:
4133 4137 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4134 4138
4135 4139 def postincoming(ui, repo, modheads, optupdate, checkout):
4136 4140 if modheads == 0:
4137 4141 return
4138 4142 if optupdate:
4139 4143 try:
4140 4144 return hg.update(repo, checkout)
4141 4145 except util.Abort, inst:
4142 4146 ui.warn(_("not updating: %s\n" % str(inst)))
4143 4147 return 0
4144 4148 if modheads > 1:
4145 4149 currentbranchheads = len(repo.branchheads())
4146 4150 if currentbranchheads == modheads:
4147 4151 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4148 4152 elif currentbranchheads > 1:
4149 4153 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4150 4154 else:
4151 4155 ui.status(_("(run 'hg heads' to see heads)\n"))
4152 4156 else:
4153 4157 ui.status(_("(run 'hg update' to get a working copy)\n"))
4154 4158
4155 4159 @command('^pull',
4156 4160 [('u', 'update', None,
4157 4161 _('update to new branch head if changesets were pulled')),
4158 4162 ('f', 'force', None, _('run even when remote repository is unrelated')),
4159 4163 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4160 4164 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4161 4165 ('b', 'branch', [], _('a specific branch you would like to pull'),
4162 4166 _('BRANCH')),
4163 4167 ] + remoteopts,
4164 4168 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4165 4169 def pull(ui, repo, source="default", **opts):
4166 4170 """pull changes from the specified source
4167 4171
4168 4172 Pull changes from a remote repository to a local one.
4169 4173
4170 4174 This finds all changes from the repository at the specified path
4171 4175 or URL and adds them to a local repository (the current one unless
4172 4176 -R is specified). By default, this does not update the copy of the
4173 4177 project in the working directory.
4174 4178
4175 4179 Use :hg:`incoming` if you want to see what would have been added
4176 4180 by a pull at the time you issued this command. If you then decide
4177 4181 to add those changes to the repository, you should use :hg:`pull
4178 4182 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4179 4183
4180 4184 If SOURCE is omitted, the 'default' path will be used.
4181 4185 See :hg:`help urls` for more information.
4182 4186
4183 4187 Returns 0 on success, 1 if an update had unresolved files.
4184 4188 """
4185 4189 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4186 4190 other = hg.peer(repo, opts, source)
4187 4191 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4188 4192 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4189 4193
4190 4194 if opts.get('bookmark'):
4191 4195 if not revs:
4192 4196 revs = []
4193 4197 rb = other.listkeys('bookmarks')
4194 4198 for b in opts['bookmark']:
4195 4199 if b not in rb:
4196 4200 raise util.Abort(_('remote bookmark %s not found!') % b)
4197 4201 revs.append(rb[b])
4198 4202
4199 4203 if revs:
4200 4204 try:
4201 4205 revs = [other.lookup(rev) for rev in revs]
4202 4206 except error.CapabilityError:
4203 4207 err = _("other repository doesn't support revision lookup, "
4204 4208 "so a rev cannot be specified.")
4205 4209 raise util.Abort(err)
4206 4210
4207 4211 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4208 4212 bookmarks.updatefromremote(ui, repo, other)
4209 4213 if checkout:
4210 4214 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4211 4215 repo._subtoppath = source
4212 4216 try:
4213 4217 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4214 4218
4215 4219 finally:
4216 4220 del repo._subtoppath
4217 4221
4218 4222 # update specified bookmarks
4219 4223 if opts.get('bookmark'):
4220 4224 for b in opts['bookmark']:
4221 4225 # explicit pull overrides local bookmark if any
4222 4226 ui.status(_("importing bookmark %s\n") % b)
4223 4227 repo._bookmarks[b] = repo[rb[b]].node()
4224 4228 bookmarks.write(repo)
4225 4229
4226 4230 return ret
4227 4231
4228 4232 @command('^push',
4229 4233 [('f', 'force', None, _('force push')),
4230 4234 ('r', 'rev', [],
4231 4235 _('a changeset intended to be included in the destination'),
4232 4236 _('REV')),
4233 4237 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4234 4238 ('b', 'branch', [],
4235 4239 _('a specific branch you would like to push'), _('BRANCH')),
4236 4240 ('', 'new-branch', False, _('allow pushing a new branch')),
4237 4241 ] + remoteopts,
4238 4242 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4239 4243 def push(ui, repo, dest=None, **opts):
4240 4244 """push changes to the specified destination
4241 4245
4242 4246 Push changesets from the local repository to the specified
4243 4247 destination.
4244 4248
4245 4249 This operation is symmetrical to pull: it is identical to a pull
4246 4250 in the destination repository from the current one.
4247 4251
4248 4252 By default, push will not allow creation of new heads at the
4249 4253 destination, since multiple heads would make it unclear which head
4250 4254 to use. In this situation, it is recommended to pull and merge
4251 4255 before pushing.
4252 4256
4253 4257 Use --new-branch if you want to allow push to create a new named
4254 4258 branch that is not present at the destination. This allows you to
4255 4259 only create a new branch without forcing other changes.
4256 4260
4257 4261 Use -f/--force to override the default behavior and push all
4258 4262 changesets on all branches.
4259 4263
4260 4264 If -r/--rev is used, the specified revision and all its ancestors
4261 4265 will be pushed to the remote repository.
4262 4266
4263 4267 Please see :hg:`help urls` for important details about ``ssh://``
4264 4268 URLs. If DESTINATION is omitted, a default path will be used.
4265 4269
4266 4270 Returns 0 if push was successful, 1 if nothing to push.
4267 4271 """
4268 4272
4269 4273 if opts.get('bookmark'):
4270 4274 for b in opts['bookmark']:
4271 4275 # translate -B options to -r so changesets get pushed
4272 4276 if b in repo._bookmarks:
4273 4277 opts.setdefault('rev', []).append(b)
4274 4278 else:
4275 4279 # if we try to push a deleted bookmark, translate it to null
4276 4280 # this lets simultaneous -r, -b options continue working
4277 4281 opts.setdefault('rev', []).append("null")
4278 4282
4279 4283 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4280 4284 dest, branches = hg.parseurl(dest, opts.get('branch'))
4281 4285 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4282 4286 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4283 4287 other = hg.peer(repo, opts, dest)
4284 4288 if revs:
4285 4289 revs = [repo.lookup(rev) for rev in revs]
4286 4290
4287 4291 repo._subtoppath = dest
4288 4292 try:
4289 4293 # push subrepos depth-first for coherent ordering
4290 4294 c = repo['']
4291 4295 subs = c.substate # only repos that are committed
4292 4296 for s in sorted(subs):
4293 4297 if not c.sub(s).push(opts.get('force')):
4294 4298 return False
4295 4299 finally:
4296 4300 del repo._subtoppath
4297 4301 result = repo.push(other, opts.get('force'), revs=revs,
4298 4302 newbranch=opts.get('new_branch'))
4299 4303
4300 4304 result = (result == 0)
4301 4305
4302 4306 if opts.get('bookmark'):
4303 4307 rb = other.listkeys('bookmarks')
4304 4308 for b in opts['bookmark']:
4305 4309 # explicit push overrides remote bookmark if any
4306 4310 if b in repo._bookmarks:
4307 4311 ui.status(_("exporting bookmark %s\n") % b)
4308 4312 new = repo[b].hex()
4309 4313 elif b in rb:
4310 4314 ui.status(_("deleting remote bookmark %s\n") % b)
4311 4315 new = '' # delete
4312 4316 else:
4313 4317 ui.warn(_('bookmark %s does not exist on the local '
4314 4318 'or remote repository!\n') % b)
4315 4319 return 2
4316 4320 old = rb.get(b, '')
4317 4321 r = other.pushkey('bookmarks', b, old, new)
4318 4322 if not r:
4319 4323 ui.warn(_('updating bookmark %s failed!\n') % b)
4320 4324 if not result:
4321 4325 result = 2
4322 4326
4323 4327 return result
4324 4328
4325 4329 @command('recover', [])
4326 4330 def recover(ui, repo):
4327 4331 """roll back an interrupted transaction
4328 4332
4329 4333 Recover from an interrupted commit or pull.
4330 4334
4331 4335 This command tries to fix the repository status after an
4332 4336 interrupted operation. It should only be necessary when Mercurial
4333 4337 suggests it.
4334 4338
4335 4339 Returns 0 if successful, 1 if nothing to recover or verify fails.
4336 4340 """
4337 4341 if repo.recover():
4338 4342 return hg.verify(repo)
4339 4343 return 1
4340 4344
4341 4345 @command('^remove|rm',
4342 4346 [('A', 'after', None, _('record delete for missing files')),
4343 4347 ('f', 'force', None,
4344 4348 _('remove (and delete) file even if added or modified')),
4345 4349 ] + walkopts,
4346 4350 _('[OPTION]... FILE...'))
4347 4351 def remove(ui, repo, *pats, **opts):
4348 4352 """remove the specified files on the next commit
4349 4353
4350 4354 Schedule the indicated files for removal from the current branch.
4351 4355
4352 4356 This command schedules the files to be removed at the next commit.
4353 4357 To undo a remove before that, see :hg:`revert`. To undo added
4354 4358 files, see :hg:`forget`.
4355 4359
4356 4360 .. container:: verbose
4357 4361
4358 4362 -A/--after can be used to remove only files that have already
4359 4363 been deleted, -f/--force can be used to force deletion, and -Af
4360 4364 can be used to remove files from the next revision without
4361 4365 deleting them from the working directory.
4362 4366
4363 4367 The following table details the behavior of remove for different
4364 4368 file states (columns) and option combinations (rows). The file
4365 4369 states are Added [A], Clean [C], Modified [M] and Missing [!]
4366 4370 (as reported by :hg:`status`). The actions are Warn, Remove
4367 4371 (from branch) and Delete (from disk):
4368 4372
4369 4373 ======= == == == ==
4370 4374 A C M !
4371 4375 ======= == == == ==
4372 4376 none W RD W R
4373 4377 -f R RD RD R
4374 4378 -A W W W R
4375 4379 -Af R R R R
4376 4380 ======= == == == ==
4377 4381
4378 4382 Note that remove never deletes files in Added [A] state from the
4379 4383 working directory, not even if option --force is specified.
4380 4384
4381 4385 Returns 0 on success, 1 if any warnings encountered.
4382 4386 """
4383 4387
4384 4388 ret = 0
4385 4389 after, force = opts.get('after'), opts.get('force')
4386 4390 if not pats and not after:
4387 4391 raise util.Abort(_('no files specified'))
4388 4392
4389 4393 m = scmutil.match(repo[None], pats, opts)
4390 4394 s = repo.status(match=m, clean=True)
4391 4395 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4392 4396
4393 4397 for f in m.files():
4394 4398 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4395 4399 if os.path.exists(m.rel(f)):
4396 4400 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4397 4401 ret = 1
4398 4402
4399 4403 if force:
4400 4404 list = modified + deleted + clean + added
4401 4405 elif after:
4402 4406 list = deleted
4403 4407 for f in modified + added + clean:
4404 4408 ui.warn(_('not removing %s: file still exists (use -f'
4405 4409 ' to force removal)\n') % m.rel(f))
4406 4410 ret = 1
4407 4411 else:
4408 4412 list = deleted + clean
4409 4413 for f in modified:
4410 4414 ui.warn(_('not removing %s: file is modified (use -f'
4411 4415 ' to force removal)\n') % m.rel(f))
4412 4416 ret = 1
4413 4417 for f in added:
4414 4418 ui.warn(_('not removing %s: file has been marked for add'
4415 4419 ' (use forget to undo)\n') % m.rel(f))
4416 4420 ret = 1
4417 4421
4418 4422 for f in sorted(list):
4419 4423 if ui.verbose or not m.exact(f):
4420 4424 ui.status(_('removing %s\n') % m.rel(f))
4421 4425
4422 4426 wlock = repo.wlock()
4423 4427 try:
4424 4428 if not after:
4425 4429 for f in list:
4426 4430 if f in added:
4427 4431 continue # we never unlink added files on remove
4428 4432 try:
4429 4433 util.unlinkpath(repo.wjoin(f))
4430 4434 except OSError, inst:
4431 4435 if inst.errno != errno.ENOENT:
4432 4436 raise
4433 4437 repo[None].forget(list)
4434 4438 finally:
4435 4439 wlock.release()
4436 4440
4437 4441 return ret
4438 4442
4439 4443 @command('rename|move|mv',
4440 4444 [('A', 'after', None, _('record a rename that has already occurred')),
4441 4445 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4442 4446 ] + walkopts + dryrunopts,
4443 4447 _('[OPTION]... SOURCE... DEST'))
4444 4448 def rename(ui, repo, *pats, **opts):
4445 4449 """rename files; equivalent of copy + remove
4446 4450
4447 4451 Mark dest as copies of sources; mark sources for deletion. If dest
4448 4452 is a directory, copies are put in that directory. If dest is a
4449 4453 file, there can only be one source.
4450 4454
4451 4455 By default, this command copies the contents of files as they
4452 4456 exist in the working directory. If invoked with -A/--after, the
4453 4457 operation is recorded, but no copying is performed.
4454 4458
4455 4459 This command takes effect at the next commit. To undo a rename
4456 4460 before that, see :hg:`revert`.
4457 4461
4458 4462 Returns 0 on success, 1 if errors are encountered.
4459 4463 """
4460 4464 wlock = repo.wlock(False)
4461 4465 try:
4462 4466 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4463 4467 finally:
4464 4468 wlock.release()
4465 4469
4466 4470 @command('resolve',
4467 4471 [('a', 'all', None, _('select all unresolved files')),
4468 4472 ('l', 'list', None, _('list state of files needing merge')),
4469 4473 ('m', 'mark', None, _('mark files as resolved')),
4470 4474 ('u', 'unmark', None, _('mark files as unresolved')),
4471 4475 ('n', 'no-status', None, _('hide status prefix'))]
4472 4476 + mergetoolopts + walkopts,
4473 4477 _('[OPTION]... [FILE]...'))
4474 4478 def resolve(ui, repo, *pats, **opts):
4475 4479 """redo merges or set/view the merge status of files
4476 4480
4477 4481 Merges with unresolved conflicts are often the result of
4478 4482 non-interactive merging using the ``internal:merge`` configuration
4479 4483 setting, or a command-line merge tool like ``diff3``. The resolve
4480 4484 command is used to manage the files involved in a merge, after
4481 4485 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4482 4486 working directory must have two parents).
4483 4487
4484 4488 The resolve command can be used in the following ways:
4485 4489
4486 4490 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4487 4491 files, discarding any previous merge attempts. Re-merging is not
4488 4492 performed for files already marked as resolved. Use ``--all/-a``
4489 4493 to select all unresolved files. ``--tool`` can be used to specify
4490 4494 the merge tool used for the given files. It overrides the HGMERGE
4491 4495 environment variable and your configuration files. Previous file
4492 4496 contents are saved with a ``.orig`` suffix.
4493 4497
4494 4498 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4495 4499 (e.g. after having manually fixed-up the files). The default is
4496 4500 to mark all unresolved files.
4497 4501
4498 4502 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4499 4503 default is to mark all resolved files.
4500 4504
4501 4505 - :hg:`resolve -l`: list files which had or still have conflicts.
4502 4506 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4503 4507
4504 4508 Note that Mercurial will not let you commit files with unresolved
4505 4509 merge conflicts. You must use :hg:`resolve -m ...` before you can
4506 4510 commit after a conflicting merge.
4507 4511
4508 4512 Returns 0 on success, 1 if any files fail a resolve attempt.
4509 4513 """
4510 4514
4511 4515 all, mark, unmark, show, nostatus = \
4512 4516 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4513 4517
4514 4518 if (show and (mark or unmark)) or (mark and unmark):
4515 4519 raise util.Abort(_("too many options specified"))
4516 4520 if pats and all:
4517 4521 raise util.Abort(_("can't specify --all and patterns"))
4518 4522 if not (all or pats or show or mark or unmark):
4519 4523 raise util.Abort(_('no files or directories specified; '
4520 4524 'use --all to remerge all files'))
4521 4525
4522 4526 ms = mergemod.mergestate(repo)
4523 4527 m = scmutil.match(repo[None], pats, opts)
4524 4528 ret = 0
4525 4529
4526 4530 for f in ms:
4527 4531 if m(f):
4528 4532 if show:
4529 4533 if nostatus:
4530 4534 ui.write("%s\n" % f)
4531 4535 else:
4532 4536 ui.write("%s %s\n" % (ms[f].upper(), f),
4533 4537 label='resolve.' +
4534 4538 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4535 4539 elif mark:
4536 4540 ms.mark(f, "r")
4537 4541 elif unmark:
4538 4542 ms.mark(f, "u")
4539 4543 else:
4540 4544 wctx = repo[None]
4541 4545 mctx = wctx.parents()[-1]
4542 4546
4543 4547 # backup pre-resolve (merge uses .orig for its own purposes)
4544 4548 a = repo.wjoin(f)
4545 4549 util.copyfile(a, a + ".resolve")
4546 4550
4547 4551 try:
4548 4552 # resolve file
4549 4553 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4550 4554 if ms.resolve(f, wctx, mctx):
4551 4555 ret = 1
4552 4556 finally:
4553 4557 ui.setconfig('ui', 'forcemerge', '')
4554 4558
4555 4559 # replace filemerge's .orig file with our resolve file
4556 4560 util.rename(a + ".resolve", a + ".orig")
4557 4561
4558 4562 ms.commit()
4559 4563 return ret
4560 4564
4561 4565 @command('revert',
4562 4566 [('a', 'all', None, _('revert all changes when no arguments given')),
4563 4567 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4564 4568 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4565 4569 ('C', 'no-backup', None, _('do not save backup copies of files')),
4566 4570 ] + walkopts + dryrunopts,
4567 4571 _('[OPTION]... [-r REV] [NAME]...'))
4568 4572 def revert(ui, repo, *pats, **opts):
4569 4573 """restore files to their checkout state
4570 4574
4571 4575 .. note::
4572 4576 To check out earlier revisions, you should use :hg:`update REV`.
4573 4577 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4574 4578
4575 4579 With no revision specified, revert the specified files or directories
4576 4580 to the contents they had in the parent of the working directory.
4577 4581 This restores the contents of files to an unmodified
4578 4582 state and unschedules adds, removes, copies, and renames. If the
4579 4583 working directory has two parents, you must explicitly specify a
4580 4584 revision.
4581 4585
4582 4586 Using the -r/--rev or -d/--date options, revert the given files or
4583 4587 directories to their states as of a specific revision. Because
4584 4588 revert does not change the working directory parents, this will
4585 4589 cause these files to appear modified. This can be helpful to "back
4586 4590 out" some or all of an earlier change. See :hg:`backout` for a
4587 4591 related method.
4588 4592
4589 4593 Modified files are saved with a .orig suffix before reverting.
4590 4594 To disable these backups, use --no-backup.
4591 4595
4592 4596 See :hg:`help dates` for a list of formats valid for -d/--date.
4593 4597
4594 4598 Returns 0 on success.
4595 4599 """
4596 4600
4597 4601 if opts.get("date"):
4598 4602 if opts.get("rev"):
4599 4603 raise util.Abort(_("you can't specify a revision and a date"))
4600 4604 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4601 4605
4602 4606 parent, p2 = repo.dirstate.parents()
4603 4607 if not opts.get('rev') and p2 != nullid:
4604 4608 # revert after merge is a trap for new users (issue2915)
4605 4609 raise util.Abort(_('uncommitted merge with no revision specified'),
4606 4610 hint=_('use "hg update" or see "hg help revert"'))
4607 4611
4608 4612 ctx = scmutil.revsingle(repo, opts.get('rev'))
4609 4613 node = ctx.node()
4610 4614
4611 4615 if not pats and not opts.get('all'):
4612 4616 msg = _("no files or directories specified")
4613 4617 if p2 != nullid:
4614 4618 hint = _("uncommitted merge, use --all to discard all changes,"
4615 4619 " or 'hg update -C .' to abort the merge")
4616 4620 raise util.Abort(msg, hint=hint)
4617 4621 dirty = util.any(repo.status())
4618 4622 if node != parent:
4619 4623 if dirty:
4620 4624 hint = _("uncommitted changes, use --all to discard all"
4621 4625 " changes, or 'hg update %s' to update") % ctx.rev()
4622 4626 else:
4623 4627 hint = _("use --all to revert all files,"
4624 4628 " or 'hg update %s' to update") % ctx.rev()
4625 4629 elif dirty:
4626 4630 hint = _("uncommitted changes, use --all to discard all changes")
4627 4631 else:
4628 4632 hint = _("use --all to revert all files")
4629 4633 raise util.Abort(msg, hint=hint)
4630 4634
4631 4635 mf = ctx.manifest()
4632 4636 if node == parent:
4633 4637 pmf = mf
4634 4638 else:
4635 4639 pmf = None
4636 4640
4637 4641 # need all matching names in dirstate and manifest of target rev,
4638 4642 # so have to walk both. do not print errors if files exist in one
4639 4643 # but not other.
4640 4644
4641 4645 names = {}
4642 4646
4643 4647 wlock = repo.wlock()
4644 4648 try:
4645 4649 # walk dirstate.
4646 4650
4647 4651 m = scmutil.match(repo[None], pats, opts)
4648 4652 m.bad = lambda x, y: False
4649 4653 for abs in repo.walk(m):
4650 4654 names[abs] = m.rel(abs), m.exact(abs)
4651 4655
4652 4656 # walk target manifest.
4653 4657
4654 4658 def badfn(path, msg):
4655 4659 if path in names:
4656 4660 return
4657 4661 if path in repo[node].substate:
4658 4662 ui.warn("%s: %s\n" % (m.rel(path),
4659 4663 'reverting subrepos is unsupported'))
4660 4664 return
4661 4665 path_ = path + '/'
4662 4666 for f in names:
4663 4667 if f.startswith(path_):
4664 4668 return
4665 4669 ui.warn("%s: %s\n" % (m.rel(path), msg))
4666 4670
4667 4671 m = scmutil.match(repo[node], pats, opts)
4668 4672 m.bad = badfn
4669 4673 for abs in repo[node].walk(m):
4670 4674 if abs not in names:
4671 4675 names[abs] = m.rel(abs), m.exact(abs)
4672 4676
4673 4677 m = scmutil.matchfiles(repo, names)
4674 4678 changes = repo.status(match=m)[:4]
4675 4679 modified, added, removed, deleted = map(set, changes)
4676 4680
4677 4681 # if f is a rename, also revert the source
4678 4682 cwd = repo.getcwd()
4679 4683 for f in added:
4680 4684 src = repo.dirstate.copied(f)
4681 4685 if src and src not in names and repo.dirstate[src] == 'r':
4682 4686 removed.add(src)
4683 4687 names[src] = (repo.pathto(src, cwd), True)
4684 4688
4685 4689 def removeforget(abs):
4686 4690 if repo.dirstate[abs] == 'a':
4687 4691 return _('forgetting %s\n')
4688 4692 return _('removing %s\n')
4689 4693
4690 4694 revert = ([], _('reverting %s\n'))
4691 4695 add = ([], _('adding %s\n'))
4692 4696 remove = ([], removeforget)
4693 4697 undelete = ([], _('undeleting %s\n'))
4694 4698
4695 4699 disptable = (
4696 4700 # dispatch table:
4697 4701 # file state
4698 4702 # action if in target manifest
4699 4703 # action if not in target manifest
4700 4704 # make backup if in target manifest
4701 4705 # make backup if not in target manifest
4702 4706 (modified, revert, remove, True, True),
4703 4707 (added, revert, remove, True, False),
4704 4708 (removed, undelete, None, False, False),
4705 4709 (deleted, revert, remove, False, False),
4706 4710 )
4707 4711
4708 4712 for abs, (rel, exact) in sorted(names.items()):
4709 4713 mfentry = mf.get(abs)
4710 4714 target = repo.wjoin(abs)
4711 4715 def handle(xlist, dobackup):
4712 4716 xlist[0].append(abs)
4713 4717 if (dobackup and not opts.get('no_backup') and
4714 4718 os.path.lexists(target)):
4715 4719 bakname = "%s.orig" % rel
4716 4720 ui.note(_('saving current version of %s as %s\n') %
4717 4721 (rel, bakname))
4718 4722 if not opts.get('dry_run'):
4719 4723 util.rename(target, bakname)
4720 4724 if ui.verbose or not exact:
4721 4725 msg = xlist[1]
4722 4726 if not isinstance(msg, basestring):
4723 4727 msg = msg(abs)
4724 4728 ui.status(msg % rel)
4725 4729 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4726 4730 if abs not in table:
4727 4731 continue
4728 4732 # file has changed in dirstate
4729 4733 if mfentry:
4730 4734 handle(hitlist, backuphit)
4731 4735 elif misslist is not None:
4732 4736 handle(misslist, backupmiss)
4733 4737 break
4734 4738 else:
4735 4739 if abs not in repo.dirstate:
4736 4740 if mfentry:
4737 4741 handle(add, True)
4738 4742 elif exact:
4739 4743 ui.warn(_('file not managed: %s\n') % rel)
4740 4744 continue
4741 4745 # file has not changed in dirstate
4742 4746 if node == parent:
4743 4747 if exact:
4744 4748 ui.warn(_('no changes needed to %s\n') % rel)
4745 4749 continue
4746 4750 if pmf is None:
4747 4751 # only need parent manifest in this unlikely case,
4748 4752 # so do not read by default
4749 4753 pmf = repo[parent].manifest()
4750 4754 if abs in pmf:
4751 4755 if mfentry:
4752 4756 # if version of file is same in parent and target
4753 4757 # manifests, do nothing
4754 4758 if (pmf[abs] != mfentry or
4755 4759 pmf.flags(abs) != mf.flags(abs)):
4756 4760 handle(revert, False)
4757 4761 else:
4758 4762 handle(remove, False)
4759 4763
4760 4764 if not opts.get('dry_run'):
4761 4765 def checkout(f):
4762 4766 fc = ctx[f]
4763 4767 repo.wwrite(f, fc.data(), fc.flags())
4764 4768
4765 4769 audit_path = scmutil.pathauditor(repo.root)
4766 4770 for f in remove[0]:
4767 4771 if repo.dirstate[f] == 'a':
4768 4772 repo.dirstate.drop(f)
4769 4773 continue
4770 4774 audit_path(f)
4771 4775 try:
4772 4776 util.unlinkpath(repo.wjoin(f))
4773 4777 except OSError:
4774 4778 pass
4775 4779 repo.dirstate.remove(f)
4776 4780
4777 4781 normal = None
4778 4782 if node == parent:
4779 4783 # We're reverting to our parent. If possible, we'd like status
4780 4784 # to report the file as clean. We have to use normallookup for
4781 4785 # merges to avoid losing information about merged/dirty files.
4782 4786 if p2 != nullid:
4783 4787 normal = repo.dirstate.normallookup
4784 4788 else:
4785 4789 normal = repo.dirstate.normal
4786 4790 for f in revert[0]:
4787 4791 checkout(f)
4788 4792 if normal:
4789 4793 normal(f)
4790 4794
4791 4795 for f in add[0]:
4792 4796 checkout(f)
4793 4797 repo.dirstate.add(f)
4794 4798
4795 4799 normal = repo.dirstate.normallookup
4796 4800 if node == parent and p2 == nullid:
4797 4801 normal = repo.dirstate.normal
4798 4802 for f in undelete[0]:
4799 4803 checkout(f)
4800 4804 normal(f)
4801 4805
4802 4806 finally:
4803 4807 wlock.release()
4804 4808
4805 4809 @command('rollback', dryrunopts +
4806 4810 [('f', 'force', False, _('ignore safety measures'))])
4807 4811 def rollback(ui, repo, **opts):
4808 4812 """roll back the last transaction (dangerous)
4809 4813
4810 4814 This command should be used with care. There is only one level of
4811 4815 rollback, and there is no way to undo a rollback. It will also
4812 4816 restore the dirstate at the time of the last transaction, losing
4813 4817 any dirstate changes since that time. This command does not alter
4814 4818 the working directory.
4815 4819
4816 4820 Transactions are used to encapsulate the effects of all commands
4817 4821 that create new changesets or propagate existing changesets into a
4818 4822 repository. For example, the following commands are transactional,
4819 4823 and their effects can be rolled back:
4820 4824
4821 4825 - commit
4822 4826 - import
4823 4827 - pull
4824 4828 - push (with this repository as the destination)
4825 4829 - unbundle
4826 4830
4827 4831 It's possible to lose data with rollback: commit, update back to
4828 4832 an older changeset, and then rollback. The update removes the
4829 4833 changes you committed from the working directory, and rollback
4830 4834 removes them from history. To avoid data loss, you must pass
4831 4835 --force in this case.
4832 4836
4833 4837 This command is not intended for use on public repositories. Once
4834 4838 changes are visible for pull by other users, rolling a transaction
4835 4839 back locally is ineffective (someone else may already have pulled
4836 4840 the changes). Furthermore, a race is possible with readers of the
4837 4841 repository; for example an in-progress pull from the repository
4838 4842 may fail if a rollback is performed.
4839 4843
4840 4844 Returns 0 on success, 1 if no rollback data is available.
4841 4845 """
4842 4846 return repo.rollback(dryrun=opts.get('dry_run'),
4843 4847 force=opts.get('force'))
4844 4848
4845 4849 @command('root', [])
4846 4850 def root(ui, repo):
4847 4851 """print the root (top) of the current working directory
4848 4852
4849 4853 Print the root directory of the current repository.
4850 4854
4851 4855 Returns 0 on success.
4852 4856 """
4853 4857 ui.write(repo.root + "\n")
4854 4858
4855 4859 @command('^serve',
4856 4860 [('A', 'accesslog', '', _('name of access log file to write to'),
4857 4861 _('FILE')),
4858 4862 ('d', 'daemon', None, _('run server in background')),
4859 4863 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4860 4864 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4861 4865 # use string type, then we can check if something was passed
4862 4866 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4863 4867 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4864 4868 _('ADDR')),
4865 4869 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4866 4870 _('PREFIX')),
4867 4871 ('n', 'name', '',
4868 4872 _('name to show in web pages (default: working directory)'), _('NAME')),
4869 4873 ('', 'web-conf', '',
4870 4874 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4871 4875 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4872 4876 _('FILE')),
4873 4877 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4874 4878 ('', 'stdio', None, _('for remote clients')),
4875 4879 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4876 4880 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4877 4881 ('', 'style', '', _('template style to use'), _('STYLE')),
4878 4882 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4879 4883 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4880 4884 _('[OPTION]...'))
4881 4885 def serve(ui, repo, **opts):
4882 4886 """start stand-alone webserver
4883 4887
4884 4888 Start a local HTTP repository browser and pull server. You can use
4885 4889 this for ad-hoc sharing and browsing of repositories. It is
4886 4890 recommended to use a real web server to serve a repository for
4887 4891 longer periods of time.
4888 4892
4889 4893 Please note that the server does not implement access control.
4890 4894 This means that, by default, anybody can read from the server and
4891 4895 nobody can write to it by default. Set the ``web.allow_push``
4892 4896 option to ``*`` to allow everybody to push to the server. You
4893 4897 should use a real web server if you need to authenticate users.
4894 4898
4895 4899 By default, the server logs accesses to stdout and errors to
4896 4900 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4897 4901 files.
4898 4902
4899 4903 To have the server choose a free port number to listen on, specify
4900 4904 a port number of 0; in this case, the server will print the port
4901 4905 number it uses.
4902 4906
4903 4907 Returns 0 on success.
4904 4908 """
4905 4909
4906 4910 if opts["stdio"] and opts["cmdserver"]:
4907 4911 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4908 4912
4909 4913 def checkrepo():
4910 4914 if repo is None:
4911 4915 raise error.RepoError(_("There is no Mercurial repository here"
4912 4916 " (.hg not found)"))
4913 4917
4914 4918 if opts["stdio"]:
4915 4919 checkrepo()
4916 4920 s = sshserver.sshserver(ui, repo)
4917 4921 s.serve_forever()
4918 4922
4919 4923 if opts["cmdserver"]:
4920 4924 checkrepo()
4921 4925 s = commandserver.server(ui, repo, opts["cmdserver"])
4922 4926 return s.serve()
4923 4927
4924 4928 # this way we can check if something was given in the command-line
4925 4929 if opts.get('port'):
4926 4930 opts['port'] = util.getport(opts.get('port'))
4927 4931
4928 4932 baseui = repo and repo.baseui or ui
4929 4933 optlist = ("name templates style address port prefix ipv6"
4930 4934 " accesslog errorlog certificate encoding")
4931 4935 for o in optlist.split():
4932 4936 val = opts.get(o, '')
4933 4937 if val in (None, ''): # should check against default options instead
4934 4938 continue
4935 4939 baseui.setconfig("web", o, val)
4936 4940 if repo and repo.ui != baseui:
4937 4941 repo.ui.setconfig("web", o, val)
4938 4942
4939 4943 o = opts.get('web_conf') or opts.get('webdir_conf')
4940 4944 if not o:
4941 4945 if not repo:
4942 4946 raise error.RepoError(_("There is no Mercurial repository"
4943 4947 " here (.hg not found)"))
4944 4948 o = repo.root
4945 4949
4946 4950 app = hgweb.hgweb(o, baseui=ui)
4947 4951
4948 4952 class service(object):
4949 4953 def init(self):
4950 4954 util.setsignalhandler()
4951 4955 self.httpd = hgweb.server.create_server(ui, app)
4952 4956
4953 4957 if opts['port'] and not ui.verbose:
4954 4958 return
4955 4959
4956 4960 if self.httpd.prefix:
4957 4961 prefix = self.httpd.prefix.strip('/') + '/'
4958 4962 else:
4959 4963 prefix = ''
4960 4964
4961 4965 port = ':%d' % self.httpd.port
4962 4966 if port == ':80':
4963 4967 port = ''
4964 4968
4965 4969 bindaddr = self.httpd.addr
4966 4970 if bindaddr == '0.0.0.0':
4967 4971 bindaddr = '*'
4968 4972 elif ':' in bindaddr: # IPv6
4969 4973 bindaddr = '[%s]' % bindaddr
4970 4974
4971 4975 fqaddr = self.httpd.fqaddr
4972 4976 if ':' in fqaddr:
4973 4977 fqaddr = '[%s]' % fqaddr
4974 4978 if opts['port']:
4975 4979 write = ui.status
4976 4980 else:
4977 4981 write = ui.write
4978 4982 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4979 4983 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4980 4984
4981 4985 def run(self):
4982 4986 self.httpd.serve_forever()
4983 4987
4984 4988 service = service()
4985 4989
4986 4990 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4987 4991
4988 4992 @command('showconfig|debugconfig',
4989 4993 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4990 4994 _('[-u] [NAME]...'))
4991 4995 def showconfig(ui, repo, *values, **opts):
4992 4996 """show combined config settings from all hgrc files
4993 4997
4994 4998 With no arguments, print names and values of all config items.
4995 4999
4996 5000 With one argument of the form section.name, print just the value
4997 5001 of that config item.
4998 5002
4999 5003 With multiple arguments, print names and values of all config
5000 5004 items with matching section names.
5001 5005
5002 5006 With --debug, the source (filename and line number) is printed
5003 5007 for each config item.
5004 5008
5005 5009 Returns 0 on success.
5006 5010 """
5007 5011
5008 5012 for f in scmutil.rcpath():
5009 5013 ui.debug('read config from: %s\n' % f)
5010 5014 untrusted = bool(opts.get('untrusted'))
5011 5015 if values:
5012 5016 sections = [v for v in values if '.' not in v]
5013 5017 items = [v for v in values if '.' in v]
5014 5018 if len(items) > 1 or items and sections:
5015 5019 raise util.Abort(_('only one config item permitted'))
5016 5020 for section, name, value in ui.walkconfig(untrusted=untrusted):
5017 5021 value = str(value).replace('\n', '\\n')
5018 5022 sectname = section + '.' + name
5019 5023 if values:
5020 5024 for v in values:
5021 5025 if v == section:
5022 5026 ui.debug('%s: ' %
5023 5027 ui.configsource(section, name, untrusted))
5024 5028 ui.write('%s=%s\n' % (sectname, value))
5025 5029 elif v == sectname:
5026 5030 ui.debug('%s: ' %
5027 5031 ui.configsource(section, name, untrusted))
5028 5032 ui.write(value, '\n')
5029 5033 else:
5030 5034 ui.debug('%s: ' %
5031 5035 ui.configsource(section, name, untrusted))
5032 5036 ui.write('%s=%s\n' % (sectname, value))
5033 5037
5034 5038 @command('^status|st',
5035 5039 [('A', 'all', None, _('show status of all files')),
5036 5040 ('m', 'modified', None, _('show only modified files')),
5037 5041 ('a', 'added', None, _('show only added files')),
5038 5042 ('r', 'removed', None, _('show only removed files')),
5039 5043 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5040 5044 ('c', 'clean', None, _('show only files without changes')),
5041 5045 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5042 5046 ('i', 'ignored', None, _('show only ignored files')),
5043 5047 ('n', 'no-status', None, _('hide status prefix')),
5044 5048 ('C', 'copies', None, _('show source of copied files')),
5045 5049 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5046 5050 ('', 'rev', [], _('show difference from revision'), _('REV')),
5047 5051 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5048 5052 ] + walkopts + subrepoopts,
5049 5053 _('[OPTION]... [FILE]...'))
5050 5054 def status(ui, repo, *pats, **opts):
5051 5055 """show changed files in the working directory
5052 5056
5053 5057 Show status of files in the repository. If names are given, only
5054 5058 files that match are shown. Files that are clean or ignored or
5055 5059 the source of a copy/move operation, are not listed unless
5056 5060 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5057 5061 Unless options described with "show only ..." are given, the
5058 5062 options -mardu are used.
5059 5063
5060 5064 Option -q/--quiet hides untracked (unknown and ignored) files
5061 5065 unless explicitly requested with -u/--unknown or -i/--ignored.
5062 5066
5063 5067 .. note::
5064 5068 status may appear to disagree with diff if permissions have
5065 5069 changed or a merge has occurred. The standard diff format does
5066 5070 not report permission changes and diff only reports changes
5067 5071 relative to one merge parent.
5068 5072
5069 5073 If one revision is given, it is used as the base revision.
5070 5074 If two revisions are given, the differences between them are
5071 5075 shown. The --change option can also be used as a shortcut to list
5072 5076 the changed files of a revision from its first parent.
5073 5077
5074 5078 The codes used to show the status of files are::
5075 5079
5076 5080 M = modified
5077 5081 A = added
5078 5082 R = removed
5079 5083 C = clean
5080 5084 ! = missing (deleted by non-hg command, but still tracked)
5081 5085 ? = not tracked
5082 5086 I = ignored
5083 5087 = origin of the previous file listed as A (added)
5084 5088
5085 5089 .. container:: verbose
5086 5090
5087 5091 Examples:
5088 5092
5089 5093 - show changes in the working directory relative to a changeset:
5090 5094
5091 5095 hg status --rev 9353
5092 5096
5093 5097 - show all changes including copies in an existing changeset::
5094 5098
5095 5099 hg status --copies --change 9353
5096 5100
5097 5101 - get a NUL separated list of added files, suitable for xargs::
5098 5102
5099 5103 hg status -an0
5100 5104
5101 5105 Returns 0 on success.
5102 5106 """
5103 5107
5104 5108 revs = opts.get('rev')
5105 5109 change = opts.get('change')
5106 5110
5107 5111 if revs and change:
5108 5112 msg = _('cannot specify --rev and --change at the same time')
5109 5113 raise util.Abort(msg)
5110 5114 elif change:
5111 5115 node2 = repo.lookup(change)
5112 5116 node1 = repo[node2].p1().node()
5113 5117 else:
5114 5118 node1, node2 = scmutil.revpair(repo, revs)
5115 5119
5116 5120 cwd = (pats and repo.getcwd()) or ''
5117 5121 end = opts.get('print0') and '\0' or '\n'
5118 5122 copy = {}
5119 5123 states = 'modified added removed deleted unknown ignored clean'.split()
5120 5124 show = [k for k in states if opts.get(k)]
5121 5125 if opts.get('all'):
5122 5126 show += ui.quiet and (states[:4] + ['clean']) or states
5123 5127 if not show:
5124 5128 show = ui.quiet and states[:4] or states[:5]
5125 5129
5126 5130 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5127 5131 'ignored' in show, 'clean' in show, 'unknown' in show,
5128 5132 opts.get('subrepos'))
5129 5133 changestates = zip(states, 'MAR!?IC', stat)
5130 5134
5131 5135 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5132 5136 ctxn = repo[nullid]
5133 5137 ctx1 = repo[node1]
5134 5138 ctx2 = repo[node2]
5135 5139 added = stat[1]
5136 5140 if node2 is None:
5137 5141 added = stat[0] + stat[1] # merged?
5138 5142
5139 5143 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5140 5144 if k in added:
5141 5145 copy[k] = v
5142 5146 elif v in added:
5143 5147 copy[v] = k
5144 5148
5145 5149 for state, char, files in changestates:
5146 5150 if state in show:
5147 5151 format = "%s %%s%s" % (char, end)
5148 5152 if opts.get('no_status'):
5149 5153 format = "%%s%s" % end
5150 5154
5151 5155 for f in files:
5152 5156 ui.write(format % repo.pathto(f, cwd),
5153 5157 label='status.' + state)
5154 5158 if f in copy:
5155 5159 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5156 5160 label='status.copied')
5157 5161
5158 5162 @command('^summary|sum',
5159 5163 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5160 5164 def summary(ui, repo, **opts):
5161 5165 """summarize working directory state
5162 5166
5163 5167 This generates a brief summary of the working directory state,
5164 5168 including parents, branch, commit status, and available updates.
5165 5169
5166 5170 With the --remote option, this will check the default paths for
5167 5171 incoming and outgoing changes. This can be time-consuming.
5168 5172
5169 5173 Returns 0 on success.
5170 5174 """
5171 5175
5172 5176 ctx = repo[None]
5173 5177 parents = ctx.parents()
5174 5178 pnode = parents[0].node()
5175 5179 marks = []
5176 5180
5177 5181 for p in parents:
5178 5182 # label with log.changeset (instead of log.parent) since this
5179 5183 # shows a working directory parent *changeset*:
5180 5184 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5181 5185 label='log.changeset')
5182 5186 ui.write(' '.join(p.tags()), label='log.tag')
5183 5187 if p.bookmarks():
5184 5188 marks.extend(p.bookmarks())
5185 5189 if p.rev() == -1:
5186 5190 if not len(repo):
5187 5191 ui.write(_(' (empty repository)'))
5188 5192 else:
5189 5193 ui.write(_(' (no revision checked out)'))
5190 5194 ui.write('\n')
5191 5195 if p.description():
5192 5196 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5193 5197 label='log.summary')
5194 5198
5195 5199 branch = ctx.branch()
5196 5200 bheads = repo.branchheads(branch)
5197 5201 m = _('branch: %s\n') % branch
5198 5202 if branch != 'default':
5199 5203 ui.write(m, label='log.branch')
5200 5204 else:
5201 5205 ui.status(m, label='log.branch')
5202 5206
5203 5207 if marks:
5204 5208 current = repo._bookmarkcurrent
5205 5209 ui.write(_('bookmarks:'), label='log.bookmark')
5206 5210 if current is not None:
5207 5211 try:
5208 5212 marks.remove(current)
5209 5213 ui.write(' *' + current, label='bookmarks.current')
5210 5214 except ValueError:
5211 5215 # current bookmark not in parent ctx marks
5212 5216 pass
5213 5217 for m in marks:
5214 5218 ui.write(' ' + m, label='log.bookmark')
5215 5219 ui.write('\n', label='log.bookmark')
5216 5220
5217 5221 st = list(repo.status(unknown=True))[:6]
5218 5222
5219 5223 c = repo.dirstate.copies()
5220 5224 copied, renamed = [], []
5221 5225 for d, s in c.iteritems():
5222 5226 if s in st[2]:
5223 5227 st[2].remove(s)
5224 5228 renamed.append(d)
5225 5229 else:
5226 5230 copied.append(d)
5227 5231 if d in st[1]:
5228 5232 st[1].remove(d)
5229 5233 st.insert(3, renamed)
5230 5234 st.insert(4, copied)
5231 5235
5232 5236 ms = mergemod.mergestate(repo)
5233 5237 st.append([f for f in ms if ms[f] == 'u'])
5234 5238
5235 5239 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5236 5240 st.append(subs)
5237 5241
5238 5242 labels = [ui.label(_('%d modified'), 'status.modified'),
5239 5243 ui.label(_('%d added'), 'status.added'),
5240 5244 ui.label(_('%d removed'), 'status.removed'),
5241 5245 ui.label(_('%d renamed'), 'status.copied'),
5242 5246 ui.label(_('%d copied'), 'status.copied'),
5243 5247 ui.label(_('%d deleted'), 'status.deleted'),
5244 5248 ui.label(_('%d unknown'), 'status.unknown'),
5245 5249 ui.label(_('%d ignored'), 'status.ignored'),
5246 5250 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5247 5251 ui.label(_('%d subrepos'), 'status.modified')]
5248 5252 t = []
5249 5253 for s, l in zip(st, labels):
5250 5254 if s:
5251 5255 t.append(l % len(s))
5252 5256
5253 5257 t = ', '.join(t)
5254 5258 cleanworkdir = False
5255 5259
5256 5260 if len(parents) > 1:
5257 5261 t += _(' (merge)')
5258 5262 elif branch != parents[0].branch():
5259 5263 t += _(' (new branch)')
5260 5264 elif (parents[0].extra().get('close') and
5261 5265 pnode in repo.branchheads(branch, closed=True)):
5262 5266 t += _(' (head closed)')
5263 5267 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5264 5268 t += _(' (clean)')
5265 5269 cleanworkdir = True
5266 5270 elif pnode not in bheads:
5267 5271 t += _(' (new branch head)')
5268 5272
5269 5273 if cleanworkdir:
5270 5274 ui.status(_('commit: %s\n') % t.strip())
5271 5275 else:
5272 5276 ui.write(_('commit: %s\n') % t.strip())
5273 5277
5274 5278 # all ancestors of branch heads - all ancestors of parent = new csets
5275 5279 new = [0] * len(repo)
5276 5280 cl = repo.changelog
5277 5281 for a in [cl.rev(n) for n in bheads]:
5278 5282 new[a] = 1
5279 5283 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5280 5284 new[a] = 1
5281 5285 for a in [p.rev() for p in parents]:
5282 5286 if a >= 0:
5283 5287 new[a] = 0
5284 5288 for a in cl.ancestors(*[p.rev() for p in parents]):
5285 5289 new[a] = 0
5286 5290 new = sum(new)
5287 5291
5288 5292 if new == 0:
5289 5293 ui.status(_('update: (current)\n'))
5290 5294 elif pnode not in bheads:
5291 5295 ui.write(_('update: %d new changesets (update)\n') % new)
5292 5296 else:
5293 5297 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5294 5298 (new, len(bheads)))
5295 5299
5296 5300 if opts.get('remote'):
5297 5301 t = []
5298 5302 source, branches = hg.parseurl(ui.expandpath('default'))
5299 5303 other = hg.peer(repo, {}, source)
5300 5304 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5301 5305 ui.debug('comparing with %s\n' % util.hidepassword(source))
5302 5306 repo.ui.pushbuffer()
5303 5307 commoninc = discovery.findcommonincoming(repo, other)
5304 5308 _common, incoming, _rheads = commoninc
5305 5309 repo.ui.popbuffer()
5306 5310 if incoming:
5307 5311 t.append(_('1 or more incoming'))
5308 5312
5309 5313 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5310 5314 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5311 5315 if source != dest:
5312 5316 other = hg.peer(repo, {}, dest)
5313 5317 commoninc = None
5314 5318 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5315 5319 repo.ui.pushbuffer()
5316 5320 common, outheads = discovery.findcommonoutgoing(repo, other,
5317 5321 commoninc=commoninc)
5318 5322 repo.ui.popbuffer()
5319 5323 o = repo.changelog.findmissing(common=common, heads=outheads)
5320 5324 if o:
5321 5325 t.append(_('%d outgoing') % len(o))
5322 5326 if 'bookmarks' in other.listkeys('namespaces'):
5323 5327 lmarks = repo.listkeys('bookmarks')
5324 5328 rmarks = other.listkeys('bookmarks')
5325 5329 diff = set(rmarks) - set(lmarks)
5326 5330 if len(diff) > 0:
5327 5331 t.append(_('%d incoming bookmarks') % len(diff))
5328 5332 diff = set(lmarks) - set(rmarks)
5329 5333 if len(diff) > 0:
5330 5334 t.append(_('%d outgoing bookmarks') % len(diff))
5331 5335
5332 5336 if t:
5333 5337 ui.write(_('remote: %s\n') % (', '.join(t)))
5334 5338 else:
5335 5339 ui.status(_('remote: (synced)\n'))
5336 5340
5337 5341 @command('tag',
5338 5342 [('f', 'force', None, _('force tag')),
5339 5343 ('l', 'local', None, _('make the tag local')),
5340 5344 ('r', 'rev', '', _('revision to tag'), _('REV')),
5341 5345 ('', 'remove', None, _('remove a tag')),
5342 5346 # -l/--local is already there, commitopts cannot be used
5343 5347 ('e', 'edit', None, _('edit commit message')),
5344 5348 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5345 5349 ] + commitopts2,
5346 5350 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5347 5351 def tag(ui, repo, name1, *names, **opts):
5348 5352 """add one or more tags for the current or given revision
5349 5353
5350 5354 Name a particular revision using <name>.
5351 5355
5352 5356 Tags are used to name particular revisions of the repository and are
5353 5357 very useful to compare different revisions, to go back to significant
5354 5358 earlier versions or to mark branch points as releases, etc. Changing
5355 5359 an existing tag is normally disallowed; use -f/--force to override.
5356 5360
5357 5361 If no revision is given, the parent of the working directory is
5358 5362 used, or tip if no revision is checked out.
5359 5363
5360 5364 To facilitate version control, distribution, and merging of tags,
5361 5365 they are stored as a file named ".hgtags" which is managed similarly
5362 5366 to other project files and can be hand-edited if necessary. This
5363 5367 also means that tagging creates a new commit. The file
5364 5368 ".hg/localtags" is used for local tags (not shared among
5365 5369 repositories).
5366 5370
5367 5371 Tag commits are usually made at the head of a branch. If the parent
5368 5372 of the working directory is not a branch head, :hg:`tag` aborts; use
5369 5373 -f/--force to force the tag commit to be based on a non-head
5370 5374 changeset.
5371 5375
5372 5376 See :hg:`help dates` for a list of formats valid for -d/--date.
5373 5377
5374 5378 Since tag names have priority over branch names during revision
5375 5379 lookup, using an existing branch name as a tag name is discouraged.
5376 5380
5377 5381 Returns 0 on success.
5378 5382 """
5379 5383
5380 5384 rev_ = "."
5381 5385 names = [t.strip() for t in (name1,) + names]
5382 5386 if len(names) != len(set(names)):
5383 5387 raise util.Abort(_('tag names must be unique'))
5384 5388 for n in names:
5385 5389 if n in ['tip', '.', 'null']:
5386 5390 raise util.Abort(_("the name '%s' is reserved") % n)
5387 5391 if not n:
5388 5392 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5389 5393 if opts.get('rev') and opts.get('remove'):
5390 5394 raise util.Abort(_("--rev and --remove are incompatible"))
5391 5395 if opts.get('rev'):
5392 5396 rev_ = opts['rev']
5393 5397 message = opts.get('message')
5394 5398 if opts.get('remove'):
5395 5399 expectedtype = opts.get('local') and 'local' or 'global'
5396 5400 for n in names:
5397 5401 if not repo.tagtype(n):
5398 5402 raise util.Abort(_("tag '%s' does not exist") % n)
5399 5403 if repo.tagtype(n) != expectedtype:
5400 5404 if expectedtype == 'global':
5401 5405 raise util.Abort(_("tag '%s' is not a global tag") % n)
5402 5406 else:
5403 5407 raise util.Abort(_("tag '%s' is not a local tag") % n)
5404 5408 rev_ = nullid
5405 5409 if not message:
5406 5410 # we don't translate commit messages
5407 5411 message = 'Removed tag %s' % ', '.join(names)
5408 5412 elif not opts.get('force'):
5409 5413 for n in names:
5410 5414 if n in repo.tags():
5411 5415 raise util.Abort(_("tag '%s' already exists "
5412 5416 "(use -f to force)") % n)
5413 5417 if not opts.get('local'):
5414 5418 p1, p2 = repo.dirstate.parents()
5415 5419 if p2 != nullid:
5416 5420 raise util.Abort(_('uncommitted merge'))
5417 5421 bheads = repo.branchheads()
5418 5422 if not opts.get('force') and bheads and p1 not in bheads:
5419 5423 raise util.Abort(_('not at a branch head (use -f to force)'))
5420 5424 r = scmutil.revsingle(repo, rev_).node()
5421 5425
5422 5426 if not message:
5423 5427 # we don't translate commit messages
5424 5428 message = ('Added tag %s for changeset %s' %
5425 5429 (', '.join(names), short(r)))
5426 5430
5427 5431 date = opts.get('date')
5428 5432 if date:
5429 5433 date = util.parsedate(date)
5430 5434
5431 5435 if opts.get('edit'):
5432 5436 message = ui.edit(message, ui.username())
5433 5437
5434 5438 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5435 5439
5436 5440 @command('tags', [], '')
5437 5441 def tags(ui, repo):
5438 5442 """list repository tags
5439 5443
5440 5444 This lists both regular and local tags. When the -v/--verbose
5441 5445 switch is used, a third column "local" is printed for local tags.
5442 5446
5443 5447 Returns 0 on success.
5444 5448 """
5445 5449
5446 5450 hexfunc = ui.debugflag and hex or short
5447 5451 tagtype = ""
5448 5452
5449 5453 for t, n in reversed(repo.tagslist()):
5450 5454 if ui.quiet:
5451 5455 ui.write("%s\n" % t, label='tags.normal')
5452 5456 continue
5453 5457
5454 5458 hn = hexfunc(n)
5455 5459 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5456 5460 rev = ui.label(r, 'log.changeset')
5457 5461 spaces = " " * (30 - encoding.colwidth(t))
5458 5462
5459 5463 tag = ui.label(t, 'tags.normal')
5460 5464 if ui.verbose:
5461 5465 if repo.tagtype(t) == 'local':
5462 5466 tagtype = " local"
5463 5467 tag = ui.label(t, 'tags.local')
5464 5468 else:
5465 5469 tagtype = ""
5466 5470 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5467 5471
5468 5472 @command('tip',
5469 5473 [('p', 'patch', None, _('show patch')),
5470 5474 ('g', 'git', None, _('use git extended diff format')),
5471 5475 ] + templateopts,
5472 5476 _('[-p] [-g]'))
5473 5477 def tip(ui, repo, **opts):
5474 5478 """show the tip revision
5475 5479
5476 5480 The tip revision (usually just called the tip) is the changeset
5477 5481 most recently added to the repository (and therefore the most
5478 5482 recently changed head).
5479 5483
5480 5484 If you have just made a commit, that commit will be the tip. If
5481 5485 you have just pulled changes from another repository, the tip of
5482 5486 that repository becomes the current tip. The "tip" tag is special
5483 5487 and cannot be renamed or assigned to a different changeset.
5484 5488
5485 5489 Returns 0 on success.
5486 5490 """
5487 5491 displayer = cmdutil.show_changeset(ui, repo, opts)
5488 5492 displayer.show(repo[len(repo) - 1])
5489 5493 displayer.close()
5490 5494
5491 5495 @command('unbundle',
5492 5496 [('u', 'update', None,
5493 5497 _('update to new branch head if changesets were unbundled'))],
5494 5498 _('[-u] FILE...'))
5495 5499 def unbundle(ui, repo, fname1, *fnames, **opts):
5496 5500 """apply one or more changegroup files
5497 5501
5498 5502 Apply one or more compressed changegroup files generated by the
5499 5503 bundle command.
5500 5504
5501 5505 Returns 0 on success, 1 if an update has unresolved files.
5502 5506 """
5503 5507 fnames = (fname1,) + fnames
5504 5508
5505 5509 lock = repo.lock()
5506 5510 wc = repo['.']
5507 5511 try:
5508 5512 for fname in fnames:
5509 5513 f = url.open(ui, fname)
5510 5514 gen = changegroup.readbundle(f, fname)
5511 5515 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5512 5516 lock=lock)
5513 5517 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5514 5518 finally:
5515 5519 lock.release()
5516 5520 return postincoming(ui, repo, modheads, opts.get('update'), None)
5517 5521
5518 5522 @command('^update|up|checkout|co',
5519 5523 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5520 5524 ('c', 'check', None,
5521 5525 _('update across branches if no uncommitted changes')),
5522 5526 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5523 5527 ('r', 'rev', '', _('revision'), _('REV'))],
5524 5528 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5525 5529 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5526 5530 """update working directory (or switch revisions)
5527 5531
5528 5532 Update the repository's working directory to the specified
5529 5533 changeset. If no changeset is specified, update to the tip of the
5530 5534 current named branch.
5531 5535
5532 5536 If the changeset is not a descendant of the working directory's
5533 5537 parent, the update is aborted. With the -c/--check option, the
5534 5538 working directory is checked for uncommitted changes; if none are
5535 5539 found, the working directory is updated to the specified
5536 5540 changeset.
5537 5541
5538 5542 Update sets the working directory's parent revison to the specified
5539 5543 changeset (see :hg:`help parents`).
5540 5544
5541 5545 The following rules apply when the working directory contains
5542 5546 uncommitted changes:
5543 5547
5544 5548 1. If neither -c/--check nor -C/--clean is specified, and if
5545 5549 the requested changeset is an ancestor or descendant of
5546 5550 the working directory's parent, the uncommitted changes
5547 5551 are merged into the requested changeset and the merged
5548 5552 result is left uncommitted. If the requested changeset is
5549 5553 not an ancestor or descendant (that is, it is on another
5550 5554 branch), the update is aborted and the uncommitted changes
5551 5555 are preserved.
5552 5556
5553 5557 2. With the -c/--check option, the update is aborted and the
5554 5558 uncommitted changes are preserved.
5555 5559
5556 5560 3. With the -C/--clean option, uncommitted changes are discarded and
5557 5561 the working directory is updated to the requested changeset.
5558 5562
5559 5563 Use null as the changeset to remove the working directory (like
5560 5564 :hg:`clone -U`).
5561 5565
5562 5566 If you want to revert just one file to an older revision, use
5563 5567 :hg:`revert [-r REV] NAME`.
5564 5568
5565 5569 See :hg:`help dates` for a list of formats valid for -d/--date.
5566 5570
5567 5571 Returns 0 on success, 1 if there are unresolved files.
5568 5572 """
5569 5573 if rev and node:
5570 5574 raise util.Abort(_("please specify just one revision"))
5571 5575
5572 5576 if rev is None or rev == '':
5573 5577 rev = node
5574 5578
5575 5579 # if we defined a bookmark, we have to remember the original bookmark name
5576 5580 brev = rev
5577 5581 rev = scmutil.revsingle(repo, rev, rev).rev()
5578 5582
5579 5583 if check and clean:
5580 5584 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5581 5585
5582 5586 if check:
5583 5587 # we could use dirty() but we can ignore merge and branch trivia
5584 5588 c = repo[None]
5585 5589 if c.modified() or c.added() or c.removed():
5586 5590 raise util.Abort(_("uncommitted local changes"))
5587 5591
5588 5592 if date:
5589 5593 if rev is not None:
5590 5594 raise util.Abort(_("you can't specify a revision and a date"))
5591 5595 rev = cmdutil.finddate(ui, repo, date)
5592 5596
5593 5597 if clean or check:
5594 5598 ret = hg.clean(repo, rev)
5595 5599 else:
5596 5600 ret = hg.update(repo, rev)
5597 5601
5598 5602 if brev in repo._bookmarks:
5599 5603 bookmarks.setcurrent(repo, brev)
5600 5604
5601 5605 return ret
5602 5606
5603 5607 @command('verify', [])
5604 5608 def verify(ui, repo):
5605 5609 """verify the integrity of the repository
5606 5610
5607 5611 Verify the integrity of the current repository.
5608 5612
5609 5613 This will perform an extensive check of the repository's
5610 5614 integrity, validating the hashes and checksums of each entry in
5611 5615 the changelog, manifest, and tracked files, as well as the
5612 5616 integrity of their crosslinks and indices.
5613 5617
5614 5618 Returns 0 on success, 1 if errors are encountered.
5615 5619 """
5616 5620 return hg.verify(repo)
5617 5621
5618 5622 @command('version', [])
5619 5623 def version_(ui):
5620 5624 """output version and copyright information"""
5621 5625 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5622 5626 % util.version())
5623 5627 ui.status(_(
5624 5628 "(see http://mercurial.selenic.com for more information)\n"
5625 5629 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5626 5630 "This is free software; see the source for copying conditions. "
5627 5631 "There is NO\nwarranty; "
5628 5632 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5629 5633 ))
5630 5634
5631 5635 norepo = ("clone init version help debugcommands debugcomplete"
5632 5636 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5633 5637 " debugknown debuggetbundle debugbundle")
5634 5638 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5635 5639 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,1312 +1,1312 b''
1 1 The Mercurial system uses a set of configuration files to control
2 2 aspects of its behavior.
3 3
4 4 The configuration files use a simple ini-file format. A configuration
5 5 file consists of sections, led by a ``[section]`` header and followed
6 6 by ``name = value`` entries::
7 7
8 8 [ui]
9 9 username = Firstname Lastname <firstname.lastname@example.net>
10 10 verbose = True
11 11
12 12 The above entries will be referred to as ``ui.username`` and
13 13 ``ui.verbose``, respectively. See the Syntax section below.
14 14
15 15 Files
16 16 -----
17 17
18 18 Mercurial reads configuration data from several files, if they exist.
19 19 These files do not exist by default and you will have to create the
20 20 appropriate configuration files yourself: global configuration like
21 21 the username setting is typically put into
22 22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
23 23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
24 24
25 25 The names of these files depend on the system on which Mercurial is
26 26 installed. ``*.rc`` files from a single directory are read in
27 27 alphabetical order, later ones overriding earlier ones. Where multiple
28 28 paths are given below, settings from earlier paths override later
29 29 ones.
30 30
31 31 | (Unix, Windows) ``<repo>/.hg/hgrc``
32 32
33 33 Per-repository configuration options that only apply in a
34 34 particular repository. This file is not version-controlled, and
35 35 will not get transferred during a "clone" operation. Options in
36 36 this file override options in all other configuration files. On
37 37 Unix, most of this file will be ignored if it doesn't belong to a
38 38 trusted user or to a trusted group. See the documentation for the
39 39 ``[trusted]`` section below for more details.
40 40
41 41 | (Unix) ``$HOME/.hgrc``
42 42 | (Windows) ``%USERPROFILE%\.hgrc``
43 43 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 44 | (Windows) ``%HOME%\.hgrc``
45 45 | (Windows) ``%HOME%\Mercurial.ini``
46 46
47 47 Per-user configuration file(s), for the user running Mercurial. On
48 48 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 49 files apply to all Mercurial commands executed by this user in any
50 50 directory. Options in these files override per-system and per-installation
51 51 options.
52 52
53 53 | (Unix) ``/etc/mercurial/hgrc``
54 54 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
55 55
56 56 Per-system configuration files, for the system on which Mercurial
57 57 is running. Options in these files apply to all Mercurial commands
58 58 executed by any user in any directory. Options in these files
59 59 override per-installation options.
60 60
61 61 | (Unix) ``<install-root>/etc/mercurial/hgrc``
62 62 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
63 63
64 64 Per-installation configuration files, searched for in the
65 65 directory where Mercurial is installed. ``<install-root>`` is the
66 66 parent directory of the **hg** executable (or symlink) being run. For
67 67 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
68 68 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
69 69 to all Mercurial commands executed by any user in any directory.
70 70
71 71 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
72 72 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
73 73 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
74 74
75 75 Per-installation/system configuration files, for the system on
76 76 which Mercurial is running. Options in these files apply to all
77 77 Mercurial commands executed by any user in any directory. Registry
78 78 keys contain PATH-like strings, every part of which must reference
79 79 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
80 80 be read. Mercurial checks each of these locations in the specified
81 81 order until one or more configuration files are detected. If the
82 82 pywin32 extensions are not installed, Mercurial will only look for
83 83 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
84 84
85 85 Syntax
86 86 ------
87 87
88 88 A configuration file consists of sections, led by a ``[section]`` header
89 89 and followed by ``name = value`` entries (sometimes called
90 90 ``configuration keys``)::
91 91
92 92 [spam]
93 93 eggs=ham
94 94 green=
95 95 eggs
96 96
97 97 Each line contains one entry. If the lines that follow are indented,
98 98 they are treated as continuations of that entry. Leading whitespace is
99 99 removed from values. Empty lines are skipped. Lines beginning with
100 100 ``#`` or ``;`` are ignored and may be used to provide comments.
101 101
102 102 Configuration keys can be set multiple times, in which case Mercurial
103 103 will use the value that was configured last. As an example::
104 104
105 105 [spam]
106 106 eggs=large
107 107 ham=serrano
108 108 eggs=small
109 109
110 110 This would set the configuration key named ``eggs`` to ``small``.
111 111
112 112 It is also possible to define a section multiple times. A section can
113 113 be redefined on the same and/or on different configuration files. For
114 114 example::
115 115
116 116 [foo]
117 117 eggs=large
118 118 ham=serrano
119 119 eggs=small
120 120
121 121 [bar]
122 122 eggs=ham
123 123 green=
124 124 eggs
125 125
126 126 [foo]
127 127 ham=prosciutto
128 128 eggs=medium
129 129 bread=toasted
130 130
131 131 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
132 132 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
133 133 respectively. As you can see there only thing that matters is the last
134 134 value that was set for each of the configuration keys.
135 135
136 136 If a configuration key is set multiple times in different
137 137 configuration files the final value will depend on the order in which
138 138 the different configuration files are read, with settings from earlier
139 139 paths overriding later ones as described on the ``Files`` section
140 140 above.
141 141
142 142 A line of the form ``%include file`` will include ``file`` into the
143 143 current configuration file. The inclusion is recursive, which means
144 144 that included files can include other files. Filenames are relative to
145 145 the configuration file in which the ``%include`` directive is found.
146 146 Environment variables and ``~user`` constructs are expanded in
147 147 ``file``. This lets you do something like::
148 148
149 149 %include ~/.hgrc.d/$HOST.rc
150 150
151 151 to include a different configuration file on each computer you use.
152 152
153 153 A line with ``%unset name`` will remove ``name`` from the current
154 154 section, if it has been set previously.
155 155
156 156 The values are either free-form text strings, lists of text strings,
157 157 or Boolean values. Boolean values can be set to true using any of "1",
158 158 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
159 159 (all case insensitive).
160 160
161 161 List values are separated by whitespace or comma, except when values are
162 162 placed in double quotation marks::
163 163
164 164 allow_read = "John Doe, PhD", brian, betty
165 165
166 166 Quotation marks can be escaped by prefixing them with a backslash. Only
167 167 quotation marks at the beginning of a word is counted as a quotation
168 168 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
169 169
170 170 Sections
171 171 --------
172 172
173 173 This section describes the different sections that may appear in a
174 174 Mercurial configuration file, the purpose of each section, its possible
175 175 keys, and their possible values.
176 176
177 177 ``alias``
178 178 """""""""
179 179
180 180 Defines command aliases.
181 181 Aliases allow you to define your own commands in terms of other
182 182 commands (or aliases), optionally including arguments. Positional
183 183 arguments in the form of ``$1``, ``$2``, etc in the alias definition
184 184 are expanded by Mercurial before execution. Positional arguments not
185 185 already used by ``$N`` in the definition are put at the end of the
186 186 command to be executed.
187 187
188 188 Alias definitions consist of lines of the form::
189 189
190 190 <alias> = <command> [<argument>]...
191 191
192 192 For example, this definition::
193 193
194 194 latest = log --limit 5
195 195
196 196 creates a new command ``latest`` that shows only the five most recent
197 197 changesets. You can define subsequent aliases using earlier ones::
198 198
199 199 stable5 = latest -b stable
200 200
201 201 .. note:: It is possible to create aliases with the same names as
202 202 existing commands, which will then override the original
203 203 definitions. This is almost always a bad idea!
204 204
205 205 An alias can start with an exclamation point (``!``) to make it a
206 206 shell alias. A shell alias is executed with the shell and will let you
207 207 run arbitrary commands. As an example, ::
208 208
209 209 echo = !echo
210 210
211 211 will let you do ``hg echo foo`` to have ``foo`` printed in your
212 212 terminal. A better example might be::
213 213
214 214 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
215 215
216 216 which will make ``hg purge`` delete all unknown files in the
217 217 repository in the same manner as the purge extension.
218 218
219 219 Shell aliases are executed in an environment where ``$HG`` expand to
220 220 the path of the Mercurial that was used to execute the alias. This is
221 221 useful when you want to call further Mercurial commands in a shell
222 222 alias, as was done above for the purge alias. In addition,
223 223 ``$HG_ARGS`` expand to the arguments given to Mercurial. In the ``hg
224 224 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
225 225
226 226 .. note:: Some global configuration options such as ``-R`` are
227 227 processed before shell aliases and will thus not be passed to
228 228 aliases.
229 229
230 230 ``auth``
231 231 """"""""
232 232
233 233 Authentication credentials for HTTP authentication. This section
234 234 allows you to store usernames and passwords for use when logging
235 235 *into* HTTP servers. See the ``[web]`` configuration section if
236 236 you want to configure *who* can login to your HTTP server.
237 237
238 238 Each line has the following format::
239 239
240 240 <name>.<argument> = <value>
241 241
242 242 where ``<name>`` is used to group arguments into authentication
243 243 entries. Example::
244 244
245 245 foo.prefix = hg.intevation.org/mercurial
246 246 foo.username = foo
247 247 foo.password = bar
248 248 foo.schemes = http https
249 249
250 250 bar.prefix = secure.example.org
251 251 bar.key = path/to/file.key
252 252 bar.cert = path/to/file.cert
253 253 bar.schemes = https
254 254
255 255 Supported arguments:
256 256
257 257 ``prefix``
258 258 Either ``*`` or a URI prefix with or without the scheme part.
259 259 The authentication entry with the longest matching prefix is used
260 260 (where ``*`` matches everything and counts as a match of length
261 261 1). If the prefix doesn't include a scheme, the match is performed
262 262 against the URI with its scheme stripped as well, and the schemes
263 263 argument, q.v., is then subsequently consulted.
264 264
265 265 ``username``
266 266 Optional. Username to authenticate with. If not given, and the
267 267 remote site requires basic or digest authentication, the user will
268 268 be prompted for it. Environment variables are expanded in the
269 269 username letting you do ``foo.username = $USER``. If the URI
270 270 includes a username, only ``[auth]`` entries with a matching
271 271 username or without a username will be considered.
272 272
273 273 ``password``
274 274 Optional. Password to authenticate with. If not given, and the
275 275 remote site requires basic or digest authentication, the user
276 276 will be prompted for it.
277 277
278 278 ``key``
279 279 Optional. PEM encoded client certificate key file. Environment
280 280 variables are expanded in the filename.
281 281
282 282 ``cert``
283 283 Optional. PEM encoded client certificate chain file. Environment
284 284 variables are expanded in the filename.
285 285
286 286 ``schemes``
287 287 Optional. Space separated list of URI schemes to use this
288 288 authentication entry with. Only used if the prefix doesn't include
289 289 a scheme. Supported schemes are http and https. They will match
290 290 static-http and static-https respectively, as well.
291 291 Default: https.
292 292
293 293 If no suitable authentication entry is found, the user is prompted
294 294 for credentials as usual if required by the remote.
295 295
296 296
297 297 ``decode/encode``
298 298 """""""""""""""""
299 299
300 300 Filters for transforming files on checkout/checkin. This would
301 301 typically be used for newline processing or other
302 302 localization/canonicalization of files.
303 303
304 304 Filters consist of a filter pattern followed by a filter command.
305 305 Filter patterns are globs by default, rooted at the repository root.
306 306 For example, to match any file ending in ``.txt`` in the root
307 307 directory only, use the pattern ``*.txt``. To match any file ending
308 308 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
309 309 For each file only the first matching filter applies.
310 310
311 311 The filter command can start with a specifier, either ``pipe:`` or
312 312 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
313 313
314 314 A ``pipe:`` command must accept data on stdin and return the transformed
315 315 data on stdout.
316 316
317 317 Pipe example::
318 318
319 319 [encode]
320 320 # uncompress gzip files on checkin to improve delta compression
321 321 # note: not necessarily a good idea, just an example
322 322 *.gz = pipe: gunzip
323 323
324 324 [decode]
325 325 # recompress gzip files when writing them to the working dir (we
326 326 # can safely omit "pipe:", because it's the default)
327 327 *.gz = gzip
328 328
329 329 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
330 330 with the name of a temporary file that contains the data to be
331 331 filtered by the command. The string ``OUTFILE`` is replaced with the name
332 332 of an empty temporary file, where the filtered data must be written by
333 333 the command.
334 334
335 335 .. note:: The tempfile mechanism is recommended for Windows systems,
336 336 where the standard shell I/O redirection operators often have
337 337 strange effects and may corrupt the contents of your files.
338 338
339 339 This filter mechanism is used internally by the ``eol`` extension to
340 340 translate line ending characters between Windows (CRLF) and Unix (LF)
341 341 format. We suggest you use the ``eol`` extension for convenience.
342 342
343 343
344 344 ``defaults``
345 345 """"""""""""
346 346
347 347 (defaults are deprecated. Don't use them. Use aliases instead)
348 348
349 349 Use the ``[defaults]`` section to define command defaults, i.e. the
350 350 default options/arguments to pass to the specified commands.
351 351
352 352 The following example makes :hg:`log` run in verbose mode, and
353 353 :hg:`status` show only the modified files, by default::
354 354
355 355 [defaults]
356 356 log = -v
357 357 status = -m
358 358
359 359 The actual commands, instead of their aliases, must be used when
360 360 defining command defaults. The command defaults will also be applied
361 361 to the aliases of the commands defined.
362 362
363 363
364 364 ``diff``
365 365 """"""""
366 366
367 367 Settings used when displaying diffs. Everything except for ``unified`` is a
368 368 Boolean and defaults to False.
369 369
370 370 ``git``
371 371 Use git extended diff format.
372 372
373 373 ``nodates``
374 374 Don't include dates in diff headers.
375 375
376 376 ``showfunc``
377 377 Show which function each change is in.
378 378
379 379 ``ignorews``
380 380 Ignore white space when comparing lines.
381 381
382 382 ``ignorewsamount``
383 383 Ignore changes in the amount of white space.
384 384
385 385 ``ignoreblanklines``
386 386 Ignore changes whose lines are all blank.
387 387
388 388 ``unified``
389 389 Number of lines of context to show.
390 390
391 391 ``email``
392 392 """""""""
393 393
394 394 Settings for extensions that send email messages.
395 395
396 396 ``from``
397 397 Optional. Email address to use in "From" header and SMTP envelope
398 398 of outgoing messages.
399 399
400 400 ``to``
401 401 Optional. Comma-separated list of recipients' email addresses.
402 402
403 403 ``cc``
404 404 Optional. Comma-separated list of carbon copy recipients'
405 405 email addresses.
406 406
407 407 ``bcc``
408 408 Optional. Comma-separated list of blind carbon copy recipients'
409 409 email addresses.
410 410
411 411 ``method``
412 412 Optional. Method to use to send email messages. If value is ``smtp``
413 413 (default), use SMTP (see the ``[smtp]`` section for configuration).
414 414 Otherwise, use as name of program to run that acts like sendmail
415 415 (takes ``-f`` option for sender, list of recipients on command line,
416 416 message on stdin). Normally, setting this to ``sendmail`` or
417 417 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
418 418
419 419 ``charsets``
420 420 Optional. Comma-separated list of character sets considered
421 421 convenient for recipients. Addresses, headers, and parts not
422 422 containing patches of outgoing messages will be encoded in the
423 423 first character set to which conversion from local encoding
424 424 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
425 425 conversion fails, the text in question is sent as is. Defaults to
426 426 empty (explicit) list.
427 427
428 428 Order of outgoing email character sets:
429 429
430 430 1. ``us-ascii``: always first, regardless of settings
431 431 2. ``email.charsets``: in order given by user
432 432 3. ``ui.fallbackencoding``: if not in email.charsets
433 433 4. ``$HGENCODING``: if not in email.charsets
434 434 5. ``utf-8``: always last, regardless of settings
435 435
436 436 Email example::
437 437
438 438 [email]
439 439 from = Joseph User <joe.user@example.com>
440 440 method = /usr/sbin/sendmail
441 441 # charsets for western Europeans
442 442 # us-ascii, utf-8 omitted, as they are tried first and last
443 443 charsets = iso-8859-1, iso-8859-15, windows-1252
444 444
445 445
446 446 ``extensions``
447 447 """"""""""""""
448 448
449 449 Mercurial has an extension mechanism for adding new features. To
450 450 enable an extension, create an entry for it in this section.
451 451
452 452 If you know that the extension is already in Python's search path,
453 453 you can give the name of the module, followed by ``=``, with nothing
454 454 after the ``=``.
455 455
456 456 Otherwise, give a name that you choose, followed by ``=``, followed by
457 457 the path to the ``.py`` file (including the file name extension) that
458 458 defines the extension.
459 459
460 460 To explicitly disable an extension that is enabled in an hgrc of
461 461 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
462 462 or ``foo = !`` when path is not supplied.
463 463
464 464 Example for ``~/.hgrc``::
465 465
466 466 [extensions]
467 467 # (the mq extension will get loaded from Mercurial's path)
468 468 mq =
469 469 # (this extension will get loaded from the file specified)
470 470 myfeature = ~/.hgext/myfeature.py
471 471
472 472
473 473 ``hostfingerprints``
474 474 """"""""""""""""""""
475 475
476 476 Fingerprints of the certificates of known HTTPS servers.
477 477 A HTTPS connection to a server with a fingerprint configured here will
478 478 only succeed if the servers certificate matches the fingerprint.
479 479 This is very similar to how ssh known hosts works.
480 480 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
481 481 The CA chain and web.cacerts is not used for servers with a fingerprint.
482 482
483 483 For example::
484 484
485 485 [hostfingerprints]
486 486 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
487 487
488 488 This feature is only supported when using Python 2.6 or later.
489 489
490 490
491 491 ``format``
492 492 """"""""""
493 493
494 494 ``usestore``
495 495 Enable or disable the "store" repository format which improves
496 496 compatibility with systems that fold case or otherwise mangle
497 497 filenames. Enabled by default. Disabling this option will allow
498 498 you to store longer filenames in some situations at the expense of
499 499 compatibility and ensures that the on-disk format of newly created
500 500 repositories will be compatible with Mercurial before version 0.9.4.
501 501
502 502 ``usefncache``
503 503 Enable or disable the "fncache" repository format which enhances
504 504 the "store" repository format (which has to be enabled to use
505 505 fncache) to allow longer filenames and avoids using Windows
506 506 reserved names, e.g. "nul". Enabled by default. Disabling this
507 507 option ensures that the on-disk format of newly created
508 508 repositories will be compatible with Mercurial before version 1.1.
509 509
510 510 ``dotencode``
511 511 Enable or disable the "dotencode" repository format which enhances
512 512 the "fncache" repository format (which has to be enabled to use
513 513 dotencode) to avoid issues with filenames starting with ._ on
514 514 Mac OS X and spaces on Windows. Enabled by default. Disabling this
515 515 option ensures that the on-disk format of newly created
516 516 repositories will be compatible with Mercurial before version 1.7.
517 517
518 518 ``merge-patterns``
519 519 """"""""""""""""""
520 520
521 521 This section specifies merge tools to associate with particular file
522 522 patterns. Tools matched here will take precedence over the default
523 523 merge tool. Patterns are globs by default, rooted at the repository
524 524 root.
525 525
526 526 Example::
527 527
528 528 [merge-patterns]
529 529 **.c = kdiff3
530 530 **.jpg = myimgmerge
531 531
532 532 ``merge-tools``
533 533 """""""""""""""
534 534
535 535 This section configures external merge tools to use for file-level
536 536 merges.
537 537
538 538 Example ``~/.hgrc``::
539 539
540 540 [merge-tools]
541 541 # Override stock tool location
542 542 kdiff3.executable = ~/bin/kdiff3
543 543 # Specify command line
544 544 kdiff3.args = $base $local $other -o $output
545 545 # Give higher priority
546 546 kdiff3.priority = 1
547 547
548 548 # Define new tool
549 549 myHtmlTool.args = -m $local $other $base $output
550 550 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
551 551 myHtmlTool.priority = 1
552 552
553 553 Supported arguments:
554 554
555 555 ``priority``
556 556 The priority in which to evaluate this tool.
557 557 Default: 0.
558 558
559 559 ``executable``
560 560 Either just the name of the executable or its pathname. On Windows,
561 561 the path can use environment variables with ${ProgramFiles} syntax.
562 562 Default: the tool name.
563 563
564 564 ``args``
565 565 The arguments to pass to the tool executable. You can refer to the
566 566 files being merged as well as the output file through these
567 567 variables: ``$base``, ``$local``, ``$other``, ``$output``.
568 568 Default: ``$local $base $other``
569 569
570 570 ``premerge``
571 571 Attempt to run internal non-interactive 3-way merge tool before
572 572 launching external tool. Options are ``true``, ``false``, or ``keep``
573 573 to leave markers in the file if the premerge fails.
574 574 Default: True
575 575
576 576 ``binary``
577 577 This tool can merge binary files. Defaults to False, unless tool
578 578 was selected by file pattern match.
579 579
580 580 ``symlink``
581 581 This tool can merge symlinks. Defaults to False, even if tool was
582 582 selected by file pattern match.
583 583
584 584 ``check``
585 585 A list of merge success-checking options:
586 586
587 587 ``changed``
588 588 Ask whether merge was successful when the merged file shows no changes.
589 589 ``conflicts``
590 590 Check whether there are conflicts even though the tool reported success.
591 591 ``prompt``
592 592 Always prompt for merge success, regardless of success reported by tool.
593 593
594 594 ``checkchanged``
595 595 True is equivalent to ``check = changed``.
596 596 Default: False
597 597
598 598 ``checkconflicts``
599 599 True is equivalent to ``check = conflicts``.
600 600 Default: False
601 601
602 602 ``fixeol``
603 603 Attempt to fix up EOL changes caused by the merge tool.
604 604 Default: False
605 605
606 606 ``gui``
607 607 This tool requires a graphical interface to run. Default: False
608 608
609 609 ``regkey``
610 610 Windows registry key which describes install location of this
611 611 tool. Mercurial will search for this key first under
612 612 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
613 613 Default: None
614 614
615 615 ``regkeyalt``
616 616 An alternate Windows registry key to try if the first key is not
617 617 found. The alternate key uses the same ``regname`` and ``regappend``
618 618 semantics of the primary key. The most common use for this key
619 619 is to search for 32bit applications on 64bit operating systems.
620 620 Default: None
621 621
622 622 ``regname``
623 623 Name of value to read from specified registry key. Defaults to the
624 624 unnamed (default) value.
625 625
626 626 ``regappend``
627 627 String to append to the value read from the registry, typically
628 628 the executable name of the tool.
629 629 Default: None
630 630
631 631
632 632 ``hooks``
633 633 """""""""
634 634
635 635 Commands or Python functions that get automatically executed by
636 636 various actions such as starting or finishing a commit. Multiple
637 637 hooks can be run for the same action by appending a suffix to the
638 638 action. Overriding a site-wide hook can be done by changing its
639 639 value or setting it to an empty string.
640 640
641 641 Example ``.hg/hgrc``::
642 642
643 643 [hooks]
644 644 # update working directory after adding changesets
645 645 changegroup.update = hg update
646 646 # do not use the site-wide hook
647 647 incoming =
648 648 incoming.email = /my/email/hook
649 649 incoming.autobuild = /my/build/hook
650 650
651 651 Most hooks are run with environment variables set that give useful
652 652 additional information. For each hook below, the environment
653 653 variables it is passed are listed with names of the form ``$HG_foo``.
654 654
655 655 ``changegroup``
656 656 Run after a changegroup has been added via push, pull or unbundle.
657 657 ID of the first new changeset is in ``$HG_NODE``. URL from which
658 658 changes came is in ``$HG_URL``.
659 659
660 660 ``commit``
661 661 Run after a changeset has been created in the local repository. ID
662 662 of the newly created changeset is in ``$HG_NODE``. Parent changeset
663 663 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
664 664
665 665 ``incoming``
666 666 Run after a changeset has been pulled, pushed, or unbundled into
667 667 the local repository. The ID of the newly arrived changeset is in
668 668 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
669 669
670 670 ``outgoing``
671 671 Run after sending changes from local repository to another. ID of
672 672 first changeset sent is in ``$HG_NODE``. Source of operation is in
673 673 ``$HG_SOURCE``; see "preoutgoing" hook for description.
674 674
675 675 ``post-<command>``
676 676 Run after successful invocations of the associated command. The
677 677 contents of the command line are passed as ``$HG_ARGS`` and the result
678 678 code in ``$HG_RESULT``. Parsed command line arguments are passed as
679 679 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
680 680 the python data internally passed to <command>. ``$HG_OPTS`` is a
681 681 dictionary of options (with unspecified options set to their defaults).
682 682 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
683 683
684 684 ``pre-<command>``
685 685 Run before executing the associated command. The contents of the
686 686 command line are passed as ``$HG_ARGS``. Parsed command line arguments
687 687 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
688 688 representations of the data internally passed to <command>. ``$HG_OPTS``
689 689 is a dictionary of options (with unspecified options set to their
690 690 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
691 691 failure, the command doesn't execute and Mercurial returns the failure
692 692 code.
693 693
694 694 ``prechangegroup``
695 695 Run before a changegroup is added via push, pull or unbundle. Exit
696 696 status 0 allows the changegroup to proceed. Non-zero status will
697 697 cause the push, pull or unbundle to fail. URL from which changes
698 698 will come is in ``$HG_URL``.
699 699
700 700 ``precommit``
701 701 Run before starting a local commit. Exit status 0 allows the
702 702 commit to proceed. Non-zero status will cause the commit to fail.
703 703 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
704 704
705 705 ``prelistkeys``
706 706 Run before listing pushkeys (like bookmarks) in the
707 707 repository. Non-zero status will cause failure. The key namespace is
708 708 in ``$HG_NAMESPACE``.
709 709
710 710 ``preoutgoing``
711 711 Run before collecting changes to send from the local repository to
712 712 another. Non-zero status will cause failure. This lets you prevent
713 713 pull over HTTP or SSH. Also prevents against local pull, push
714 714 (outbound) or bundle commands, but not effective, since you can
715 715 just copy files instead then. Source of operation is in
716 716 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
717 717 SSH or HTTP repository. If "push", "pull" or "bundle", operation
718 718 is happening on behalf of repository on same system.
719 719
720 720 ``prepushkey``
721 721 Run before a pushkey (like a bookmark) is added to the
722 722 repository. Non-zero status will cause the key to be rejected. The
723 723 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
724 724 the old value (if any) is in ``$HG_OLD``, and the new value is in
725 725 ``$HG_NEW``.
726 726
727 727 ``pretag``
728 728 Run before creating a tag. Exit status 0 allows the tag to be
729 729 created. Non-zero status will cause the tag to fail. ID of
730 730 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
731 731 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
732 732
733 733 ``pretxnchangegroup``
734 734 Run after a changegroup has been added via push, pull or unbundle,
735 735 but before the transaction has been committed. Changegroup is
736 736 visible to hook program. This lets you validate incoming changes
737 737 before accepting them. Passed the ID of the first new changeset in
738 738 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
739 739 status will cause the transaction to be rolled back and the push,
740 740 pull or unbundle will fail. URL that was source of changes is in
741 741 ``$HG_URL``.
742 742
743 743 ``pretxncommit``
744 744 Run after a changeset has been created but the transaction not yet
745 745 committed. Changeset is visible to hook program. This lets you
746 746 validate commit message and changes. Exit status 0 allows the
747 747 commit to proceed. Non-zero status will cause the transaction to
748 748 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
749 749 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
750 750
751 751 ``preupdate``
752 752 Run before updating the working directory. Exit status 0 allows
753 753 the update to proceed. Non-zero status will prevent the update.
754 754 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
755 755 of second new parent is in ``$HG_PARENT2``.
756 756
757 757 ``listkeys``
758 758 Run after listing pushkeys (like bookmarks) in the repository. The
759 759 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
760 760 dictionary containing the keys and values.
761 761
762 762 ``pushkey``
763 763 Run after a pushkey (like a bookmark) is added to the
764 764 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
765 765 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
766 766 value is in ``$HG_NEW``.
767 767
768 768 ``tag``
769 769 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
770 770 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
771 771 repository if ``$HG_LOCAL=0``.
772 772
773 773 ``update``
774 774 Run after updating the working directory. Changeset ID of first
775 775 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
776 776 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
777 777 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
778 778
779 779 .. note:: It is generally better to use standard hooks rather than the
780 780 generic pre- and post- command hooks as they are guaranteed to be
781 781 called in the appropriate contexts for influencing transactions.
782 782 Also, hooks like "commit" will be called in all contexts that
783 783 generate a commit (e.g. tag) and not just the commit command.
784 784
785 785 .. note:: Environment variables with empty values may not be passed to
786 786 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
787 787 will have an empty value under Unix-like platforms for non-merge
788 788 changesets, while it will not be available at all under Windows.
789 789
790 790 The syntax for Python hooks is as follows::
791 791
792 792 hookname = python:modulename.submodule.callable
793 793 hookname = python:/path/to/python/module.py:callable
794 794
795 795 Python hooks are run within the Mercurial process. Each hook is
796 796 called with at least three keyword arguments: a ui object (keyword
797 797 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
798 798 keyword that tells what kind of hook is used. Arguments listed as
799 799 environment variables above are passed as keyword arguments, with no
800 800 ``HG_`` prefix, and names in lower case.
801 801
802 802 If a Python hook returns a "true" value or raises an exception, this
803 803 is treated as a failure.
804 804
805 805
806 806 ``http_proxy``
807 807 """"""""""""""
808 808
809 809 Used to access web-based Mercurial repositories through a HTTP
810 810 proxy.
811 811
812 812 ``host``
813 813 Host name and (optional) port of the proxy server, for example
814 814 "myproxy:8000".
815 815
816 816 ``no``
817 817 Optional. Comma-separated list of host names that should bypass
818 818 the proxy.
819 819
820 820 ``passwd``
821 821 Optional. Password to authenticate with at the proxy server.
822 822
823 823 ``user``
824 824 Optional. User name to authenticate with at the proxy server.
825 825
826 826 ``always``
827 827 Optional. Always use the proxy, even for localhost and any entries
828 828 in ``http_proxy.no``. True or False. Default: False.
829 829
830 830 ``smtp``
831 831 """"""""
832 832
833 833 Configuration for extensions that need to send email messages.
834 834
835 835 ``host``
836 836 Host name of mail server, e.g. "mail.example.com".
837 837
838 838 ``port``
839 839 Optional. Port to connect to on mail server. Default: 25.
840 840
841 841 ``tls``
842 842 Optional. Method to enable TLS when connecting to mail server: starttls,
843 843 smtps or none. Default: none.
844 844
845 845 ``username``
846 846 Optional. User name for authenticating with the SMTP server.
847 847 Default: none.
848 848
849 849 ``password``
850 850 Optional. Password for authenticating with the SMTP server. If not
851 851 specified, interactive sessions will prompt the user for a
852 852 password; non-interactive sessions will fail. Default: none.
853 853
854 854 ``local_hostname``
855 855 Optional. It's the hostname that the sender can use to identify
856 856 itself to the MTA.
857 857
858 858
859 859 ``patch``
860 860 """""""""
861 861
862 862 Settings used when applying patches, for instance through the 'import'
863 863 command or with Mercurial Queues extension.
864 864
865 865 ``eol``
866 866 When set to 'strict' patch content and patched files end of lines
867 867 are preserved. When set to ``lf`` or ``crlf``, both files end of
868 868 lines are ignored when patching and the result line endings are
869 869 normalized to either LF (Unix) or CRLF (Windows). When set to
870 870 ``auto``, end of lines are again ignored while patching but line
871 871 endings in patched files are normalized to their original setting
872 872 on a per-file basis. If target file does not exist or has no end
873 873 of line, patch line endings are preserved.
874 874 Default: strict.
875 875
876 876
877 877 ``paths``
878 878 """""""""
879 879
880 880 Assigns symbolic names to repositories. The left side is the
881 881 symbolic name, and the right gives the directory or URL that is the
882 882 location of the repository. Default paths can be declared by setting
883 883 the following entries.
884 884
885 885 ``default``
886 886 Directory or URL to use when pulling if no source is specified.
887 887 Default is set to repository from which the current repository was
888 888 cloned.
889 889
890 890 ``default-push``
891 891 Optional. Directory or URL to use when pushing if no destination
892 892 is specified.
893 893
894 894
895 895 ``profiling``
896 896 """""""""""""
897 897
898 898 Specifies profiling format and file output. In this section
899 899 description, 'profiling data' stands for the raw data collected
900 900 during profiling, while 'profiling report' stands for a statistical
901 901 text report generated from the profiling data. The profiling is done
902 902 using lsprof.
903 903
904 904 ``format``
905 905 Profiling format.
906 906 Default: text.
907 907
908 908 ``text``
909 909 Generate a profiling report. When saving to a file, it should be
910 910 noted that only the report is saved, and the profiling data is
911 911 not kept.
912 912 ``kcachegrind``
913 913 Format profiling data for kcachegrind use: when saving to a
914 914 file, the generated file can directly be loaded into
915 915 kcachegrind.
916 916
917 917 ``output``
918 918 File path where profiling data or report should be saved. If the
919 919 file exists, it is replaced. Default: None, data is printed on
920 920 stderr
921 921
922 922 ``revsetalias``
923 923 """""""""""""""
924 924
925 925 Alias definitions for revsets. See :hg:`help revsets` for details.
926 926
927 927 ``server``
928 928 """"""""""
929 929
930 930 Controls generic server settings.
931 931
932 932 ``uncompressed``
933 933 Whether to allow clients to clone a repository using the
934 934 uncompressed streaming protocol. This transfers about 40% more
935 935 data than a regular clone, but uses less memory and CPU on both
936 936 server and client. Over a LAN (100 Mbps or better) or a very fast
937 937 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
938 938 regular clone. Over most WAN connections (anything slower than
939 939 about 6 Mbps), uncompressed streaming is slower, because of the
940 940 extra data transfer overhead. This mode will also temporarily hold
941 941 the write lock while determining what data to transfer.
942 942 Default is True.
943 943
944 944 ``validate``
945 945 Whether to validate the completeness of pushed changesets by
946 946 checking that all new file revisions specified in manifests are
947 947 present. Default is False.
948 948
949 949 ``subpaths``
950 950 """"""""""""
951 951
952 952 Defines subrepositories source locations rewriting rules of the form::
953 953
954 954 <pattern> = <replacement>
955 955
956 956 Where ``pattern`` is a regular expression matching the source and
957 957 ``replacement`` is the replacement string used to rewrite it. Groups
958 958 can be matched in ``pattern`` and referenced in ``replacements``. For
959 959 instance::
960 960
961 961 http://server/(.*)-hg/ = http://hg.server/\1/
962 962
963 963 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
964 964
965 965 All patterns are applied in definition order.
966 966
967 967 ``trusted``
968 968 """""""""""
969 969
970 970 Mercurial will not use the settings in the
971 971 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
972 972 user or to a trusted group, as various hgrc features allow arbitrary
973 973 commands to be run. This issue is often encountered when configuring
974 974 hooks or extensions for shared repositories or servers. However,
975 975 the web interface will use some safe settings from the ``[web]``
976 976 section.
977 977
978 978 This section specifies what users and groups are trusted. The
979 979 current user is always trusted. To trust everybody, list a user or a
980 980 group with name ``*``. These settings must be placed in an
981 981 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
982 982 user or service running Mercurial.
983 983
984 984 ``users``
985 985 Comma-separated list of trusted users.
986 986
987 987 ``groups``
988 988 Comma-separated list of trusted groups.
989 989
990 990
991 991 ``ui``
992 992 """"""
993 993
994 994 User interface controls.
995 995
996 996 ``archivemeta``
997 997 Whether to include the .hg_archival.txt file containing meta data
998 998 (hashes for the repository base and for tip) in archives created
999 999 by the :hg:`archive` command or downloaded via hgweb.
1000 1000 Default is True.
1001 1001
1002 1002 ``askusername``
1003 1003 Whether to prompt for a username when committing. If True, and
1004 1004 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1005 1005 be prompted to enter a username. If no username is entered, the
1006 1006 default ``USER@HOST`` is used instead.
1007 1007 Default is False.
1008 1008
1009 1009 ``commitsubrepos``
1010 1010 Whether to commit modified subrepositories when committing the
1011 1011 parent repository. If False and one subrepository has uncommitted
1012 1012 changes, abort the commit.
1013 Default is True.
1013 Default is False.
1014 1014
1015 1015 ``debug``
1016 1016 Print debugging information. True or False. Default is False.
1017 1017
1018 1018 ``editor``
1019 1019 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1020 1020
1021 1021 ``fallbackencoding``
1022 1022 Encoding to try if it's not possible to decode the changelog using
1023 1023 UTF-8. Default is ISO-8859-1.
1024 1024
1025 1025 ``ignore``
1026 1026 A file to read per-user ignore patterns from. This file should be
1027 1027 in the same format as a repository-wide .hgignore file. This
1028 1028 option supports hook syntax, so if you want to specify multiple
1029 1029 ignore files, you can do so by setting something like
1030 1030 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1031 1031 format, see the ``hgignore(5)`` man page.
1032 1032
1033 1033 ``interactive``
1034 1034 Allow to prompt the user. True or False. Default is True.
1035 1035
1036 1036 ``logtemplate``
1037 1037 Template string for commands that print changesets.
1038 1038
1039 1039 ``merge``
1040 1040 The conflict resolution program to use during a manual merge.
1041 1041 For more information on merge tools see :hg:`help merge-tools`.
1042 1042 For configuring merge tools see the ``[merge-tools]`` section.
1043 1043
1044 1044 ``portablefilenames``
1045 1045 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1046 1046 Default is ``warn``.
1047 1047 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1048 1048 platforms, if a file with a non-portable filename is added (e.g. a file
1049 1049 with a name that can't be created on Windows because it contains reserved
1050 1050 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1051 1051 collision with an existing file).
1052 1052 If set to ``ignore`` (or ``false``), no warning is printed.
1053 1053 If set to ``abort``, the command is aborted.
1054 1054 On Windows, this configuration option is ignored and the command aborted.
1055 1055
1056 1056 ``quiet``
1057 1057 Reduce the amount of output printed. True or False. Default is False.
1058 1058
1059 1059 ``remotecmd``
1060 1060 remote command to use for clone/push/pull operations. Default is ``hg``.
1061 1061
1062 1062 ``report_untrusted``
1063 1063 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1064 1064 trusted user or group. True or False. Default is True.
1065 1065
1066 1066 ``slash``
1067 1067 Display paths using a slash (``/``) as the path separator. This
1068 1068 only makes a difference on systems where the default path
1069 1069 separator is not the slash character (e.g. Windows uses the
1070 1070 backslash character (``\``)).
1071 1071 Default is False.
1072 1072
1073 1073 ``ssh``
1074 1074 command to use for SSH connections. Default is ``ssh``.
1075 1075
1076 1076 ``strict``
1077 1077 Require exact command names, instead of allowing unambiguous
1078 1078 abbreviations. True or False. Default is False.
1079 1079
1080 1080 ``style``
1081 1081 Name of style to use for command output.
1082 1082
1083 1083 ``timeout``
1084 1084 The timeout used when a lock is held (in seconds), a negative value
1085 1085 means no timeout. Default is 600.
1086 1086
1087 1087 ``traceback``
1088 1088 Mercurial always prints a traceback when an unknown exception
1089 1089 occurs. Setting this to True will make Mercurial print a traceback
1090 1090 on all exceptions, even those recognized by Mercurial (such as
1091 1091 IOError or MemoryError). Default is False.
1092 1092
1093 1093 ``username``
1094 1094 The committer of a changeset created when running "commit".
1095 1095 Typically a person's name and email address, e.g. ``Fred Widget
1096 1096 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1097 1097 the username in hgrc is empty, it has to be specified manually or
1098 1098 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1099 1099 ``username =`` in the system hgrc). Environment variables in the
1100 1100 username are expanded.
1101 1101
1102 1102 ``verbose``
1103 1103 Increase the amount of output printed. True or False. Default is False.
1104 1104
1105 1105
1106 1106 ``web``
1107 1107 """""""
1108 1108
1109 1109 Web interface configuration. The settings in this section apply to
1110 1110 both the builtin webserver (started by :hg:`serve`) and the script you
1111 1111 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1112 1112 and WSGI).
1113 1113
1114 1114 The Mercurial webserver does no authentication (it does not prompt for
1115 1115 usernames and passwords to validate *who* users are), but it does do
1116 1116 authorization (it grants or denies access for *authenticated users*
1117 1117 based on settings in this section). You must either configure your
1118 1118 webserver to do authentication for you, or disable the authorization
1119 1119 checks.
1120 1120
1121 1121 For a quick setup in a trusted environment, e.g., a private LAN, where
1122 1122 you want it to accept pushes from anybody, you can use the following
1123 1123 command line::
1124 1124
1125 1125 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1126 1126
1127 1127 Note that this will allow anybody to push anything to the server and
1128 1128 that this should not be used for public servers.
1129 1129
1130 1130 The full set of options is:
1131 1131
1132 1132 ``accesslog``
1133 1133 Where to output the access log. Default is stdout.
1134 1134
1135 1135 ``address``
1136 1136 Interface address to bind to. Default is all.
1137 1137
1138 1138 ``allow_archive``
1139 1139 List of archive format (bz2, gz, zip) allowed for downloading.
1140 1140 Default is empty.
1141 1141
1142 1142 ``allowbz2``
1143 1143 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1144 1144 revisions.
1145 1145 Default is False.
1146 1146
1147 1147 ``allowgz``
1148 1148 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1149 1149 revisions.
1150 1150 Default is False.
1151 1151
1152 1152 ``allowpull``
1153 1153 Whether to allow pulling from the repository. Default is True.
1154 1154
1155 1155 ``allow_push``
1156 1156 Whether to allow pushing to the repository. If empty or not set,
1157 1157 push is not allowed. If the special value ``*``, any remote user can
1158 1158 push, including unauthenticated users. Otherwise, the remote user
1159 1159 must have been authenticated, and the authenticated user name must
1160 1160 be present in this list. The contents of the allow_push list are
1161 1161 examined after the deny_push list.
1162 1162
1163 1163 ``guessmime``
1164 1164 Control MIME types for raw download of file content.
1165 1165 Set to True to let hgweb guess the content type from the file
1166 1166 extension. This will serve HTML files as ``text/html`` and might
1167 1167 allow cross-site scripting attacks when serving untrusted
1168 1168 repositories. Default is False.
1169 1169
1170 1170 ``allow_read``
1171 1171 If the user has not already been denied repository access due to
1172 1172 the contents of deny_read, this list determines whether to grant
1173 1173 repository access to the user. If this list is not empty, and the
1174 1174 user is unauthenticated or not present in the list, then access is
1175 1175 denied for the user. If the list is empty or not set, then access
1176 1176 is permitted to all users by default. Setting allow_read to the
1177 1177 special value ``*`` is equivalent to it not being set (i.e. access
1178 1178 is permitted to all users). The contents of the allow_read list are
1179 1179 examined after the deny_read list.
1180 1180
1181 1181 ``allowzip``
1182 1182 (DEPRECATED) Whether to allow .zip downloading of repository
1183 1183 revisions. Default is False. This feature creates temporary files.
1184 1184
1185 1185 ``baseurl``
1186 1186 Base URL to use when publishing URLs in other locations, so
1187 1187 third-party tools like email notification hooks can construct
1188 1188 URLs. Example: ``http://hgserver/repos/``.
1189 1189
1190 1190 ``cacerts``
1191 1191 Path to file containing a list of PEM encoded certificate
1192 1192 authority certificates. Environment variables and ``~user``
1193 1193 constructs are expanded in the filename. If specified on the
1194 1194 client, then it will verify the identity of remote HTTPS servers
1195 1195 with these certificates. The form must be as follows::
1196 1196
1197 1197 -----BEGIN CERTIFICATE-----
1198 1198 ... (certificate in base64 PEM encoding) ...
1199 1199 -----END CERTIFICATE-----
1200 1200 -----BEGIN CERTIFICATE-----
1201 1201 ... (certificate in base64 PEM encoding) ...
1202 1202 -----END CERTIFICATE-----
1203 1203
1204 1204 This feature is only supported when using Python 2.6 or later. If you wish
1205 1205 to use it with earlier versions of Python, install the backported
1206 1206 version of the ssl library that is available from
1207 1207 ``http://pypi.python.org``.
1208 1208
1209 1209 You can use OpenSSL's CA certificate file if your platform has one.
1210 1210 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1211 1211 Otherwise you will have to generate this file manually.
1212 1212
1213 1213 To disable SSL verification temporarily, specify ``--insecure`` from
1214 1214 command line.
1215 1215
1216 1216 ``cache``
1217 1217 Whether to support caching in hgweb. Defaults to True.
1218 1218
1219 1219 ``contact``
1220 1220 Name or email address of the person in charge of the repository.
1221 1221 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1222 1222
1223 1223 ``deny_push``
1224 1224 Whether to deny pushing to the repository. If empty or not set,
1225 1225 push is not denied. If the special value ``*``, all remote users are
1226 1226 denied push. Otherwise, unauthenticated users are all denied, and
1227 1227 any authenticated user name present in this list is also denied. The
1228 1228 contents of the deny_push list are examined before the allow_push list.
1229 1229
1230 1230 ``deny_read``
1231 1231 Whether to deny reading/viewing of the repository. If this list is
1232 1232 not empty, unauthenticated users are all denied, and any
1233 1233 authenticated user name present in this list is also denied access to
1234 1234 the repository. If set to the special value ``*``, all remote users
1235 1235 are denied access (rarely needed ;). If deny_read is empty or not set,
1236 1236 the determination of repository access depends on the presence and
1237 1237 content of the allow_read list (see description). If both
1238 1238 deny_read and allow_read are empty or not set, then access is
1239 1239 permitted to all users by default. If the repository is being
1240 1240 served via hgwebdir, denied users will not be able to see it in
1241 1241 the list of repositories. The contents of the deny_read list have
1242 1242 priority over (are examined before) the contents of the allow_read
1243 1243 list.
1244 1244
1245 1245 ``descend``
1246 1246 hgwebdir indexes will not descend into subdirectories. Only repositories
1247 1247 directly in the current path will be shown (other repositories are still
1248 1248 available from the index corresponding to their containing path).
1249 1249
1250 1250 ``description``
1251 1251 Textual description of the repository's purpose or contents.
1252 1252 Default is "unknown".
1253 1253
1254 1254 ``encoding``
1255 1255 Character encoding name. Default is the current locale charset.
1256 1256 Example: "UTF-8"
1257 1257
1258 1258 ``errorlog``
1259 1259 Where to output the error log. Default is stderr.
1260 1260
1261 1261 ``hidden``
1262 1262 Whether to hide the repository in the hgwebdir index.
1263 1263 Default is False.
1264 1264
1265 1265 ``ipv6``
1266 1266 Whether to use IPv6. Default is False.
1267 1267
1268 1268 ``logoimg``
1269 1269 File name of the logo image that some templates display on each page.
1270 1270 The file name is relative to ``staticurl``. That is, the full path to
1271 1271 the logo image is "staticurl/logoimg".
1272 1272 If unset, ``hglogo.png`` will be used.
1273 1273
1274 1274 ``logourl``
1275 1275 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1276 1276 will be used.
1277 1277
1278 1278 ``name``
1279 1279 Repository name to use in the web interface. Default is current
1280 1280 working directory.
1281 1281
1282 1282 ``maxchanges``
1283 1283 Maximum number of changes to list on the changelog. Default is 10.
1284 1284
1285 1285 ``maxfiles``
1286 1286 Maximum number of files to list per changeset. Default is 10.
1287 1287
1288 1288 ``port``
1289 1289 Port to listen on. Default is 8000.
1290 1290
1291 1291 ``prefix``
1292 1292 Prefix path to serve from. Default is '' (server root).
1293 1293
1294 1294 ``push_ssl``
1295 1295 Whether to require that inbound pushes be transported over SSL to
1296 1296 prevent password sniffing. Default is True.
1297 1297
1298 1298 ``staticurl``
1299 1299 Base URL to use for static files. If unset, static files (e.g. the
1300 1300 hgicon.png favicon) will be served by the CGI script itself. Use
1301 1301 this setting to serve them directly with the HTTP server.
1302 1302 Example: ``http://hgserver/static/``.
1303 1303
1304 1304 ``stripes``
1305 1305 How many lines a "zebra stripe" should span in multiline output.
1306 1306 Default is 1; set to 0 to disable.
1307 1307
1308 1308 ``style``
1309 1309 Which template map style to use.
1310 1310
1311 1311 ``templates``
1312 1312 Where to find the HTML templates. Default is install path.
@@ -1,2084 +1,2085 b''
1 1 # localrepo.py - read/write repository class 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 bin, hex, nullid, nullrev, short
9 9 from i18n import _
10 10 import repo, changegroup, subrepo, discovery, pushkey
11 11 import changelog, dirstate, filelog, manifest, context, bookmarks
12 12 import lock, transaction, store, encoding
13 13 import scmutil, util, extensions, hook, error, revset
14 14 import match as matchmod
15 15 import merge as mergemod
16 16 import tags as tagsmod
17 17 from lock import release
18 18 import weakref, errno, os, time, inspect
19 19 propertycache = util.propertycache
20 20 filecache = scmutil.filecache
21 21
22 22 class localrepository(repo.repository):
23 23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
24 24 'known', 'getbundle'))
25 25 supportedformats = set(('revlogv1', 'generaldelta'))
26 26 supported = supportedformats | set(('store', 'fncache', 'shared',
27 27 'dotencode'))
28 28
29 29 def __init__(self, baseui, path=None, create=False):
30 30 repo.repository.__init__(self)
31 31 self.root = os.path.realpath(util.expandpath(path))
32 32 self.path = os.path.join(self.root, ".hg")
33 33 self.origroot = path
34 34 self.auditor = scmutil.pathauditor(self.root, self._checknested)
35 35 self.opener = scmutil.opener(self.path)
36 36 self.wopener = scmutil.opener(self.root)
37 37 self.baseui = baseui
38 38 self.ui = baseui.copy()
39 39
40 40 try:
41 41 self.ui.readconfig(self.join("hgrc"), self.root)
42 42 extensions.loadall(self.ui)
43 43 except IOError:
44 44 pass
45 45
46 46 if not os.path.isdir(self.path):
47 47 if create:
48 48 if not os.path.exists(path):
49 49 util.makedirs(path)
50 50 util.makedir(self.path, notindexed=True)
51 51 requirements = ["revlogv1"]
52 52 if self.ui.configbool('format', 'usestore', True):
53 53 os.mkdir(os.path.join(self.path, "store"))
54 54 requirements.append("store")
55 55 if self.ui.configbool('format', 'usefncache', True):
56 56 requirements.append("fncache")
57 57 if self.ui.configbool('format', 'dotencode', True):
58 58 requirements.append('dotencode')
59 59 # create an invalid changelog
60 60 self.opener.append(
61 61 "00changelog.i",
62 62 '\0\0\0\2' # represents revlogv2
63 63 ' dummy changelog to prevent using the old repo layout'
64 64 )
65 65 if self.ui.configbool('format', 'generaldelta', False):
66 66 requirements.append("generaldelta")
67 67 requirements = set(requirements)
68 68 else:
69 69 raise error.RepoError(_("repository %s not found") % path)
70 70 elif create:
71 71 raise error.RepoError(_("repository %s already exists") % path)
72 72 else:
73 73 try:
74 74 requirements = scmutil.readrequires(self.opener, self.supported)
75 75 except IOError, inst:
76 76 if inst.errno != errno.ENOENT:
77 77 raise
78 78 requirements = set()
79 79
80 80 self.sharedpath = self.path
81 81 try:
82 82 s = os.path.realpath(self.opener.read("sharedpath").rstrip('\n'))
83 83 if not os.path.exists(s):
84 84 raise error.RepoError(
85 85 _('.hg/sharedpath points to nonexistent directory %s') % s)
86 86 self.sharedpath = s
87 87 except IOError, inst:
88 88 if inst.errno != errno.ENOENT:
89 89 raise
90 90
91 91 self.store = store.store(requirements, self.sharedpath, scmutil.opener)
92 92 self.spath = self.store.path
93 93 self.sopener = self.store.opener
94 94 self.sjoin = self.store.join
95 95 self.opener.createmode = self.store.createmode
96 96 self._applyrequirements(requirements)
97 97 if create:
98 98 self._writerequirements()
99 99
100 100
101 101 self._branchcache = None
102 102 self._branchcachetip = None
103 103 self.filterpats = {}
104 104 self._datafilters = {}
105 105 self._transref = self._lockref = self._wlockref = None
106 106
107 107 # A cache for various files under .hg/ that tracks file changes,
108 108 # (used by the filecache decorator)
109 109 #
110 110 # Maps a property name to its util.filecacheentry
111 111 self._filecache = {}
112 112
113 113 def _applyrequirements(self, requirements):
114 114 self.requirements = requirements
115 115 openerreqs = set(('revlogv1', 'generaldelta'))
116 116 self.sopener.options = dict((r, 1) for r in requirements
117 117 if r in openerreqs)
118 118
119 119 def _writerequirements(self):
120 120 reqfile = self.opener("requires", "w")
121 121 for r in self.requirements:
122 122 reqfile.write("%s\n" % r)
123 123 reqfile.close()
124 124
125 125 def _checknested(self, path):
126 126 """Determine if path is a legal nested repository."""
127 127 if not path.startswith(self.root):
128 128 return False
129 129 subpath = path[len(self.root) + 1:]
130 130
131 131 # XXX: Checking against the current working copy is wrong in
132 132 # the sense that it can reject things like
133 133 #
134 134 # $ hg cat -r 10 sub/x.txt
135 135 #
136 136 # if sub/ is no longer a subrepository in the working copy
137 137 # parent revision.
138 138 #
139 139 # However, it can of course also allow things that would have
140 140 # been rejected before, such as the above cat command if sub/
141 141 # is a subrepository now, but was a normal directory before.
142 142 # The old path auditor would have rejected by mistake since it
143 143 # panics when it sees sub/.hg/.
144 144 #
145 145 # All in all, checking against the working copy seems sensible
146 146 # since we want to prevent access to nested repositories on
147 147 # the filesystem *now*.
148 148 ctx = self[None]
149 149 parts = util.splitpath(subpath)
150 150 while parts:
151 151 prefix = os.sep.join(parts)
152 152 if prefix in ctx.substate:
153 153 if prefix == subpath:
154 154 return True
155 155 else:
156 156 sub = ctx.sub(prefix)
157 157 return sub.checknested(subpath[len(prefix) + 1:])
158 158 else:
159 159 parts.pop()
160 160 return False
161 161
162 162 @filecache('bookmarks')
163 163 def _bookmarks(self):
164 164 return bookmarks.read(self)
165 165
166 166 @filecache('bookmarks.current')
167 167 def _bookmarkcurrent(self):
168 168 return bookmarks.readcurrent(self)
169 169
170 170 def _writebookmarks(self, marks):
171 171 bookmarks.write(self)
172 172
173 173 @filecache('00changelog.i', True)
174 174 def changelog(self):
175 175 c = changelog.changelog(self.sopener)
176 176 if 'HG_PENDING' in os.environ:
177 177 p = os.environ['HG_PENDING']
178 178 if p.startswith(self.root):
179 179 c.readpending('00changelog.i.a')
180 180 return c
181 181
182 182 @filecache('00manifest.i', True)
183 183 def manifest(self):
184 184 return manifest.manifest(self.sopener)
185 185
186 186 @filecache('dirstate')
187 187 def dirstate(self):
188 188 warned = [0]
189 189 def validate(node):
190 190 try:
191 191 self.changelog.rev(node)
192 192 return node
193 193 except error.LookupError:
194 194 if not warned[0]:
195 195 warned[0] = True
196 196 self.ui.warn(_("warning: ignoring unknown"
197 197 " working parent %s!\n") % short(node))
198 198 return nullid
199 199
200 200 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
201 201
202 202 def __getitem__(self, changeid):
203 203 if changeid is None:
204 204 return context.workingctx(self)
205 205 return context.changectx(self, changeid)
206 206
207 207 def __contains__(self, changeid):
208 208 try:
209 209 return bool(self.lookup(changeid))
210 210 except error.RepoLookupError:
211 211 return False
212 212
213 213 def __nonzero__(self):
214 214 return True
215 215
216 216 def __len__(self):
217 217 return len(self.changelog)
218 218
219 219 def __iter__(self):
220 220 for i in xrange(len(self)):
221 221 yield i
222 222
223 223 def set(self, expr, *args):
224 224 '''
225 225 Yield a context for each matching revision, after doing arg
226 226 replacement via revset.formatspec
227 227 '''
228 228
229 229 expr = revset.formatspec(expr, *args)
230 230 m = revset.match(None, expr)
231 231 for r in m(self, range(len(self))):
232 232 yield self[r]
233 233
234 234 def url(self):
235 235 return 'file:' + self.root
236 236
237 237 def hook(self, name, throw=False, **args):
238 238 return hook.hook(self.ui, self, name, throw, **args)
239 239
240 240 tag_disallowed = ':\r\n'
241 241
242 242 def _tag(self, names, node, message, local, user, date, extra={}):
243 243 if isinstance(names, str):
244 244 allchars = names
245 245 names = (names,)
246 246 else:
247 247 allchars = ''.join(names)
248 248 for c in self.tag_disallowed:
249 249 if c in allchars:
250 250 raise util.Abort(_('%r cannot be used in a tag name') % c)
251 251
252 252 branches = self.branchmap()
253 253 for name in names:
254 254 self.hook('pretag', throw=True, node=hex(node), tag=name,
255 255 local=local)
256 256 if name in branches:
257 257 self.ui.warn(_("warning: tag %s conflicts with existing"
258 258 " branch name\n") % name)
259 259
260 260 def writetags(fp, names, munge, prevtags):
261 261 fp.seek(0, 2)
262 262 if prevtags and prevtags[-1] != '\n':
263 263 fp.write('\n')
264 264 for name in names:
265 265 m = munge and munge(name) or name
266 266 if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
267 267 old = self.tags().get(name, nullid)
268 268 fp.write('%s %s\n' % (hex(old), m))
269 269 fp.write('%s %s\n' % (hex(node), m))
270 270 fp.close()
271 271
272 272 prevtags = ''
273 273 if local:
274 274 try:
275 275 fp = self.opener('localtags', 'r+')
276 276 except IOError:
277 277 fp = self.opener('localtags', 'a')
278 278 else:
279 279 prevtags = fp.read()
280 280
281 281 # local tags are stored in the current charset
282 282 writetags(fp, names, None, prevtags)
283 283 for name in names:
284 284 self.hook('tag', node=hex(node), tag=name, local=local)
285 285 return
286 286
287 287 try:
288 288 fp = self.wfile('.hgtags', 'rb+')
289 289 except IOError, e:
290 290 if e.errno != errno.ENOENT:
291 291 raise
292 292 fp = self.wfile('.hgtags', 'ab')
293 293 else:
294 294 prevtags = fp.read()
295 295
296 296 # committed tags are stored in UTF-8
297 297 writetags(fp, names, encoding.fromlocal, prevtags)
298 298
299 299 fp.close()
300 300
301 301 if '.hgtags' not in self.dirstate:
302 302 self[None].add(['.hgtags'])
303 303
304 304 m = matchmod.exact(self.root, '', ['.hgtags'])
305 305 tagnode = self.commit(message, user, date, extra=extra, match=m)
306 306
307 307 for name in names:
308 308 self.hook('tag', node=hex(node), tag=name, local=local)
309 309
310 310 return tagnode
311 311
312 312 def tag(self, names, node, message, local, user, date):
313 313 '''tag a revision with one or more symbolic names.
314 314
315 315 names is a list of strings or, when adding a single tag, names may be a
316 316 string.
317 317
318 318 if local is True, the tags are stored in a per-repository file.
319 319 otherwise, they are stored in the .hgtags file, and a new
320 320 changeset is committed with the change.
321 321
322 322 keyword arguments:
323 323
324 324 local: whether to store tags in non-version-controlled file
325 325 (default False)
326 326
327 327 message: commit message to use if committing
328 328
329 329 user: name of user to use if committing
330 330
331 331 date: date tuple to use if committing'''
332 332
333 333 if not local:
334 334 for x in self.status()[:5]:
335 335 if '.hgtags' in x:
336 336 raise util.Abort(_('working copy of .hgtags is changed '
337 337 '(please commit .hgtags manually)'))
338 338
339 339 self.tags() # instantiate the cache
340 340 self._tag(names, node, message, local, user, date)
341 341
342 342 @propertycache
343 343 def _tagscache(self):
344 344 '''Returns a tagscache object that contains various tags related caches.'''
345 345
346 346 # This simplifies its cache management by having one decorated
347 347 # function (this one) and the rest simply fetch things from it.
348 348 class tagscache(object):
349 349 def __init__(self):
350 350 # These two define the set of tags for this repository. tags
351 351 # maps tag name to node; tagtypes maps tag name to 'global' or
352 352 # 'local'. (Global tags are defined by .hgtags across all
353 353 # heads, and local tags are defined in .hg/localtags.)
354 354 # They constitute the in-memory cache of tags.
355 355 self.tags = self.tagtypes = None
356 356
357 357 self.nodetagscache = self.tagslist = None
358 358
359 359 cache = tagscache()
360 360 cache.tags, cache.tagtypes = self._findtags()
361 361
362 362 return cache
363 363
364 364 def tags(self):
365 365 '''return a mapping of tag to node'''
366 366 return self._tagscache.tags
367 367
368 368 def _findtags(self):
369 369 '''Do the hard work of finding tags. Return a pair of dicts
370 370 (tags, tagtypes) where tags maps tag name to node, and tagtypes
371 371 maps tag name to a string like \'global\' or \'local\'.
372 372 Subclasses or extensions are free to add their own tags, but
373 373 should be aware that the returned dicts will be retained for the
374 374 duration of the localrepo object.'''
375 375
376 376 # XXX what tagtype should subclasses/extensions use? Currently
377 377 # mq and bookmarks add tags, but do not set the tagtype at all.
378 378 # Should each extension invent its own tag type? Should there
379 379 # be one tagtype for all such "virtual" tags? Or is the status
380 380 # quo fine?
381 381
382 382 alltags = {} # map tag name to (node, hist)
383 383 tagtypes = {}
384 384
385 385 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
386 386 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
387 387
388 388 # Build the return dicts. Have to re-encode tag names because
389 389 # the tags module always uses UTF-8 (in order not to lose info
390 390 # writing to the cache), but the rest of Mercurial wants them in
391 391 # local encoding.
392 392 tags = {}
393 393 for (name, (node, hist)) in alltags.iteritems():
394 394 if node != nullid:
395 395 try:
396 396 # ignore tags to unknown nodes
397 397 self.changelog.lookup(node)
398 398 tags[encoding.tolocal(name)] = node
399 399 except error.LookupError:
400 400 pass
401 401 tags['tip'] = self.changelog.tip()
402 402 tagtypes = dict([(encoding.tolocal(name), value)
403 403 for (name, value) in tagtypes.iteritems()])
404 404 return (tags, tagtypes)
405 405
406 406 def tagtype(self, tagname):
407 407 '''
408 408 return the type of the given tag. result can be:
409 409
410 410 'local' : a local tag
411 411 'global' : a global tag
412 412 None : tag does not exist
413 413 '''
414 414
415 415 return self._tagscache.tagtypes.get(tagname)
416 416
417 417 def tagslist(self):
418 418 '''return a list of tags ordered by revision'''
419 419 if not self._tagscache.tagslist:
420 420 l = []
421 421 for t, n in self.tags().iteritems():
422 422 r = self.changelog.rev(n)
423 423 l.append((r, t, n))
424 424 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
425 425
426 426 return self._tagscache.tagslist
427 427
428 428 def nodetags(self, node):
429 429 '''return the tags associated with a node'''
430 430 if not self._tagscache.nodetagscache:
431 431 nodetagscache = {}
432 432 for t, n in self.tags().iteritems():
433 433 nodetagscache.setdefault(n, []).append(t)
434 434 for tags in nodetagscache.itervalues():
435 435 tags.sort()
436 436 self._tagscache.nodetagscache = nodetagscache
437 437 return self._tagscache.nodetagscache.get(node, [])
438 438
439 439 def nodebookmarks(self, node):
440 440 marks = []
441 441 for bookmark, n in self._bookmarks.iteritems():
442 442 if n == node:
443 443 marks.append(bookmark)
444 444 return sorted(marks)
445 445
446 446 def _branchtags(self, partial, lrev):
447 447 # TODO: rename this function?
448 448 tiprev = len(self) - 1
449 449 if lrev != tiprev:
450 450 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
451 451 self._updatebranchcache(partial, ctxgen)
452 452 self._writebranchcache(partial, self.changelog.tip(), tiprev)
453 453
454 454 return partial
455 455
456 456 def updatebranchcache(self):
457 457 tip = self.changelog.tip()
458 458 if self._branchcache is not None and self._branchcachetip == tip:
459 459 return self._branchcache
460 460
461 461 oldtip = self._branchcachetip
462 462 self._branchcachetip = tip
463 463 if oldtip is None or oldtip not in self.changelog.nodemap:
464 464 partial, last, lrev = self._readbranchcache()
465 465 else:
466 466 lrev = self.changelog.rev(oldtip)
467 467 partial = self._branchcache
468 468
469 469 self._branchtags(partial, lrev)
470 470 # this private cache holds all heads (not just tips)
471 471 self._branchcache = partial
472 472
473 473 def branchmap(self):
474 474 '''returns a dictionary {branch: [branchheads]}'''
475 475 self.updatebranchcache()
476 476 return self._branchcache
477 477
478 478 def branchtags(self):
479 479 '''return a dict where branch names map to the tipmost head of
480 480 the branch, open heads come before closed'''
481 481 bt = {}
482 482 for bn, heads in self.branchmap().iteritems():
483 483 tip = heads[-1]
484 484 for h in reversed(heads):
485 485 if 'close' not in self.changelog.read(h)[5]:
486 486 tip = h
487 487 break
488 488 bt[bn] = tip
489 489 return bt
490 490
491 491 def _readbranchcache(self):
492 492 partial = {}
493 493 try:
494 494 f = self.opener("cache/branchheads")
495 495 lines = f.read().split('\n')
496 496 f.close()
497 497 except (IOError, OSError):
498 498 return {}, nullid, nullrev
499 499
500 500 try:
501 501 last, lrev = lines.pop(0).split(" ", 1)
502 502 last, lrev = bin(last), int(lrev)
503 503 if lrev >= len(self) or self[lrev].node() != last:
504 504 # invalidate the cache
505 505 raise ValueError('invalidating branch cache (tip differs)')
506 506 for l in lines:
507 507 if not l:
508 508 continue
509 509 node, label = l.split(" ", 1)
510 510 label = encoding.tolocal(label.strip())
511 511 partial.setdefault(label, []).append(bin(node))
512 512 except KeyboardInterrupt:
513 513 raise
514 514 except Exception, inst:
515 515 if self.ui.debugflag:
516 516 self.ui.warn(str(inst), '\n')
517 517 partial, last, lrev = {}, nullid, nullrev
518 518 return partial, last, lrev
519 519
520 520 def _writebranchcache(self, branches, tip, tiprev):
521 521 try:
522 522 f = self.opener("cache/branchheads", "w", atomictemp=True)
523 523 f.write("%s %s\n" % (hex(tip), tiprev))
524 524 for label, nodes in branches.iteritems():
525 525 for node in nodes:
526 526 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
527 527 f.close()
528 528 except (IOError, OSError):
529 529 pass
530 530
531 531 def _updatebranchcache(self, partial, ctxgen):
532 532 # collect new branch entries
533 533 newbranches = {}
534 534 for c in ctxgen:
535 535 newbranches.setdefault(c.branch(), []).append(c.node())
536 536 # if older branchheads are reachable from new ones, they aren't
537 537 # really branchheads. Note checking parents is insufficient:
538 538 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
539 539 for branch, newnodes in newbranches.iteritems():
540 540 bheads = partial.setdefault(branch, [])
541 541 bheads.extend(newnodes)
542 542 if len(bheads) <= 1:
543 543 continue
544 544 bheads = sorted(bheads, key=lambda x: self[x].rev())
545 545 # starting from tip means fewer passes over reachable
546 546 while newnodes:
547 547 latest = newnodes.pop()
548 548 if latest not in bheads:
549 549 continue
550 550 minbhrev = self[bheads[0]].node()
551 551 reachable = self.changelog.reachable(latest, minbhrev)
552 552 reachable.remove(latest)
553 553 if reachable:
554 554 bheads = [b for b in bheads if b not in reachable]
555 555 partial[branch] = bheads
556 556
557 557 def lookup(self, key):
558 558 if isinstance(key, int):
559 559 return self.changelog.node(key)
560 560 elif key == '.':
561 561 return self.dirstate.p1()
562 562 elif key == 'null':
563 563 return nullid
564 564 elif key == 'tip':
565 565 return self.changelog.tip()
566 566 n = self.changelog._match(key)
567 567 if n:
568 568 return n
569 569 if key in self._bookmarks:
570 570 return self._bookmarks[key]
571 571 if key in self.tags():
572 572 return self.tags()[key]
573 573 if key in self.branchtags():
574 574 return self.branchtags()[key]
575 575 n = self.changelog._partialmatch(key)
576 576 if n:
577 577 return n
578 578
579 579 # can't find key, check if it might have come from damaged dirstate
580 580 if key in self.dirstate.parents():
581 581 raise error.Abort(_("working directory has unknown parent '%s'!")
582 582 % short(key))
583 583 try:
584 584 if len(key) == 20:
585 585 key = hex(key)
586 586 except TypeError:
587 587 pass
588 588 raise error.RepoLookupError(_("unknown revision '%s'") % key)
589 589
590 590 def lookupbranch(self, key, remote=None):
591 591 repo = remote or self
592 592 if key in repo.branchmap():
593 593 return key
594 594
595 595 repo = (remote and remote.local()) and remote or self
596 596 return repo[key].branch()
597 597
598 598 def known(self, nodes):
599 599 nm = self.changelog.nodemap
600 600 return [(n in nm) for n in nodes]
601 601
602 602 def local(self):
603 603 return self
604 604
605 605 def join(self, f):
606 606 return os.path.join(self.path, f)
607 607
608 608 def wjoin(self, f):
609 609 return os.path.join(self.root, f)
610 610
611 611 def file(self, f):
612 612 if f[0] == '/':
613 613 f = f[1:]
614 614 return filelog.filelog(self.sopener, f)
615 615
616 616 def changectx(self, changeid):
617 617 return self[changeid]
618 618
619 619 def parents(self, changeid=None):
620 620 '''get list of changectxs for parents of changeid'''
621 621 return self[changeid].parents()
622 622
623 623 def filectx(self, path, changeid=None, fileid=None):
624 624 """changeid can be a changeset revision, node, or tag.
625 625 fileid can be a file revision or node."""
626 626 return context.filectx(self, path, changeid, fileid)
627 627
628 628 def getcwd(self):
629 629 return self.dirstate.getcwd()
630 630
631 631 def pathto(self, f, cwd=None):
632 632 return self.dirstate.pathto(f, cwd)
633 633
634 634 def wfile(self, f, mode='r'):
635 635 return self.wopener(f, mode)
636 636
637 637 def _link(self, f):
638 638 return os.path.islink(self.wjoin(f))
639 639
640 640 def _loadfilter(self, filter):
641 641 if filter not in self.filterpats:
642 642 l = []
643 643 for pat, cmd in self.ui.configitems(filter):
644 644 if cmd == '!':
645 645 continue
646 646 mf = matchmod.match(self.root, '', [pat])
647 647 fn = None
648 648 params = cmd
649 649 for name, filterfn in self._datafilters.iteritems():
650 650 if cmd.startswith(name):
651 651 fn = filterfn
652 652 params = cmd[len(name):].lstrip()
653 653 break
654 654 if not fn:
655 655 fn = lambda s, c, **kwargs: util.filter(s, c)
656 656 # Wrap old filters not supporting keyword arguments
657 657 if not inspect.getargspec(fn)[2]:
658 658 oldfn = fn
659 659 fn = lambda s, c, **kwargs: oldfn(s, c)
660 660 l.append((mf, fn, params))
661 661 self.filterpats[filter] = l
662 662 return self.filterpats[filter]
663 663
664 664 def _filter(self, filterpats, filename, data):
665 665 for mf, fn, cmd in filterpats:
666 666 if mf(filename):
667 667 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
668 668 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
669 669 break
670 670
671 671 return data
672 672
673 673 @propertycache
674 674 def _encodefilterpats(self):
675 675 return self._loadfilter('encode')
676 676
677 677 @propertycache
678 678 def _decodefilterpats(self):
679 679 return self._loadfilter('decode')
680 680
681 681 def adddatafilter(self, name, filter):
682 682 self._datafilters[name] = filter
683 683
684 684 def wread(self, filename):
685 685 if self._link(filename):
686 686 data = os.readlink(self.wjoin(filename))
687 687 else:
688 688 data = self.wopener.read(filename)
689 689 return self._filter(self._encodefilterpats, filename, data)
690 690
691 691 def wwrite(self, filename, data, flags):
692 692 data = self._filter(self._decodefilterpats, filename, data)
693 693 if 'l' in flags:
694 694 self.wopener.symlink(data, filename)
695 695 else:
696 696 self.wopener.write(filename, data)
697 697 if 'x' in flags:
698 698 util.setflags(self.wjoin(filename), False, True)
699 699
700 700 def wwritedata(self, filename, data):
701 701 return self._filter(self._decodefilterpats, filename, data)
702 702
703 703 def transaction(self, desc):
704 704 tr = self._transref and self._transref() or None
705 705 if tr and tr.running():
706 706 return tr.nest()
707 707
708 708 # abort here if the journal already exists
709 709 if os.path.exists(self.sjoin("journal")):
710 710 raise error.RepoError(
711 711 _("abandoned transaction found - run hg recover"))
712 712
713 713 journalfiles = self._writejournal(desc)
714 714 renames = [(x, undoname(x)) for x in journalfiles]
715 715
716 716 tr = transaction.transaction(self.ui.warn, self.sopener,
717 717 self.sjoin("journal"),
718 718 aftertrans(renames),
719 719 self.store.createmode)
720 720 self._transref = weakref.ref(tr)
721 721 return tr
722 722
723 723 def _writejournal(self, desc):
724 724 # save dirstate for rollback
725 725 try:
726 726 ds = self.opener.read("dirstate")
727 727 except IOError:
728 728 ds = ""
729 729 self.opener.write("journal.dirstate", ds)
730 730 self.opener.write("journal.branch",
731 731 encoding.fromlocal(self.dirstate.branch()))
732 732 self.opener.write("journal.desc",
733 733 "%d\n%s\n" % (len(self), desc))
734 734
735 735 bkname = self.join('bookmarks')
736 736 if os.path.exists(bkname):
737 737 util.copyfile(bkname, self.join('journal.bookmarks'))
738 738 else:
739 739 self.opener.write('journal.bookmarks', '')
740 740
741 741 return (self.sjoin('journal'), self.join('journal.dirstate'),
742 742 self.join('journal.branch'), self.join('journal.desc'),
743 743 self.join('journal.bookmarks'))
744 744
745 745 def recover(self):
746 746 lock = self.lock()
747 747 try:
748 748 if os.path.exists(self.sjoin("journal")):
749 749 self.ui.status(_("rolling back interrupted transaction\n"))
750 750 transaction.rollback(self.sopener, self.sjoin("journal"),
751 751 self.ui.warn)
752 752 self.invalidate()
753 753 return True
754 754 else:
755 755 self.ui.warn(_("no interrupted transaction available\n"))
756 756 return False
757 757 finally:
758 758 lock.release()
759 759
760 760 def rollback(self, dryrun=False, force=False):
761 761 wlock = lock = None
762 762 try:
763 763 wlock = self.wlock()
764 764 lock = self.lock()
765 765 if os.path.exists(self.sjoin("undo")):
766 766 return self._rollback(dryrun, force)
767 767 else:
768 768 self.ui.warn(_("no rollback information available\n"))
769 769 return 1
770 770 finally:
771 771 release(lock, wlock)
772 772
773 773 def _rollback(self, dryrun, force):
774 774 ui = self.ui
775 775 try:
776 776 args = self.opener.read('undo.desc').splitlines()
777 777 (oldlen, desc, detail) = (int(args[0]), args[1], None)
778 778 if len(args) >= 3:
779 779 detail = args[2]
780 780 oldtip = oldlen - 1
781 781
782 782 if detail and ui.verbose:
783 783 msg = (_('repository tip rolled back to revision %s'
784 784 ' (undo %s: %s)\n')
785 785 % (oldtip, desc, detail))
786 786 else:
787 787 msg = (_('repository tip rolled back to revision %s'
788 788 ' (undo %s)\n')
789 789 % (oldtip, desc))
790 790 except IOError:
791 791 msg = _('rolling back unknown transaction\n')
792 792 desc = None
793 793
794 794 if not force and self['.'] != self['tip'] and desc == 'commit':
795 795 raise util.Abort(
796 796 _('rollback of last commit while not checked out '
797 797 'may lose data'), hint=_('use -f to force'))
798 798
799 799 ui.status(msg)
800 800 if dryrun:
801 801 return 0
802 802
803 803 parents = self.dirstate.parents()
804 804 transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
805 805 if os.path.exists(self.join('undo.bookmarks')):
806 806 util.rename(self.join('undo.bookmarks'),
807 807 self.join('bookmarks'))
808 808 self.invalidate()
809 809
810 810 parentgone = (parents[0] not in self.changelog.nodemap or
811 811 parents[1] not in self.changelog.nodemap)
812 812 if parentgone:
813 813 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
814 814 try:
815 815 branch = self.opener.read('undo.branch')
816 816 self.dirstate.setbranch(branch)
817 817 except IOError:
818 818 ui.warn(_('named branch could not be reset: '
819 819 'current branch is still \'%s\'\n')
820 820 % self.dirstate.branch())
821 821
822 822 self.dirstate.invalidate()
823 823 self.destroyed()
824 824 parents = tuple([p.rev() for p in self.parents()])
825 825 if len(parents) > 1:
826 826 ui.status(_('working directory now based on '
827 827 'revisions %d and %d\n') % parents)
828 828 else:
829 829 ui.status(_('working directory now based on '
830 830 'revision %d\n') % parents)
831 831 return 0
832 832
833 833 def invalidatecaches(self):
834 834 try:
835 835 delattr(self, '_tagscache')
836 836 except AttributeError:
837 837 pass
838 838
839 839 self._branchcache = None # in UTF-8
840 840 self._branchcachetip = None
841 841
842 842 def invalidatedirstate(self):
843 843 '''Invalidates the dirstate, causing the next call to dirstate
844 844 to check if it was modified since the last time it was read,
845 845 rereading it if it has.
846 846
847 847 This is different to dirstate.invalidate() that it doesn't always
848 848 rereads the dirstate. Use dirstate.invalidate() if you want to
849 849 explicitly read the dirstate again (i.e. restoring it to a previous
850 850 known good state).'''
851 851 try:
852 852 delattr(self, 'dirstate')
853 853 except AttributeError:
854 854 pass
855 855
856 856 def invalidate(self):
857 857 for k in self._filecache:
858 858 # dirstate is invalidated separately in invalidatedirstate()
859 859 if k == 'dirstate':
860 860 continue
861 861
862 862 try:
863 863 delattr(self, k)
864 864 except AttributeError:
865 865 pass
866 866 self.invalidatecaches()
867 867
868 868 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
869 869 try:
870 870 l = lock.lock(lockname, 0, releasefn, desc=desc)
871 871 except error.LockHeld, inst:
872 872 if not wait:
873 873 raise
874 874 self.ui.warn(_("waiting for lock on %s held by %r\n") %
875 875 (desc, inst.locker))
876 876 # default to 600 seconds timeout
877 877 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
878 878 releasefn, desc=desc)
879 879 if acquirefn:
880 880 acquirefn()
881 881 return l
882 882
883 883 def lock(self, wait=True):
884 884 '''Lock the repository store (.hg/store) and return a weak reference
885 885 to the lock. Use this before modifying the store (e.g. committing or
886 886 stripping). If you are opening a transaction, get a lock as well.)'''
887 887 l = self._lockref and self._lockref()
888 888 if l is not None and l.held:
889 889 l.lock()
890 890 return l
891 891
892 892 def unlock():
893 893 self.store.write()
894 894 for k, ce in self._filecache.items():
895 895 if k == 'dirstate':
896 896 continue
897 897 ce.refresh()
898 898
899 899 l = self._lock(self.sjoin("lock"), wait, unlock,
900 900 self.invalidate, _('repository %s') % self.origroot)
901 901 self._lockref = weakref.ref(l)
902 902 return l
903 903
904 904 def wlock(self, wait=True):
905 905 '''Lock the non-store parts of the repository (everything under
906 906 .hg except .hg/store) and return a weak reference to the lock.
907 907 Use this before modifying files in .hg.'''
908 908 l = self._wlockref and self._wlockref()
909 909 if l is not None and l.held:
910 910 l.lock()
911 911 return l
912 912
913 913 def unlock():
914 914 self.dirstate.write()
915 915 ce = self._filecache.get('dirstate')
916 916 if ce:
917 917 ce.refresh()
918 918
919 919 l = self._lock(self.join("wlock"), wait, unlock,
920 920 self.invalidatedirstate, _('working directory of %s') %
921 921 self.origroot)
922 922 self._wlockref = weakref.ref(l)
923 923 return l
924 924
925 925 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
926 926 """
927 927 commit an individual file as part of a larger transaction
928 928 """
929 929
930 930 fname = fctx.path()
931 931 text = fctx.data()
932 932 flog = self.file(fname)
933 933 fparent1 = manifest1.get(fname, nullid)
934 934 fparent2 = fparent2o = manifest2.get(fname, nullid)
935 935
936 936 meta = {}
937 937 copy = fctx.renamed()
938 938 if copy and copy[0] != fname:
939 939 # Mark the new revision of this file as a copy of another
940 940 # file. This copy data will effectively act as a parent
941 941 # of this new revision. If this is a merge, the first
942 942 # parent will be the nullid (meaning "look up the copy data")
943 943 # and the second one will be the other parent. For example:
944 944 #
945 945 # 0 --- 1 --- 3 rev1 changes file foo
946 946 # \ / rev2 renames foo to bar and changes it
947 947 # \- 2 -/ rev3 should have bar with all changes and
948 948 # should record that bar descends from
949 949 # bar in rev2 and foo in rev1
950 950 #
951 951 # this allows this merge to succeed:
952 952 #
953 953 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
954 954 # \ / merging rev3 and rev4 should use bar@rev2
955 955 # \- 2 --- 4 as the merge base
956 956 #
957 957
958 958 cfname = copy[0]
959 959 crev = manifest1.get(cfname)
960 960 newfparent = fparent2
961 961
962 962 if manifest2: # branch merge
963 963 if fparent2 == nullid or crev is None: # copied on remote side
964 964 if cfname in manifest2:
965 965 crev = manifest2[cfname]
966 966 newfparent = fparent1
967 967
968 968 # find source in nearest ancestor if we've lost track
969 969 if not crev:
970 970 self.ui.debug(" %s: searching for copy revision for %s\n" %
971 971 (fname, cfname))
972 972 for ancestor in self[None].ancestors():
973 973 if cfname in ancestor:
974 974 crev = ancestor[cfname].filenode()
975 975 break
976 976
977 977 if crev:
978 978 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
979 979 meta["copy"] = cfname
980 980 meta["copyrev"] = hex(crev)
981 981 fparent1, fparent2 = nullid, newfparent
982 982 else:
983 983 self.ui.warn(_("warning: can't find ancestor for '%s' "
984 984 "copied from '%s'!\n") % (fname, cfname))
985 985
986 986 elif fparent2 != nullid:
987 987 # is one parent an ancestor of the other?
988 988 fparentancestor = flog.ancestor(fparent1, fparent2)
989 989 if fparentancestor == fparent1:
990 990 fparent1, fparent2 = fparent2, nullid
991 991 elif fparentancestor == fparent2:
992 992 fparent2 = nullid
993 993
994 994 # is the file changed?
995 995 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
996 996 changelist.append(fname)
997 997 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
998 998
999 999 # are just the flags changed during merge?
1000 1000 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
1001 1001 changelist.append(fname)
1002 1002
1003 1003 return fparent1
1004 1004
1005 1005 def commit(self, text="", user=None, date=None, match=None, force=False,
1006 1006 editor=False, extra={}):
1007 1007 """Add a new revision to current repository.
1008 1008
1009 1009 Revision information is gathered from the working directory,
1010 1010 match can be used to filter the committed files. If editor is
1011 1011 supplied, it is called to get a commit message.
1012 1012 """
1013 1013
1014 1014 def fail(f, msg):
1015 1015 raise util.Abort('%s: %s' % (f, msg))
1016 1016
1017 1017 if not match:
1018 1018 match = matchmod.always(self.root, '')
1019 1019
1020 1020 if not force:
1021 1021 vdirs = []
1022 1022 match.dir = vdirs.append
1023 1023 match.bad = fail
1024 1024
1025 1025 wlock = self.wlock()
1026 1026 try:
1027 1027 wctx = self[None]
1028 1028 merge = len(wctx.parents()) > 1
1029 1029
1030 1030 if (not force and merge and match and
1031 1031 (match.files() or match.anypats())):
1032 1032 raise util.Abort(_('cannot partially commit a merge '
1033 1033 '(do not specify files or patterns)'))
1034 1034
1035 1035 changes = self.status(match=match, clean=force)
1036 1036 if force:
1037 1037 changes[0].extend(changes[6]) # mq may commit unchanged files
1038 1038
1039 1039 # check subrepos
1040 1040 subs = []
1041 1041 removedsubs = set()
1042 1042 if '.hgsub' in wctx:
1043 1043 # only manage subrepos and .hgsubstate if .hgsub is present
1044 1044 for p in wctx.parents():
1045 1045 removedsubs.update(s for s in p.substate if match(s))
1046 1046 for s in wctx.substate:
1047 1047 removedsubs.discard(s)
1048 1048 if match(s) and wctx.sub(s).dirty():
1049 1049 subs.append(s)
1050 1050 if (subs or removedsubs):
1051 1051 if (not match('.hgsub') and
1052 1052 '.hgsub' in (wctx.modified() + wctx.added())):
1053 1053 raise util.Abort(
1054 1054 _("can't commit subrepos without .hgsub"))
1055 1055 if '.hgsubstate' not in changes[0]:
1056 1056 changes[0].insert(0, '.hgsubstate')
1057 1057 if '.hgsubstate' in changes[2]:
1058 1058 changes[2].remove('.hgsubstate')
1059 1059 elif '.hgsub' in changes[2]:
1060 1060 # clean up .hgsubstate when .hgsub is removed
1061 1061 if ('.hgsubstate' in wctx and
1062 1062 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1063 1063 changes[2].insert(0, '.hgsubstate')
1064 1064
1065 if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
1065 if subs and not self.ui.configbool('ui', 'commitsubrepos', False):
1066 1066 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
1067 1067 if changedsubs:
1068 1068 raise util.Abort(_("uncommitted changes in subrepo %s")
1069 % changedsubs[0])
1069 % changedsubs[0],
1070 hint=_("use --subrepos for recursive commit"))
1070 1071
1071 1072 # make sure all explicit patterns are matched
1072 1073 if not force and match.files():
1073 1074 matched = set(changes[0] + changes[1] + changes[2])
1074 1075
1075 1076 for f in match.files():
1076 1077 if f == '.' or f in matched or f in wctx.substate:
1077 1078 continue
1078 1079 if f in changes[3]: # missing
1079 1080 fail(f, _('file not found!'))
1080 1081 if f in vdirs: # visited directory
1081 1082 d = f + '/'
1082 1083 for mf in matched:
1083 1084 if mf.startswith(d):
1084 1085 break
1085 1086 else:
1086 1087 fail(f, _("no match under directory!"))
1087 1088 elif f not in self.dirstate:
1088 1089 fail(f, _("file not tracked!"))
1089 1090
1090 1091 if (not force and not extra.get("close") and not merge
1091 1092 and not (changes[0] or changes[1] or changes[2])
1092 1093 and wctx.branch() == wctx.p1().branch()):
1093 1094 return None
1094 1095
1095 1096 ms = mergemod.mergestate(self)
1096 1097 for f in changes[0]:
1097 1098 if f in ms and ms[f] == 'u':
1098 1099 raise util.Abort(_("unresolved merge conflicts "
1099 1100 "(see hg help resolve)"))
1100 1101
1101 1102 cctx = context.workingctx(self, text, user, date, extra, changes)
1102 1103 if editor:
1103 1104 cctx._text = editor(self, cctx, subs)
1104 1105 edited = (text != cctx._text)
1105 1106
1106 1107 # commit subs
1107 1108 if subs or removedsubs:
1108 1109 state = wctx.substate.copy()
1109 1110 for s in sorted(subs):
1110 1111 sub = wctx.sub(s)
1111 1112 self.ui.status(_('committing subrepository %s\n') %
1112 1113 subrepo.subrelpath(sub))
1113 1114 sr = sub.commit(cctx._text, user, date)
1114 1115 state[s] = (state[s][0], sr)
1115 1116 subrepo.writestate(self, state)
1116 1117
1117 1118 # Save commit message in case this transaction gets rolled back
1118 1119 # (e.g. by a pretxncommit hook). Leave the content alone on
1119 1120 # the assumption that the user will use the same editor again.
1120 1121 msgfn = self.savecommitmessage(cctx._text)
1121 1122
1122 1123 p1, p2 = self.dirstate.parents()
1123 1124 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1124 1125 try:
1125 1126 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1126 1127 ret = self.commitctx(cctx, True)
1127 1128 except:
1128 1129 if edited:
1129 1130 self.ui.write(
1130 1131 _('note: commit message saved in %s\n') % msgfn)
1131 1132 raise
1132 1133
1133 1134 # update bookmarks, dirstate and mergestate
1134 1135 bookmarks.update(self, p1, ret)
1135 1136 for f in changes[0] + changes[1]:
1136 1137 self.dirstate.normal(f)
1137 1138 for f in changes[2]:
1138 1139 self.dirstate.drop(f)
1139 1140 self.dirstate.setparents(ret)
1140 1141 ms.reset()
1141 1142 finally:
1142 1143 wlock.release()
1143 1144
1144 1145 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1145 1146 return ret
1146 1147
1147 1148 def commitctx(self, ctx, error=False):
1148 1149 """Add a new revision to current repository.
1149 1150 Revision information is passed via the context argument.
1150 1151 """
1151 1152
1152 1153 tr = lock = None
1153 1154 removed = list(ctx.removed())
1154 1155 p1, p2 = ctx.p1(), ctx.p2()
1155 1156 user = ctx.user()
1156 1157
1157 1158 lock = self.lock()
1158 1159 try:
1159 1160 tr = self.transaction("commit")
1160 1161 trp = weakref.proxy(tr)
1161 1162
1162 1163 if ctx.files():
1163 1164 m1 = p1.manifest().copy()
1164 1165 m2 = p2.manifest()
1165 1166
1166 1167 # check in files
1167 1168 new = {}
1168 1169 changed = []
1169 1170 linkrev = len(self)
1170 1171 for f in sorted(ctx.modified() + ctx.added()):
1171 1172 self.ui.note(f + "\n")
1172 1173 try:
1173 1174 fctx = ctx[f]
1174 1175 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1175 1176 changed)
1176 1177 m1.set(f, fctx.flags())
1177 1178 except OSError, inst:
1178 1179 self.ui.warn(_("trouble committing %s!\n") % f)
1179 1180 raise
1180 1181 except IOError, inst:
1181 1182 errcode = getattr(inst, 'errno', errno.ENOENT)
1182 1183 if error or errcode and errcode != errno.ENOENT:
1183 1184 self.ui.warn(_("trouble committing %s!\n") % f)
1184 1185 raise
1185 1186 else:
1186 1187 removed.append(f)
1187 1188
1188 1189 # update manifest
1189 1190 m1.update(new)
1190 1191 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1191 1192 drop = [f for f in removed if f in m1]
1192 1193 for f in drop:
1193 1194 del m1[f]
1194 1195 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1195 1196 p2.manifestnode(), (new, drop))
1196 1197 files = changed + removed
1197 1198 else:
1198 1199 mn = p1.manifestnode()
1199 1200 files = []
1200 1201
1201 1202 # update changelog
1202 1203 self.changelog.delayupdate()
1203 1204 n = self.changelog.add(mn, files, ctx.description(),
1204 1205 trp, p1.node(), p2.node(),
1205 1206 user, ctx.date(), ctx.extra().copy())
1206 1207 p = lambda: self.changelog.writepending() and self.root or ""
1207 1208 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1208 1209 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1209 1210 parent2=xp2, pending=p)
1210 1211 self.changelog.finalize(trp)
1211 1212 tr.close()
1212 1213
1213 1214 if self._branchcache:
1214 1215 self.updatebranchcache()
1215 1216 return n
1216 1217 finally:
1217 1218 if tr:
1218 1219 tr.release()
1219 1220 lock.release()
1220 1221
1221 1222 def destroyed(self):
1222 1223 '''Inform the repository that nodes have been destroyed.
1223 1224 Intended for use by strip and rollback, so there's a common
1224 1225 place for anything that has to be done after destroying history.'''
1225 1226 # XXX it might be nice if we could take the list of destroyed
1226 1227 # nodes, but I don't see an easy way for rollback() to do that
1227 1228
1228 1229 # Ensure the persistent tag cache is updated. Doing it now
1229 1230 # means that the tag cache only has to worry about destroyed
1230 1231 # heads immediately after a strip/rollback. That in turn
1231 1232 # guarantees that "cachetip == currenttip" (comparing both rev
1232 1233 # and node) always means no nodes have been added or destroyed.
1233 1234
1234 1235 # XXX this is suboptimal when qrefresh'ing: we strip the current
1235 1236 # head, refresh the tag cache, then immediately add a new head.
1236 1237 # But I think doing it this way is necessary for the "instant
1237 1238 # tag cache retrieval" case to work.
1238 1239 self.invalidatecaches()
1239 1240
1240 1241 def walk(self, match, node=None):
1241 1242 '''
1242 1243 walk recursively through the directory tree or a given
1243 1244 changeset, finding all files matched by the match
1244 1245 function
1245 1246 '''
1246 1247 return self[node].walk(match)
1247 1248
1248 1249 def status(self, node1='.', node2=None, match=None,
1249 1250 ignored=False, clean=False, unknown=False,
1250 1251 listsubrepos=False):
1251 1252 """return status of files between two nodes or node and working directory
1252 1253
1253 1254 If node1 is None, use the first dirstate parent instead.
1254 1255 If node2 is None, compare node1 with working directory.
1255 1256 """
1256 1257
1257 1258 def mfmatches(ctx):
1258 1259 mf = ctx.manifest().copy()
1259 1260 for fn in mf.keys():
1260 1261 if not match(fn):
1261 1262 del mf[fn]
1262 1263 return mf
1263 1264
1264 1265 if isinstance(node1, context.changectx):
1265 1266 ctx1 = node1
1266 1267 else:
1267 1268 ctx1 = self[node1]
1268 1269 if isinstance(node2, context.changectx):
1269 1270 ctx2 = node2
1270 1271 else:
1271 1272 ctx2 = self[node2]
1272 1273
1273 1274 working = ctx2.rev() is None
1274 1275 parentworking = working and ctx1 == self['.']
1275 1276 match = match or matchmod.always(self.root, self.getcwd())
1276 1277 listignored, listclean, listunknown = ignored, clean, unknown
1277 1278
1278 1279 # load earliest manifest first for caching reasons
1279 1280 if not working and ctx2.rev() < ctx1.rev():
1280 1281 ctx2.manifest()
1281 1282
1282 1283 if not parentworking:
1283 1284 def bad(f, msg):
1284 1285 if f not in ctx1:
1285 1286 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1286 1287 match.bad = bad
1287 1288
1288 1289 if working: # we need to scan the working dir
1289 1290 subrepos = []
1290 1291 if '.hgsub' in self.dirstate:
1291 1292 subrepos = ctx2.substate.keys()
1292 1293 s = self.dirstate.status(match, subrepos, listignored,
1293 1294 listclean, listunknown)
1294 1295 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1295 1296
1296 1297 # check for any possibly clean files
1297 1298 if parentworking and cmp:
1298 1299 fixup = []
1299 1300 # do a full compare of any files that might have changed
1300 1301 for f in sorted(cmp):
1301 1302 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1302 1303 or ctx1[f].cmp(ctx2[f])):
1303 1304 modified.append(f)
1304 1305 else:
1305 1306 fixup.append(f)
1306 1307
1307 1308 # update dirstate for files that are actually clean
1308 1309 if fixup:
1309 1310 if listclean:
1310 1311 clean += fixup
1311 1312
1312 1313 try:
1313 1314 # updating the dirstate is optional
1314 1315 # so we don't wait on the lock
1315 1316 wlock = self.wlock(False)
1316 1317 try:
1317 1318 for f in fixup:
1318 1319 self.dirstate.normal(f)
1319 1320 finally:
1320 1321 wlock.release()
1321 1322 except error.LockError:
1322 1323 pass
1323 1324
1324 1325 if not parentworking:
1325 1326 mf1 = mfmatches(ctx1)
1326 1327 if working:
1327 1328 # we are comparing working dir against non-parent
1328 1329 # generate a pseudo-manifest for the working dir
1329 1330 mf2 = mfmatches(self['.'])
1330 1331 for f in cmp + modified + added:
1331 1332 mf2[f] = None
1332 1333 mf2.set(f, ctx2.flags(f))
1333 1334 for f in removed:
1334 1335 if f in mf2:
1335 1336 del mf2[f]
1336 1337 else:
1337 1338 # we are comparing two revisions
1338 1339 deleted, unknown, ignored = [], [], []
1339 1340 mf2 = mfmatches(ctx2)
1340 1341
1341 1342 modified, added, clean = [], [], []
1342 1343 for fn in mf2:
1343 1344 if fn in mf1:
1344 1345 if (fn not in deleted and
1345 1346 (mf1.flags(fn) != mf2.flags(fn) or
1346 1347 (mf1[fn] != mf2[fn] and
1347 1348 (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
1348 1349 modified.append(fn)
1349 1350 elif listclean:
1350 1351 clean.append(fn)
1351 1352 del mf1[fn]
1352 1353 elif fn not in deleted:
1353 1354 added.append(fn)
1354 1355 removed = mf1.keys()
1355 1356
1356 1357 r = modified, added, removed, deleted, unknown, ignored, clean
1357 1358
1358 1359 if listsubrepos:
1359 1360 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1360 1361 if working:
1361 1362 rev2 = None
1362 1363 else:
1363 1364 rev2 = ctx2.substate[subpath][1]
1364 1365 try:
1365 1366 submatch = matchmod.narrowmatcher(subpath, match)
1366 1367 s = sub.status(rev2, match=submatch, ignored=listignored,
1367 1368 clean=listclean, unknown=listunknown,
1368 1369 listsubrepos=True)
1369 1370 for rfiles, sfiles in zip(r, s):
1370 1371 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1371 1372 except error.LookupError:
1372 1373 self.ui.status(_("skipping missing subrepository: %s\n")
1373 1374 % subpath)
1374 1375
1375 1376 for l in r:
1376 1377 l.sort()
1377 1378 return r
1378 1379
1379 1380 def heads(self, start=None):
1380 1381 heads = self.changelog.heads(start)
1381 1382 # sort the output in rev descending order
1382 1383 return sorted(heads, key=self.changelog.rev, reverse=True)
1383 1384
1384 1385 def branchheads(self, branch=None, start=None, closed=False):
1385 1386 '''return a (possibly filtered) list of heads for the given branch
1386 1387
1387 1388 Heads are returned in topological order, from newest to oldest.
1388 1389 If branch is None, use the dirstate branch.
1389 1390 If start is not None, return only heads reachable from start.
1390 1391 If closed is True, return heads that are marked as closed as well.
1391 1392 '''
1392 1393 if branch is None:
1393 1394 branch = self[None].branch()
1394 1395 branches = self.branchmap()
1395 1396 if branch not in branches:
1396 1397 return []
1397 1398 # the cache returns heads ordered lowest to highest
1398 1399 bheads = list(reversed(branches[branch]))
1399 1400 if start is not None:
1400 1401 # filter out the heads that cannot be reached from startrev
1401 1402 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1402 1403 bheads = [h for h in bheads if h in fbheads]
1403 1404 if not closed:
1404 1405 bheads = [h for h in bheads if
1405 1406 ('close' not in self.changelog.read(h)[5])]
1406 1407 return bheads
1407 1408
1408 1409 def branches(self, nodes):
1409 1410 if not nodes:
1410 1411 nodes = [self.changelog.tip()]
1411 1412 b = []
1412 1413 for n in nodes:
1413 1414 t = n
1414 1415 while True:
1415 1416 p = self.changelog.parents(n)
1416 1417 if p[1] != nullid or p[0] == nullid:
1417 1418 b.append((t, n, p[0], p[1]))
1418 1419 break
1419 1420 n = p[0]
1420 1421 return b
1421 1422
1422 1423 def between(self, pairs):
1423 1424 r = []
1424 1425
1425 1426 for top, bottom in pairs:
1426 1427 n, l, i = top, [], 0
1427 1428 f = 1
1428 1429
1429 1430 while n != bottom and n != nullid:
1430 1431 p = self.changelog.parents(n)[0]
1431 1432 if i == f:
1432 1433 l.append(n)
1433 1434 f = f * 2
1434 1435 n = p
1435 1436 i += 1
1436 1437
1437 1438 r.append(l)
1438 1439
1439 1440 return r
1440 1441
1441 1442 def pull(self, remote, heads=None, force=False):
1442 1443 lock = self.lock()
1443 1444 try:
1444 1445 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1445 1446 force=force)
1446 1447 common, fetch, rheads = tmp
1447 1448 if not fetch:
1448 1449 self.ui.status(_("no changes found\n"))
1449 1450 result = 0
1450 1451 else:
1451 1452 if heads is None and list(common) == [nullid]:
1452 1453 self.ui.status(_("requesting all changes\n"))
1453 1454 elif heads is None and remote.capable('changegroupsubset'):
1454 1455 # issue1320, avoid a race if remote changed after discovery
1455 1456 heads = rheads
1456 1457
1457 1458 if remote.capable('getbundle'):
1458 1459 cg = remote.getbundle('pull', common=common,
1459 1460 heads=heads or rheads)
1460 1461 elif heads is None:
1461 1462 cg = remote.changegroup(fetch, 'pull')
1462 1463 elif not remote.capable('changegroupsubset'):
1463 1464 raise util.Abort(_("partial pull cannot be done because "
1464 1465 "other repository doesn't support "
1465 1466 "changegroupsubset."))
1466 1467 else:
1467 1468 cg = remote.changegroupsubset(fetch, heads, 'pull')
1468 1469 result = self.addchangegroup(cg, 'pull', remote.url(),
1469 1470 lock=lock)
1470 1471 finally:
1471 1472 lock.release()
1472 1473
1473 1474 return result
1474 1475
1475 1476 def checkpush(self, force, revs):
1476 1477 """Extensions can override this function if additional checks have
1477 1478 to be performed before pushing, or call it if they override push
1478 1479 command.
1479 1480 """
1480 1481 pass
1481 1482
1482 1483 def push(self, remote, force=False, revs=None, newbranch=False):
1483 1484 '''Push outgoing changesets (limited by revs) from the current
1484 1485 repository to remote. Return an integer:
1485 1486 - 0 means HTTP error *or* nothing to push
1486 1487 - 1 means we pushed and remote head count is unchanged *or*
1487 1488 we have outgoing changesets but refused to push
1488 1489 - other values as described by addchangegroup()
1489 1490 '''
1490 1491 # there are two ways to push to remote repo:
1491 1492 #
1492 1493 # addchangegroup assumes local user can lock remote
1493 1494 # repo (local filesystem, old ssh servers).
1494 1495 #
1495 1496 # unbundle assumes local user cannot lock remote repo (new ssh
1496 1497 # servers, http servers).
1497 1498
1498 1499 self.checkpush(force, revs)
1499 1500 lock = None
1500 1501 unbundle = remote.capable('unbundle')
1501 1502 if not unbundle:
1502 1503 lock = remote.lock()
1503 1504 try:
1504 1505 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1505 1506 newbranch)
1506 1507 ret = remote_heads
1507 1508 if cg is not None:
1508 1509 if unbundle:
1509 1510 # local repo finds heads on server, finds out what
1510 1511 # revs it must push. once revs transferred, if server
1511 1512 # finds it has different heads (someone else won
1512 1513 # commit/push race), server aborts.
1513 1514 if force:
1514 1515 remote_heads = ['force']
1515 1516 # ssh: return remote's addchangegroup()
1516 1517 # http: return remote's addchangegroup() or 0 for error
1517 1518 ret = remote.unbundle(cg, remote_heads, 'push')
1518 1519 else:
1519 1520 # we return an integer indicating remote head count change
1520 1521 ret = remote.addchangegroup(cg, 'push', self.url(),
1521 1522 lock=lock)
1522 1523 finally:
1523 1524 if lock is not None:
1524 1525 lock.release()
1525 1526
1526 1527 self.ui.debug("checking for updated bookmarks\n")
1527 1528 rb = remote.listkeys('bookmarks')
1528 1529 for k in rb.keys():
1529 1530 if k in self._bookmarks:
1530 1531 nr, nl = rb[k], hex(self._bookmarks[k])
1531 1532 if nr in self:
1532 1533 cr = self[nr]
1533 1534 cl = self[nl]
1534 1535 if cl in cr.descendants():
1535 1536 r = remote.pushkey('bookmarks', k, nr, nl)
1536 1537 if r:
1537 1538 self.ui.status(_("updating bookmark %s\n") % k)
1538 1539 else:
1539 1540 self.ui.warn(_('updating bookmark %s'
1540 1541 ' failed!\n') % k)
1541 1542
1542 1543 return ret
1543 1544
1544 1545 def changegroupinfo(self, nodes, source):
1545 1546 if self.ui.verbose or source == 'bundle':
1546 1547 self.ui.status(_("%d changesets found\n") % len(nodes))
1547 1548 if self.ui.debugflag:
1548 1549 self.ui.debug("list of changesets:\n")
1549 1550 for node in nodes:
1550 1551 self.ui.debug("%s\n" % hex(node))
1551 1552
1552 1553 def changegroupsubset(self, bases, heads, source):
1553 1554 """Compute a changegroup consisting of all the nodes that are
1554 1555 descendants of any of the bases and ancestors of any of the heads.
1555 1556 Return a chunkbuffer object whose read() method will return
1556 1557 successive changegroup chunks.
1557 1558
1558 1559 It is fairly complex as determining which filenodes and which
1559 1560 manifest nodes need to be included for the changeset to be complete
1560 1561 is non-trivial.
1561 1562
1562 1563 Another wrinkle is doing the reverse, figuring out which changeset in
1563 1564 the changegroup a particular filenode or manifestnode belongs to.
1564 1565 """
1565 1566 cl = self.changelog
1566 1567 if not bases:
1567 1568 bases = [nullid]
1568 1569 csets, bases, heads = cl.nodesbetween(bases, heads)
1569 1570 # We assume that all ancestors of bases are known
1570 1571 common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1571 1572 return self._changegroupsubset(common, csets, heads, source)
1572 1573
1573 1574 def getbundle(self, source, heads=None, common=None):
1574 1575 """Like changegroupsubset, but returns the set difference between the
1575 1576 ancestors of heads and the ancestors common.
1576 1577
1577 1578 If heads is None, use the local heads. If common is None, use [nullid].
1578 1579
1579 1580 The nodes in common might not all be known locally due to the way the
1580 1581 current discovery protocol works.
1581 1582 """
1582 1583 cl = self.changelog
1583 1584 if common:
1584 1585 nm = cl.nodemap
1585 1586 common = [n for n in common if n in nm]
1586 1587 else:
1587 1588 common = [nullid]
1588 1589 if not heads:
1589 1590 heads = cl.heads()
1590 1591 common, missing = cl.findcommonmissing(common, heads)
1591 1592 if not missing:
1592 1593 return None
1593 1594 return self._changegroupsubset(common, missing, heads, source)
1594 1595
1595 1596 def _changegroupsubset(self, commonrevs, csets, heads, source):
1596 1597
1597 1598 cl = self.changelog
1598 1599 mf = self.manifest
1599 1600 mfs = {} # needed manifests
1600 1601 fnodes = {} # needed file nodes
1601 1602 changedfiles = set()
1602 1603 fstate = ['', {}]
1603 1604 count = [0]
1604 1605
1605 1606 # can we go through the fast path ?
1606 1607 heads.sort()
1607 1608 if heads == sorted(self.heads()):
1608 1609 return self._changegroup(csets, source)
1609 1610
1610 1611 # slow path
1611 1612 self.hook('preoutgoing', throw=True, source=source)
1612 1613 self.changegroupinfo(csets, source)
1613 1614
1614 1615 # filter any nodes that claim to be part of the known set
1615 1616 def prune(revlog, missing):
1616 1617 return [n for n in missing
1617 1618 if revlog.linkrev(revlog.rev(n)) not in commonrevs]
1618 1619
1619 1620 def lookup(revlog, x):
1620 1621 if revlog == cl:
1621 1622 c = cl.read(x)
1622 1623 changedfiles.update(c[3])
1623 1624 mfs.setdefault(c[0], x)
1624 1625 count[0] += 1
1625 1626 self.ui.progress(_('bundling'), count[0],
1626 1627 unit=_('changesets'), total=len(csets))
1627 1628 return x
1628 1629 elif revlog == mf:
1629 1630 clnode = mfs[x]
1630 1631 mdata = mf.readfast(x)
1631 1632 for f in changedfiles:
1632 1633 if f in mdata:
1633 1634 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1634 1635 count[0] += 1
1635 1636 self.ui.progress(_('bundling'), count[0],
1636 1637 unit=_('manifests'), total=len(mfs))
1637 1638 return mfs[x]
1638 1639 else:
1639 1640 self.ui.progress(
1640 1641 _('bundling'), count[0], item=fstate[0],
1641 1642 unit=_('files'), total=len(changedfiles))
1642 1643 return fstate[1][x]
1643 1644
1644 1645 bundler = changegroup.bundle10(lookup)
1645 1646 reorder = self.ui.config('bundle', 'reorder', 'auto')
1646 1647 if reorder == 'auto':
1647 1648 reorder = None
1648 1649 else:
1649 1650 reorder = util.parsebool(reorder)
1650 1651
1651 1652 def gengroup():
1652 1653 # Create a changenode group generator that will call our functions
1653 1654 # back to lookup the owning changenode and collect information.
1654 1655 for chunk in cl.group(csets, bundler, reorder=reorder):
1655 1656 yield chunk
1656 1657 self.ui.progress(_('bundling'), None)
1657 1658
1658 1659 # Create a generator for the manifestnodes that calls our lookup
1659 1660 # and data collection functions back.
1660 1661 count[0] = 0
1661 1662 for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder):
1662 1663 yield chunk
1663 1664 self.ui.progress(_('bundling'), None)
1664 1665
1665 1666 mfs.clear()
1666 1667
1667 1668 # Go through all our files in order sorted by name.
1668 1669 count[0] = 0
1669 1670 for fname in sorted(changedfiles):
1670 1671 filerevlog = self.file(fname)
1671 1672 if not len(filerevlog):
1672 1673 raise util.Abort(_("empty or missing revlog for %s") % fname)
1673 1674 fstate[0] = fname
1674 1675 fstate[1] = fnodes.pop(fname, {})
1675 1676
1676 1677 nodelist = prune(filerevlog, fstate[1])
1677 1678 if nodelist:
1678 1679 count[0] += 1
1679 1680 yield bundler.fileheader(fname)
1680 1681 for chunk in filerevlog.group(nodelist, bundler, reorder):
1681 1682 yield chunk
1682 1683
1683 1684 # Signal that no more groups are left.
1684 1685 yield bundler.close()
1685 1686 self.ui.progress(_('bundling'), None)
1686 1687
1687 1688 if csets:
1688 1689 self.hook('outgoing', node=hex(csets[0]), source=source)
1689 1690
1690 1691 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1691 1692
1692 1693 def changegroup(self, basenodes, source):
1693 1694 # to avoid a race we use changegroupsubset() (issue1320)
1694 1695 return self.changegroupsubset(basenodes, self.heads(), source)
1695 1696
1696 1697 def _changegroup(self, nodes, source):
1697 1698 """Compute the changegroup of all nodes that we have that a recipient
1698 1699 doesn't. Return a chunkbuffer object whose read() method will return
1699 1700 successive changegroup chunks.
1700 1701
1701 1702 This is much easier than the previous function as we can assume that
1702 1703 the recipient has any changenode we aren't sending them.
1703 1704
1704 1705 nodes is the set of nodes to send"""
1705 1706
1706 1707 cl = self.changelog
1707 1708 mf = self.manifest
1708 1709 mfs = {}
1709 1710 changedfiles = set()
1710 1711 fstate = ['']
1711 1712 count = [0]
1712 1713
1713 1714 self.hook('preoutgoing', throw=True, source=source)
1714 1715 self.changegroupinfo(nodes, source)
1715 1716
1716 1717 revset = set([cl.rev(n) for n in nodes])
1717 1718
1718 1719 def gennodelst(log):
1719 1720 return [log.node(r) for r in log if log.linkrev(r) in revset]
1720 1721
1721 1722 def lookup(revlog, x):
1722 1723 if revlog == cl:
1723 1724 c = cl.read(x)
1724 1725 changedfiles.update(c[3])
1725 1726 mfs.setdefault(c[0], x)
1726 1727 count[0] += 1
1727 1728 self.ui.progress(_('bundling'), count[0],
1728 1729 unit=_('changesets'), total=len(nodes))
1729 1730 return x
1730 1731 elif revlog == mf:
1731 1732 count[0] += 1
1732 1733 self.ui.progress(_('bundling'), count[0],
1733 1734 unit=_('manifests'), total=len(mfs))
1734 1735 return cl.node(revlog.linkrev(revlog.rev(x)))
1735 1736 else:
1736 1737 self.ui.progress(
1737 1738 _('bundling'), count[0], item=fstate[0],
1738 1739 total=len(changedfiles), unit=_('files'))
1739 1740 return cl.node(revlog.linkrev(revlog.rev(x)))
1740 1741
1741 1742 bundler = changegroup.bundle10(lookup)
1742 1743 reorder = self.ui.config('bundle', 'reorder', 'auto')
1743 1744 if reorder == 'auto':
1744 1745 reorder = None
1745 1746 else:
1746 1747 reorder = util.parsebool(reorder)
1747 1748
1748 1749 def gengroup():
1749 1750 '''yield a sequence of changegroup chunks (strings)'''
1750 1751 # construct a list of all changed files
1751 1752
1752 1753 for chunk in cl.group(nodes, bundler, reorder=reorder):
1753 1754 yield chunk
1754 1755 self.ui.progress(_('bundling'), None)
1755 1756
1756 1757 count[0] = 0
1757 1758 for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder):
1758 1759 yield chunk
1759 1760 self.ui.progress(_('bundling'), None)
1760 1761
1761 1762 count[0] = 0
1762 1763 for fname in sorted(changedfiles):
1763 1764 filerevlog = self.file(fname)
1764 1765 if not len(filerevlog):
1765 1766 raise util.Abort(_("empty or missing revlog for %s") % fname)
1766 1767 fstate[0] = fname
1767 1768 nodelist = gennodelst(filerevlog)
1768 1769 if nodelist:
1769 1770 count[0] += 1
1770 1771 yield bundler.fileheader(fname)
1771 1772 for chunk in filerevlog.group(nodelist, bundler, reorder):
1772 1773 yield chunk
1773 1774 yield bundler.close()
1774 1775 self.ui.progress(_('bundling'), None)
1775 1776
1776 1777 if nodes:
1777 1778 self.hook('outgoing', node=hex(nodes[0]), source=source)
1778 1779
1779 1780 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1780 1781
1781 1782 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1782 1783 """Add the changegroup returned by source.read() to this repo.
1783 1784 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1784 1785 the URL of the repo where this changegroup is coming from.
1785 1786 If lock is not None, the function takes ownership of the lock
1786 1787 and releases it after the changegroup is added.
1787 1788
1788 1789 Return an integer summarizing the change to this repo:
1789 1790 - nothing changed or no source: 0
1790 1791 - more heads than before: 1+added heads (2..n)
1791 1792 - fewer heads than before: -1-removed heads (-2..-n)
1792 1793 - number of heads stays the same: 1
1793 1794 """
1794 1795 def csmap(x):
1795 1796 self.ui.debug("add changeset %s\n" % short(x))
1796 1797 return len(cl)
1797 1798
1798 1799 def revmap(x):
1799 1800 return cl.rev(x)
1800 1801
1801 1802 if not source:
1802 1803 return 0
1803 1804
1804 1805 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1805 1806
1806 1807 changesets = files = revisions = 0
1807 1808 efiles = set()
1808 1809
1809 1810 # write changelog data to temp files so concurrent readers will not see
1810 1811 # inconsistent view
1811 1812 cl = self.changelog
1812 1813 cl.delayupdate()
1813 1814 oldheads = cl.heads()
1814 1815
1815 1816 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
1816 1817 try:
1817 1818 trp = weakref.proxy(tr)
1818 1819 # pull off the changeset group
1819 1820 self.ui.status(_("adding changesets\n"))
1820 1821 clstart = len(cl)
1821 1822 class prog(object):
1822 1823 step = _('changesets')
1823 1824 count = 1
1824 1825 ui = self.ui
1825 1826 total = None
1826 1827 def __call__(self):
1827 1828 self.ui.progress(self.step, self.count, unit=_('chunks'),
1828 1829 total=self.total)
1829 1830 self.count += 1
1830 1831 pr = prog()
1831 1832 source.callback = pr
1832 1833
1833 1834 source.changelogheader()
1834 1835 if (cl.addgroup(source, csmap, trp) is None
1835 1836 and not emptyok):
1836 1837 raise util.Abort(_("received changelog group is empty"))
1837 1838 clend = len(cl)
1838 1839 changesets = clend - clstart
1839 1840 for c in xrange(clstart, clend):
1840 1841 efiles.update(self[c].files())
1841 1842 efiles = len(efiles)
1842 1843 self.ui.progress(_('changesets'), None)
1843 1844
1844 1845 # pull off the manifest group
1845 1846 self.ui.status(_("adding manifests\n"))
1846 1847 pr.step = _('manifests')
1847 1848 pr.count = 1
1848 1849 pr.total = changesets # manifests <= changesets
1849 1850 # no need to check for empty manifest group here:
1850 1851 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1851 1852 # no new manifest will be created and the manifest group will
1852 1853 # be empty during the pull
1853 1854 source.manifestheader()
1854 1855 self.manifest.addgroup(source, revmap, trp)
1855 1856 self.ui.progress(_('manifests'), None)
1856 1857
1857 1858 needfiles = {}
1858 1859 if self.ui.configbool('server', 'validate', default=False):
1859 1860 # validate incoming csets have their manifests
1860 1861 for cset in xrange(clstart, clend):
1861 1862 mfest = self.changelog.read(self.changelog.node(cset))[0]
1862 1863 mfest = self.manifest.readdelta(mfest)
1863 1864 # store file nodes we must see
1864 1865 for f, n in mfest.iteritems():
1865 1866 needfiles.setdefault(f, set()).add(n)
1866 1867
1867 1868 # process the files
1868 1869 self.ui.status(_("adding file changes\n"))
1869 1870 pr.step = _('files')
1870 1871 pr.count = 1
1871 1872 pr.total = efiles
1872 1873 source.callback = None
1873 1874
1874 1875 while True:
1875 1876 chunkdata = source.filelogheader()
1876 1877 if not chunkdata:
1877 1878 break
1878 1879 f = chunkdata["filename"]
1879 1880 self.ui.debug("adding %s revisions\n" % f)
1880 1881 pr()
1881 1882 fl = self.file(f)
1882 1883 o = len(fl)
1883 1884 if fl.addgroup(source, revmap, trp) is None:
1884 1885 raise util.Abort(_("received file revlog group is empty"))
1885 1886 revisions += len(fl) - o
1886 1887 files += 1
1887 1888 if f in needfiles:
1888 1889 needs = needfiles[f]
1889 1890 for new in xrange(o, len(fl)):
1890 1891 n = fl.node(new)
1891 1892 if n in needs:
1892 1893 needs.remove(n)
1893 1894 if not needs:
1894 1895 del needfiles[f]
1895 1896 self.ui.progress(_('files'), None)
1896 1897
1897 1898 for f, needs in needfiles.iteritems():
1898 1899 fl = self.file(f)
1899 1900 for n in needs:
1900 1901 try:
1901 1902 fl.rev(n)
1902 1903 except error.LookupError:
1903 1904 raise util.Abort(
1904 1905 _('missing file data for %s:%s - run hg verify') %
1905 1906 (f, hex(n)))
1906 1907
1907 1908 dh = 0
1908 1909 if oldheads:
1909 1910 heads = cl.heads()
1910 1911 dh = len(heads) - len(oldheads)
1911 1912 for h in heads:
1912 1913 if h not in oldheads and 'close' in self[h].extra():
1913 1914 dh -= 1
1914 1915 htext = ""
1915 1916 if dh:
1916 1917 htext = _(" (%+d heads)") % dh
1917 1918
1918 1919 self.ui.status(_("added %d changesets"
1919 1920 " with %d changes to %d files%s\n")
1920 1921 % (changesets, revisions, files, htext))
1921 1922
1922 1923 if changesets > 0:
1923 1924 p = lambda: cl.writepending() and self.root or ""
1924 1925 self.hook('pretxnchangegroup', throw=True,
1925 1926 node=hex(cl.node(clstart)), source=srctype,
1926 1927 url=url, pending=p)
1927 1928
1928 1929 # make changelog see real files again
1929 1930 cl.finalize(trp)
1930 1931
1931 1932 tr.close()
1932 1933 finally:
1933 1934 tr.release()
1934 1935 if lock:
1935 1936 lock.release()
1936 1937
1937 1938 if changesets > 0:
1938 1939 # forcefully update the on-disk branch cache
1939 1940 self.ui.debug("updating the branch cache\n")
1940 1941 self.updatebranchcache()
1941 1942 self.hook("changegroup", node=hex(cl.node(clstart)),
1942 1943 source=srctype, url=url)
1943 1944
1944 1945 for i in xrange(clstart, clend):
1945 1946 self.hook("incoming", node=hex(cl.node(i)),
1946 1947 source=srctype, url=url)
1947 1948
1948 1949 # never return 0 here:
1949 1950 if dh < 0:
1950 1951 return dh - 1
1951 1952 else:
1952 1953 return dh + 1
1953 1954
1954 1955 def stream_in(self, remote, requirements):
1955 1956 lock = self.lock()
1956 1957 try:
1957 1958 fp = remote.stream_out()
1958 1959 l = fp.readline()
1959 1960 try:
1960 1961 resp = int(l)
1961 1962 except ValueError:
1962 1963 raise error.ResponseError(
1963 1964 _('Unexpected response from remote server:'), l)
1964 1965 if resp == 1:
1965 1966 raise util.Abort(_('operation forbidden by server'))
1966 1967 elif resp == 2:
1967 1968 raise util.Abort(_('locking the remote repository failed'))
1968 1969 elif resp != 0:
1969 1970 raise util.Abort(_('the server sent an unknown error code'))
1970 1971 self.ui.status(_('streaming all changes\n'))
1971 1972 l = fp.readline()
1972 1973 try:
1973 1974 total_files, total_bytes = map(int, l.split(' ', 1))
1974 1975 except (ValueError, TypeError):
1975 1976 raise error.ResponseError(
1976 1977 _('Unexpected response from remote server:'), l)
1977 1978 self.ui.status(_('%d files to transfer, %s of data\n') %
1978 1979 (total_files, util.bytecount(total_bytes)))
1979 1980 start = time.time()
1980 1981 for i in xrange(total_files):
1981 1982 # XXX doesn't support '\n' or '\r' in filenames
1982 1983 l = fp.readline()
1983 1984 try:
1984 1985 name, size = l.split('\0', 1)
1985 1986 size = int(size)
1986 1987 except (ValueError, TypeError):
1987 1988 raise error.ResponseError(
1988 1989 _('Unexpected response from remote server:'), l)
1989 1990 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1990 1991 # for backwards compat, name was partially encoded
1991 1992 ofp = self.sopener(store.decodedir(name), 'w')
1992 1993 for chunk in util.filechunkiter(fp, limit=size):
1993 1994 ofp.write(chunk)
1994 1995 ofp.close()
1995 1996 elapsed = time.time() - start
1996 1997 if elapsed <= 0:
1997 1998 elapsed = 0.001
1998 1999 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1999 2000 (util.bytecount(total_bytes), elapsed,
2000 2001 util.bytecount(total_bytes / elapsed)))
2001 2002
2002 2003 # new requirements = old non-format requirements + new format-related
2003 2004 # requirements from the streamed-in repository
2004 2005 requirements.update(set(self.requirements) - self.supportedformats)
2005 2006 self._applyrequirements(requirements)
2006 2007 self._writerequirements()
2007 2008
2008 2009 self.invalidate()
2009 2010 return len(self.heads()) + 1
2010 2011 finally:
2011 2012 lock.release()
2012 2013
2013 2014 def clone(self, remote, heads=[], stream=False):
2014 2015 '''clone remote repository.
2015 2016
2016 2017 keyword arguments:
2017 2018 heads: list of revs to clone (forces use of pull)
2018 2019 stream: use streaming clone if possible'''
2019 2020
2020 2021 # now, all clients that can request uncompressed clones can
2021 2022 # read repo formats supported by all servers that can serve
2022 2023 # them.
2023 2024
2024 2025 # if revlog format changes, client will have to check version
2025 2026 # and format flags on "stream" capability, and use
2026 2027 # uncompressed only if compatible.
2027 2028
2028 2029 if stream and not heads:
2029 2030 # 'stream' means remote revlog format is revlogv1 only
2030 2031 if remote.capable('stream'):
2031 2032 return self.stream_in(remote, set(('revlogv1',)))
2032 2033 # otherwise, 'streamreqs' contains the remote revlog format
2033 2034 streamreqs = remote.capable('streamreqs')
2034 2035 if streamreqs:
2035 2036 streamreqs = set(streamreqs.split(','))
2036 2037 # if we support it, stream in and adjust our requirements
2037 2038 if not streamreqs - self.supportedformats:
2038 2039 return self.stream_in(remote, streamreqs)
2039 2040 return self.pull(remote, heads)
2040 2041
2041 2042 def pushkey(self, namespace, key, old, new):
2042 2043 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2043 2044 old=old, new=new)
2044 2045 ret = pushkey.push(self, namespace, key, old, new)
2045 2046 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2046 2047 ret=ret)
2047 2048 return ret
2048 2049
2049 2050 def listkeys(self, namespace):
2050 2051 self.hook('prelistkeys', throw=True, namespace=namespace)
2051 2052 values = pushkey.list(self, namespace)
2052 2053 self.hook('listkeys', namespace=namespace, values=values)
2053 2054 return values
2054 2055
2055 2056 def debugwireargs(self, one, two, three=None, four=None, five=None):
2056 2057 '''used to test argument passing over the wire'''
2057 2058 return "%s %s %s %s %s" % (one, two, three, four, five)
2058 2059
2059 2060 def savecommitmessage(self, text):
2060 2061 fp = self.opener('last-message.txt', 'wb')
2061 2062 try:
2062 2063 fp.write(text)
2063 2064 finally:
2064 2065 fp.close()
2065 2066 return self.pathto(fp.name[len(self.root)+1:])
2066 2067
2067 2068 # used to avoid circular references so destructors work
2068 2069 def aftertrans(files):
2069 2070 renamefiles = [tuple(t) for t in files]
2070 2071 def a():
2071 2072 for src, dest in renamefiles:
2072 2073 util.rename(src, dest)
2073 2074 return a
2074 2075
2075 2076 def undoname(fn):
2076 2077 base, name = os.path.split(fn)
2077 2078 assert name.startswith('journal')
2078 2079 return os.path.join(base, name.replace('journal', 'undo', 1))
2079 2080
2080 2081 def instance(ui, path, create):
2081 2082 return localrepository(ui, util.urllocalpath(path), create)
2082 2083
2083 2084 def islocal(path):
2084 2085 return True
@@ -1,270 +1,270 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 add
4 4 addremove
5 5 annotate
6 6 archive
7 7 backout
8 8 bisect
9 9 bookmarks
10 10 branch
11 11 branches
12 12 bundle
13 13 cat
14 14 clone
15 15 commit
16 16 copy
17 17 diff
18 18 export
19 19 forget
20 20 graft
21 21 grep
22 22 heads
23 23 help
24 24 identify
25 25 import
26 26 incoming
27 27 init
28 28 locate
29 29 log
30 30 manifest
31 31 merge
32 32 outgoing
33 33 parents
34 34 paths
35 35 pull
36 36 push
37 37 recover
38 38 remove
39 39 rename
40 40 resolve
41 41 revert
42 42 rollback
43 43 root
44 44 serve
45 45 showconfig
46 46 status
47 47 summary
48 48 tag
49 49 tags
50 50 tip
51 51 unbundle
52 52 update
53 53 verify
54 54 version
55 55
56 56 Show all commands that start with "a"
57 57 $ hg debugcomplete a
58 58 add
59 59 addremove
60 60 annotate
61 61 archive
62 62
63 63 Do not show debug commands if there are other candidates
64 64 $ hg debugcomplete d
65 65 diff
66 66
67 67 Show debug commands if there are no other candidates
68 68 $ hg debugcomplete debug
69 69 debugancestor
70 70 debugbuilddag
71 71 debugbundle
72 72 debugcheckstate
73 73 debugcommands
74 74 debugcomplete
75 75 debugconfig
76 76 debugdag
77 77 debugdata
78 78 debugdate
79 79 debugdiscovery
80 80 debugfileset
81 81 debugfsinfo
82 82 debuggetbundle
83 83 debugignore
84 84 debugindex
85 85 debugindexdot
86 86 debuginstall
87 87 debugknown
88 88 debugpushkey
89 89 debugrebuildstate
90 90 debugrename
91 91 debugrevlog
92 92 debugrevspec
93 93 debugsetparents
94 94 debugstate
95 95 debugsub
96 96 debugwalk
97 97 debugwireargs
98 98
99 99 Do not show the alias of a debug command if there are other candidates
100 100 (this should hide rawcommit)
101 101 $ hg debugcomplete r
102 102 recover
103 103 remove
104 104 rename
105 105 resolve
106 106 revert
107 107 rollback
108 108 root
109 109 Show the alias of a debug command if there are no other candidates
110 110 $ hg debugcomplete rawc
111 111
112 112
113 113 Show the global options
114 114 $ hg debugcomplete --options | sort
115 115 --config
116 116 --cwd
117 117 --debug
118 118 --debugger
119 119 --encoding
120 120 --encodingmode
121 121 --help
122 122 --noninteractive
123 123 --profile
124 124 --quiet
125 125 --repository
126 126 --time
127 127 --traceback
128 128 --verbose
129 129 --version
130 130 -R
131 131 -h
132 132 -q
133 133 -v
134 134 -y
135 135
136 136 Show the options for the "serve" command
137 137 $ hg debugcomplete --options serve | sort
138 138 --accesslog
139 139 --address
140 140 --certificate
141 141 --cmdserver
142 142 --config
143 143 --cwd
144 144 --daemon
145 145 --daemon-pipefds
146 146 --debug
147 147 --debugger
148 148 --encoding
149 149 --encodingmode
150 150 --errorlog
151 151 --help
152 152 --ipv6
153 153 --name
154 154 --noninteractive
155 155 --pid-file
156 156 --port
157 157 --prefix
158 158 --profile
159 159 --quiet
160 160 --repository
161 161 --stdio
162 162 --style
163 163 --templates
164 164 --time
165 165 --traceback
166 166 --verbose
167 167 --version
168 168 --web-conf
169 169 -6
170 170 -A
171 171 -E
172 172 -R
173 173 -a
174 174 -d
175 175 -h
176 176 -n
177 177 -p
178 178 -q
179 179 -t
180 180 -v
181 181 -y
182 182
183 183 Show an error if we use --options with an ambiguous abbreviation
184 184 $ hg debugcomplete --options s
185 185 hg: command 's' is ambiguous:
186 186 serve showconfig status summary
187 187 [255]
188 188
189 189 Show all commands + options
190 190 $ hg debugcommands
191 191 add: include, exclude, subrepos, dry-run
192 192 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
193 193 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
194 commit: addremove, close-branch, include, exclude, message, logfile, date, user
194 commit: addremove, close-branch, include, exclude, message, logfile, date, user, subrepos
195 195 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
196 196 export: output, switch-parent, rev, text, git, nodates
197 197 forget: include, exclude
198 198 init: ssh, remotecmd, insecure
199 199 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, style, template, include, exclude
200 200 merge: force, rev, preview, tool
201 201 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
202 202 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
203 203 remove: after, force, include, exclude
204 204 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
205 205 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
206 206 summary: remote
207 207 update: clean, check, date, rev
208 208 addremove: similarity, include, exclude, dry-run
209 209 archive: no-decode, prefix, rev, type, subrepos, include, exclude
210 210 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
211 211 bisect: reset, good, bad, skip, extend, command, noupdate
212 212 bookmarks: force, rev, delete, rename, inactive
213 213 branch: force, clean
214 214 branches: active, closed
215 215 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
216 216 cat: output, rev, decode, include, exclude
217 217 copy: after, force, include, exclude, dry-run
218 218 debugancestor:
219 219 debugbuilddag: mergeable-file, overwritten-file, new-file
220 220 debugbundle: all
221 221 debugcheckstate:
222 222 debugcommands:
223 223 debugcomplete: options
224 224 debugdag: tags, branches, dots, spaces
225 225 debugdata: changelog, manifest
226 226 debugdate: extended
227 227 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
228 228 debugfileset:
229 229 debugfsinfo:
230 230 debuggetbundle: head, common, type
231 231 debugignore:
232 232 debugindex: changelog, manifest, format
233 233 debugindexdot:
234 234 debuginstall:
235 235 debugknown:
236 236 debugpushkey:
237 237 debugrebuildstate: rev
238 238 debugrename: rev
239 239 debugrevlog: changelog, manifest, dump
240 240 debugrevspec:
241 241 debugsetparents:
242 242 debugstate: nodates, datesort
243 243 debugsub: rev
244 244 debugwalk: include, exclude
245 245 debugwireargs: three, four, five, ssh, remotecmd, insecure
246 246 graft: continue, edit, currentdate, currentuser, date, user, tool
247 247 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
248 248 heads: rev, topo, active, closed, style, template
249 249 help: extension, command
250 250 identify: rev, num, id, branch, tags, bookmarks
251 251 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
252 252 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
253 253 locate: rev, print0, fullpath, include, exclude
254 254 manifest: rev, all
255 255 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
256 256 parents: rev, style, template
257 257 paths:
258 258 recover:
259 259 rename: after, force, include, exclude, dry-run
260 260 resolve: all, list, mark, unmark, no-status, tool, include, exclude
261 261 revert: all, date, rev, no-backup, include, exclude, dry-run
262 262 rollback: dry-run, force
263 263 root:
264 264 showconfig: untrusted
265 265 tag: force, local, rev, remove, edit, message, date, user
266 266 tags:
267 267 tip: patch, git, style, template
268 268 unbundle: update
269 269 verify:
270 270 version:
@@ -1,361 +1,363 b''
1 $ echo "[ui]" >> $HGRCPATH
2 $ echo "commitsubrepos = Yes" >> $HGRCPATH
1 3 $ echo "[extensions]" >> $HGRCPATH
2 4 $ echo "mq=" >> $HGRCPATH
3 5 $ echo "record=" >> $HGRCPATH
4 6 $ echo "[diff]" >> $HGRCPATH
5 7 $ echo "nodates=1" >> $HGRCPATH
6 8
7 9 $ stdin=`pwd`/stdin.tmp
8 10
9 11 fn to create new repository w/dirty subrepo, and cd into it
10 12 $ mkrepo() {
11 13 > hg init $1
12 14 > cd $1
13 15 > hg qinit
14 16 > }
15 17
16 18 fn to create dirty subrepo
17 19 $ mksubrepo() {
18 20 > hg init $1
19 21 > cd $1
20 22 > echo a > a
21 23 > hg add
22 24 > cd ..
23 25 > }
24 26
25 27 $ testadd() {
26 28 > cat - > "$stdin"
27 29 > mksubrepo sub
28 30 > echo sub = sub >> .hgsub
29 31 > hg add .hgsub
30 32 > echo % abort when adding .hgsub w/dirty subrepo
31 33 > hg status -S
32 34 > echo '%' $*
33 35 > cat "$stdin" | hg $*
34 36 > echo [$?]
35 37 > hg -R sub ci -m0sub
36 38 > echo % update substate when adding .hgsub w/clean updated subrepo
37 39 > hg status -S
38 40 > echo '%' $*
39 41 > cat "$stdin" | hg $*
40 42 > hg debugsub
41 43 > }
42 44
43 45 $ testmod() {
44 46 > cat - > "$stdin"
45 47 > mksubrepo sub2
46 48 > echo sub2 = sub2 >> .hgsub
47 49 > echo % abort when modifying .hgsub w/dirty subrepo
48 50 > hg status -S
49 51 > echo '%' $*
50 52 > cat "$stdin" | hg $*
51 53 > echo [$?]
52 54 > hg -R sub2 ci -m0sub2
53 55 > echo % update substate when modifying .hgsub w/clean updated subrepo
54 56 > hg status -S
55 57 > echo '%' $*
56 58 > cat "$stdin" | hg $*
57 59 > hg debugsub
58 60 > }
59 61
60 62 $ testrm1() {
61 63 > cat - > "$stdin"
62 64 > mksubrepo sub3
63 65 > echo sub3 = sub3 >> .hgsub
64 66 > hg ci -Aqmsub3
65 67 > $EXTRA
66 68 > echo b >> sub3/a
67 69 > hg rm .hgsub
68 70 > echo % update substate when removing .hgsub w/dirty subrepo
69 71 > hg status -S
70 72 > echo '%' $*
71 73 > cat "$stdin" | hg $*
72 74 > echo % debugsub should be empty
73 75 > hg debugsub
74 76 > }
75 77
76 78 $ testrm2() {
77 79 > cat - > "$stdin"
78 80 > mksubrepo sub4
79 81 > echo sub4 = sub4 >> .hgsub
80 82 > hg ci -Aqmsub4
81 83 > $EXTRA
82 84 > hg rm .hgsub
83 85 > echo % update substate when removing .hgsub w/clean updated subrepo
84 86 > hg status -S
85 87 > echo '%' $*
86 88 > cat "$stdin" | hg $*
87 89 > echo % debugsub should be empty
88 90 > hg debugsub
89 91 > }
90 92
91 93
92 94 handle subrepos safely on qnew
93 95
94 96 $ mkrepo repo-2499-qnew
95 97 $ testadd qnew -m0 0.diff
96 98 adding a
97 99 % abort when adding .hgsub w/dirty subrepo
98 100 A .hgsub
99 101 A sub/a
100 102 % qnew -m0 0.diff
101 103 abort: uncommitted changes in subrepository sub
102 104 [255]
103 105 % update substate when adding .hgsub w/clean updated subrepo
104 106 A .hgsub
105 107 % qnew -m0 0.diff
106 108 committing subrepository sub
107 109 path sub
108 110 source sub
109 111 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
110 112
111 113 $ testmod qnew -m1 1.diff
112 114 adding a
113 115 % abort when modifying .hgsub w/dirty subrepo
114 116 M .hgsub
115 117 A sub2/a
116 118 % qnew -m1 1.diff
117 119 abort: uncommitted changes in subrepository sub2
118 120 [255]
119 121 % update substate when modifying .hgsub w/clean updated subrepo
120 122 M .hgsub
121 123 % qnew -m1 1.diff
122 124 committing subrepository sub2
123 125 path sub
124 126 source sub
125 127 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
126 128 path sub2
127 129 source sub2
128 130 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
129 131
130 132 $ hg qpop -qa
131 133 patch queue now empty
132 134 $ testrm1 qnew -m2 2.diff
133 135 adding a
134 136 % update substate when removing .hgsub w/dirty subrepo
135 137 M sub3/a
136 138 R .hgsub
137 139 % qnew -m2 2.diff
138 140 % debugsub should be empty
139 141
140 142 $ hg qpop -qa
141 143 patch queue now empty
142 144 $ testrm2 qnew -m3 3.diff
143 145 adding a
144 146 % update substate when removing .hgsub w/clean updated subrepo
145 147 R .hgsub
146 148 % qnew -m3 3.diff
147 149 % debugsub should be empty
148 150
149 151 $ cd ..
150 152
151 153
152 154 handle subrepos safely on qrefresh
153 155
154 156 $ mkrepo repo-2499-qrefresh
155 157 $ hg qnew -m0 0.diff
156 158 $ testadd qrefresh
157 159 adding a
158 160 % abort when adding .hgsub w/dirty subrepo
159 161 A .hgsub
160 162 A sub/a
161 163 % qrefresh
162 164 abort: uncommitted changes in subrepository sub
163 165 [255]
164 166 % update substate when adding .hgsub w/clean updated subrepo
165 167 A .hgsub
166 168 % qrefresh
167 169 committing subrepository sub
168 170 path sub
169 171 source sub
170 172 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
171 173
172 174 $ hg qnew -m1 1.diff
173 175 $ testmod qrefresh
174 176 adding a
175 177 % abort when modifying .hgsub w/dirty subrepo
176 178 M .hgsub
177 179 A sub2/a
178 180 % qrefresh
179 181 abort: uncommitted changes in subrepository sub2
180 182 [255]
181 183 % update substate when modifying .hgsub w/clean updated subrepo
182 184 M .hgsub
183 185 % qrefresh
184 186 committing subrepository sub2
185 187 path sub
186 188 source sub
187 189 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
188 190 path sub2
189 191 source sub2
190 192 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
191 193
192 194 $ hg qpop -qa
193 195 patch queue now empty
194 196 $ EXTRA='hg qnew -m2 2.diff'
195 197 $ testrm1 qrefresh
196 198 adding a
197 199 % update substate when removing .hgsub w/dirty subrepo
198 200 M sub3/a
199 201 R .hgsub
200 202 % qrefresh
201 203 % debugsub should be empty
202 204
203 205 $ hg qpop -qa
204 206 patch queue now empty
205 207 $ EXTRA='hg qnew -m3 3.diff'
206 208 $ testrm2 qrefresh
207 209 adding a
208 210 % update substate when removing .hgsub w/clean updated subrepo
209 211 R .hgsub
210 212 % qrefresh
211 213 % debugsub should be empty
212 214 $ EXTRA=
213 215
214 216 $ cd ..
215 217
216 218
217 219 handle subrepos safely on qpush/qpop
218 220
219 221 $ mkrepo repo-2499-qpush
220 222 $ mksubrepo sub
221 223 adding a
222 224 $ hg -R sub ci -m0sub
223 225 $ echo sub = sub > .hgsub
224 226 $ hg add .hgsub
225 227 $ hg qnew -m0 0.diff
226 228 committing subrepository sub
227 229 $ hg debugsub
228 230 path sub
229 231 source sub
230 232 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
231 233
232 234 qpop
233 235 $ hg qpop
234 236 popping 0.diff
235 237 patch queue now empty
236 238 $ hg status -AS
237 239 $ hg debugsub
238 240
239 241 qpush
240 242 $ hg qpush
241 243 applying 0.diff
242 244 now at: 0.diff
243 245 $ hg status -AS
244 246 C .hgsub
245 247 C .hgsubstate
246 248 C sub/a
247 249 $ hg debugsub
248 250 path sub
249 251 source sub
250 252 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
251 253
252 254 $ cd ..
253 255
254 256
255 257 handle subrepos safely on qrecord
256 258
257 259 $ mkrepo repo-2499-qrecord
258 260 $ testadd qrecord --config ui.interactive=1 -m0 0.diff <<EOF
259 261 > y
260 262 > y
261 263 > EOF
262 264 adding a
263 265 % abort when adding .hgsub w/dirty subrepo
264 266 A .hgsub
265 267 A sub/a
266 268 % qrecord --config ui.interactive=1 -m0 0.diff
267 269 diff --git a/.hgsub b/.hgsub
268 270 new file mode 100644
269 271 examine changes to '.hgsub'? [Ynsfdaq?]
270 272 abort: uncommitted changes in subrepository sub
271 273 [255]
272 274 % update substate when adding .hgsub w/clean updated subrepo
273 275 A .hgsub
274 276 % qrecord --config ui.interactive=1 -m0 0.diff
275 277 diff --git a/.hgsub b/.hgsub
276 278 new file mode 100644
277 279 examine changes to '.hgsub'? [Ynsfdaq?]
278 280 committing subrepository sub
279 281 path sub
280 282 source sub
281 283 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
282 284
283 285 $ testmod qrecord --config ui.interactive=1 -m1 1.diff <<EOF
284 286 > y
285 287 > y
286 288 > EOF
287 289 adding a
288 290 % abort when modifying .hgsub w/dirty subrepo
289 291 M .hgsub
290 292 A sub2/a
291 293 % qrecord --config ui.interactive=1 -m1 1.diff
292 294 diff --git a/.hgsub b/.hgsub
293 295 1 hunks, 1 lines changed
294 296 examine changes to '.hgsub'? [Ynsfdaq?]
295 297 @@ -1,1 +1,2 @@
296 298 sub = sub
297 299 +sub2 = sub2
298 300 record this change to '.hgsub'? [Ynsfdaq?]
299 301 abort: uncommitted changes in subrepository sub2
300 302 [255]
301 303 % update substate when modifying .hgsub w/clean updated subrepo
302 304 M .hgsub
303 305 % qrecord --config ui.interactive=1 -m1 1.diff
304 306 diff --git a/.hgsub b/.hgsub
305 307 1 hunks, 1 lines changed
306 308 examine changes to '.hgsub'? [Ynsfdaq?]
307 309 @@ -1,1 +1,2 @@
308 310 sub = sub
309 311 +sub2 = sub2
310 312 record this change to '.hgsub'? [Ynsfdaq?]
311 313 committing subrepository sub2
312 314 path sub
313 315 source sub
314 316 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
315 317 path sub2
316 318 source sub2
317 319 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
318 320
319 321 $ hg qpop -qa
320 322 patch queue now empty
321 323 $ testrm1 qrecord --config ui.interactive=1 -m2 2.diff <<EOF
322 324 > y
323 325 > y
324 326 > EOF
325 327 adding a
326 328 % update substate when removing .hgsub w/dirty subrepo
327 329 M sub3/a
328 330 R .hgsub
329 331 % qrecord --config ui.interactive=1 -m2 2.diff
330 332 diff --git a/.hgsub b/.hgsub
331 333 deleted file mode 100644
332 334 examine changes to '.hgsub'? [Ynsfdaq?]
333 335 % debugsub should be empty
334 336
335 337 $ hg qpop -qa
336 338 patch queue now empty
337 339 $ testrm2 qrecord --config ui.interactive=1 -m3 3.diff <<EOF
338 340 > y
339 341 > y
340 342 > EOF
341 343 adding a
342 344 % update substate when removing .hgsub w/clean updated subrepo
343 345 R .hgsub
344 346 % qrecord --config ui.interactive=1 -m3 3.diff
345 347 diff --git a/.hgsub b/.hgsub
346 348 deleted file mode 100644
347 349 examine changes to '.hgsub'? [Ynsfdaq?]
348 350 % debugsub should be empty
349 351
350 352 $ cd ..
351 353
352 354
353 355 correctly handle subrepos with patch queues
354 356 $ mkrepo repo-subrepo-with-queue
355 357 $ mksubrepo sub
356 358 adding a
357 359 $ hg -R sub qnew sub0.diff
358 360 $ echo sub = sub >> .hgsub
359 361 $ hg add .hgsub
360 362 $ hg qnew 0.diff
361 363 committing subrepository sub
@@ -1,396 +1,397 b''
1 1 Create configuration
2 2
3 3 $ echo "[ui]" >> $HGRCPATH
4 4 $ echo "interactive=true" >> $HGRCPATH
5 5
6 6 help record (no record)
7 7
8 8 $ hg help record
9 9 record extension - commands to interactively select changes for commit/qrefresh
10 10
11 11 use "hg help extensions" for information on enabling extensions
12 12
13 13 help qrecord (no record)
14 14
15 15 $ hg help qrecord
16 16 'qrecord' is provided by the following extension:
17 17
18 18 record commands to interactively select changes for commit/qrefresh
19 19
20 20 use "hg help extensions" for information on enabling extensions
21 21
22 22 $ echo "[extensions]" >> $HGRCPATH
23 23 $ echo "record=" >> $HGRCPATH
24 24
25 25 help record (record)
26 26
27 27 $ hg help record
28 28 hg record [OPTION]... [FILE]...
29 29
30 30 interactively select changes to commit
31 31
32 32 If a list of files is omitted, all changes reported by "hg status" will be
33 33 candidates for recording.
34 34
35 35 See "hg help dates" for a list of formats valid for -d/--date.
36 36
37 37 You will be prompted for whether to record changes to each modified file,
38 38 and for files with multiple changes, for each change to use. For each
39 39 query, the following responses are possible:
40 40
41 41 y - record this change
42 42 n - skip this change
43 43
44 44 s - skip remaining changes to this file
45 45 f - record remaining changes to this file
46 46
47 47 d - done, skip remaining changes and files
48 48 a - record all changes to all remaining files
49 49 q - quit, recording no changes
50 50
51 51 ? - display help
52 52
53 53 This command is not available when committing a merge.
54 54
55 55 options:
56 56
57 57 -A --addremove mark new/missing files as added/removed before
58 58 committing
59 59 --close-branch mark a branch as closed, hiding it from the branch
60 60 list
61 61 -I --include PATTERN [+] include names matching the given patterns
62 62 -X --exclude PATTERN [+] exclude names matching the given patterns
63 63 -m --message TEXT use text as commit message
64 64 -l --logfile FILE read commit message from file
65 65 -d --date DATE record the specified date as commit date
66 66 -u --user USER record the specified user as committer
67 -S --subrepos recurse into subrepositories
67 68 -w --ignore-all-space ignore white space when comparing lines
68 69 -b --ignore-space-change ignore changes in the amount of white space
69 70 -B --ignore-blank-lines ignore changes whose lines are all blank
70 71
71 72 [+] marked option can be specified multiple times
72 73
73 74 use "hg -v help record" to show more info
74 75
75 76 help (no mq, so no qrecord)
76 77
77 78 $ hg help qrecord
78 79 hg qrecord [OPTION]... PATCH [FILE]...
79 80
80 81 interactively record a new patch
81 82
82 83 See "hg help qnew" & "hg help record" for more information and usage.
83 84
84 85 use "hg -v help qrecord" to show more info
85 86
86 87 $ hg init a
87 88
88 89 qrecord (mq not present)
89 90
90 91 $ hg -R a qrecord
91 92 hg qrecord: invalid arguments
92 93 hg qrecord [OPTION]... PATCH [FILE]...
93 94
94 95 interactively record a new patch
95 96
96 97 use "hg help qrecord" to show the full help text
97 98 [255]
98 99
99 100 qrecord patch (mq not present)
100 101
101 102 $ hg -R a qrecord patch
102 103 abort: 'mq' extension not loaded
103 104 [255]
104 105
105 106 help (bad mq)
106 107
107 108 $ echo "mq=nonexistant" >> $HGRCPATH
108 109 $ hg help qrecord
109 110 *** failed to import extension mq from nonexistant: [Errno 2] No such file or directory
110 111 hg qrecord [OPTION]... PATCH [FILE]...
111 112
112 113 interactively record a new patch
113 114
114 115 See "hg help qnew" & "hg help record" for more information and usage.
115 116
116 117 use "hg -v help qrecord" to show more info
117 118
118 119 help (mq present)
119 120
120 121 $ sed 's/mq=nonexistant/mq=/' $HGRCPATH > hgrc.tmp
121 122 $ mv hgrc.tmp $HGRCPATH
122 123
123 124 $ hg help qrecord
124 125 hg qrecord [OPTION]... PATCH [FILE]...
125 126
126 127 interactively record a new patch
127 128
128 129 See "hg help qnew" & "hg help record" for more information and usage.
129 130
130 131 options:
131 132
132 133 -e --edit edit commit message
133 134 -g --git use git extended diff format
134 135 -U --currentuser add "From: <current user>" to patch
135 136 -u --user USER add "From: <USER>" to patch
136 137 -D --currentdate add "Date: <current date>" to patch
137 138 -d --date DATE add "Date: <DATE>" to patch
138 139 -I --include PATTERN [+] include names matching the given patterns
139 140 -X --exclude PATTERN [+] exclude names matching the given patterns
140 141 -m --message TEXT use text as commit message
141 142 -l --logfile FILE read commit message from file
142 143 -w --ignore-all-space ignore white space when comparing lines
143 144 -b --ignore-space-change ignore changes in the amount of white space
144 145 -B --ignore-blank-lines ignore changes whose lines are all blank
145 146 --mq operate on patch repository
146 147
147 148 [+] marked option can be specified multiple times
148 149
149 150 use "hg -v help qrecord" to show more info
150 151
151 152 $ cd a
152 153
153 154 Base commit
154 155
155 156 $ cat > 1.txt <<EOF
156 157 > 1
157 158 > 2
158 159 > 3
159 160 > 4
160 161 > 5
161 162 > EOF
162 163 $ cat > 2.txt <<EOF
163 164 > a
164 165 > b
165 166 > c
166 167 > d
167 168 > e
168 169 > f
169 170 > EOF
170 171
171 172 $ mkdir dir
172 173 $ cat > dir/a.txt <<EOF
173 174 > hello world
174 175 >
175 176 > someone
176 177 > up
177 178 > there
178 179 > loves
179 180 > me
180 181 > EOF
181 182
182 183 $ hg add 1.txt 2.txt dir/a.txt
183 184 $ hg commit -m 'initial checkin'
184 185
185 186 Changing files
186 187
187 188 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
188 189 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
189 190 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
190 191
191 192 $ mv -f 1.txt.new 1.txt
192 193 $ mv -f 2.txt.new 2.txt
193 194 $ mv -f dir/a.txt.new dir/a.txt
194 195
195 196 Whole diff
196 197
197 198 $ hg diff --nodates
198 199 diff -r 1057167b20ef 1.txt
199 200 --- a/1.txt
200 201 +++ b/1.txt
201 202 @@ -1,5 +1,5 @@
202 203 1
203 204 -2
204 205 +2 2
205 206 3
206 207 -4
207 208 +4 4
208 209 5
209 210 diff -r 1057167b20ef 2.txt
210 211 --- a/2.txt
211 212 +++ b/2.txt
212 213 @@ -1,5 +1,5 @@
213 214 a
214 215 -b
215 216 +b b
216 217 c
217 218 d
218 219 e
219 220 diff -r 1057167b20ef dir/a.txt
220 221 --- a/dir/a.txt
221 222 +++ b/dir/a.txt
222 223 @@ -1,4 +1,4 @@
223 224 -hello world
224 225 +hello world!
225 226
226 227 someone
227 228 up
228 229
229 230 qrecord with bad patch name, should abort before prompting
230 231
231 232 $ hg qrecord .hg
232 233 abort: patch name cannot begin with ".hg"
233 234 [255]
234 235
235 236 qrecord a.patch
236 237
237 238 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
238 239 > y
239 240 > y
240 241 > n
241 242 > y
242 243 > y
243 244 > n
244 245 > EOF
245 246 diff --git a/1.txt b/1.txt
246 247 2 hunks, 2 lines changed
247 248 examine changes to '1.txt'? [Ynsfdaq?]
248 249 @@ -1,3 +1,3 @@
249 250 1
250 251 -2
251 252 +2 2
252 253 3
253 254 record change 1/4 to '1.txt'? [Ynsfdaq?]
254 255 @@ -3,3 +3,3 @@
255 256 3
256 257 -4
257 258 +4 4
258 259 5
259 260 record change 2/4 to '1.txt'? [Ynsfdaq?]
260 261 diff --git a/2.txt b/2.txt
261 262 1 hunks, 1 lines changed
262 263 examine changes to '2.txt'? [Ynsfdaq?]
263 264 @@ -1,5 +1,5 @@
264 265 a
265 266 -b
266 267 +b b
267 268 c
268 269 d
269 270 e
270 271 record change 3/4 to '2.txt'? [Ynsfdaq?]
271 272 diff --git a/dir/a.txt b/dir/a.txt
272 273 1 hunks, 1 lines changed
273 274 examine changes to 'dir/a.txt'? [Ynsfdaq?]
274 275
275 276 After qrecord a.patch 'tip'"
276 277
277 278 $ hg tip -p
278 279 changeset: 1:5d1ca63427ee
279 280 tag: a.patch
280 281 tag: qbase
281 282 tag: qtip
282 283 tag: tip
283 284 user: test
284 285 date: Thu Jan 01 00:00:00 1970 +0000
285 286 summary: aaa
286 287
287 288 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
288 289 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
289 290 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
290 291 @@ -1,5 +1,5 @@
291 292 1
292 293 -2
293 294 +2 2
294 295 3
295 296 4
296 297 5
297 298 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
298 299 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
299 300 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
300 301 @@ -1,5 +1,5 @@
301 302 a
302 303 -b
303 304 +b b
304 305 c
305 306 d
306 307 e
307 308
308 309
309 310 After qrecord a.patch 'diff'"
310 311
311 312 $ hg diff --nodates
312 313 diff -r 5d1ca63427ee 1.txt
313 314 --- a/1.txt
314 315 +++ b/1.txt
315 316 @@ -1,5 +1,5 @@
316 317 1
317 318 2 2
318 319 3
319 320 -4
320 321 +4 4
321 322 5
322 323 diff -r 5d1ca63427ee dir/a.txt
323 324 --- a/dir/a.txt
324 325 +++ b/dir/a.txt
325 326 @@ -1,4 +1,4 @@
326 327 -hello world
327 328 +hello world!
328 329
329 330 someone
330 331 up
331 332
332 333 qrecord b.patch
333 334
334 335 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
335 336 > y
336 337 > y
337 338 > y
338 339 > y
339 340 > EOF
340 341 diff --git a/1.txt b/1.txt
341 342 1 hunks, 1 lines changed
342 343 examine changes to '1.txt'? [Ynsfdaq?]
343 344 @@ -1,5 +1,5 @@
344 345 1
345 346 2 2
346 347 3
347 348 -4
348 349 +4 4
349 350 5
350 351 record change 1/2 to '1.txt'? [Ynsfdaq?]
351 352 diff --git a/dir/a.txt b/dir/a.txt
352 353 1 hunks, 1 lines changed
353 354 examine changes to 'dir/a.txt'? [Ynsfdaq?]
354 355 @@ -1,4 +1,4 @@
355 356 -hello world
356 357 +hello world!
357 358
358 359 someone
359 360 up
360 361 record change 2/2 to 'dir/a.txt'? [Ynsfdaq?]
361 362
362 363 After qrecord b.patch 'tip'
363 364
364 365 $ hg tip -p
365 366 changeset: 2:b056198bf878
366 367 tag: b.patch
367 368 tag: qtip
368 369 tag: tip
369 370 user: test
370 371 date: Thu Jan 01 00:00:00 1970 +0000
371 372 summary: bbb
372 373
373 374 diff -r 5d1ca63427ee -r b056198bf878 1.txt
374 375 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
375 376 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
376 377 @@ -1,5 +1,5 @@
377 378 1
378 379 2 2
379 380 3
380 381 -4
381 382 +4 4
382 383 5
383 384 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
384 385 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
385 386 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
386 387 @@ -1,4 +1,4 @@
387 388 -hello world
388 389 +hello world!
389 390
390 391 someone
391 392 up
392 393
393 394
394 395 After qrecord b.patch 'diff'
395 396
396 397 $ hg diff --nodates
@@ -1,102 +1,102 b''
1 1 Preparing the subrepository 'sub2'
2 2
3 3 $ hg init sub2
4 4 $ echo sub2 > sub2/sub2
5 5 $ hg add -R sub2
6 6 adding sub2/sub2
7 7 $ hg commit -R sub2 -m "sub2 import"
8 8
9 9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
10 10
11 11 $ hg init sub1
12 12 $ echo sub1 > sub1/sub1
13 13 $ echo "sub2 = ../sub2" > sub1/.hgsub
14 14 $ hg clone sub2 sub1/sub2
15 15 updating to branch default
16 16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 17 $ hg add -R sub1
18 18 adding sub1/.hgsub
19 19 adding sub1/sub1
20 20 $ hg commit -R sub1 -m "sub1 import"
21 21 committing subrepository sub2
22 22
23 23 Preparing the 'main' repo which depends on the subrepo 'sub1'
24 24
25 25 $ hg init main
26 26 $ echo main > main/main
27 27 $ echo "sub1 = ../sub1" > main/.hgsub
28 28 $ hg clone sub1 main/sub1
29 29 updating to branch default
30 30 cloning subrepo sub2 from $TESTTMP/sub2
31 31 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 32 $ hg add -R main
33 33 adding main/.hgsub
34 34 adding main/main
35 35 $ hg commit -R main -m "main import"
36 36 committing subrepository sub1
37 37
38 38 Cleaning both repositories, just as a clone -U
39 39
40 40 $ hg up -C -R sub2 null
41 41 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
42 42 $ hg up -C -R sub1 null
43 43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
44 44 $ hg up -C -R main null
45 45 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
46 46 $ rm -rf main/sub1
47 47 $ rm -rf sub1/sub2
48 48
49 49 Clone main
50 50
51 51 $ hg clone main cloned
52 52 updating to branch default
53 53 cloning subrepo sub1 from $TESTTMP/sub1
54 54 cloning subrepo sub1/sub2 from $TESTTMP/sub2
55 55 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 56
57 57 Checking cloned repo ids
58 58
59 59 $ printf "cloned " ; hg id -R cloned
60 60 cloned 7f491f53a367 tip
61 61 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
62 62 cloned/sub1 fc3b4ce2696f tip
63 63 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
64 64 cloned/sub1/sub2 c57a0840e3ba tip
65 65
66 66 debugsub output for main and sub1
67 67
68 68 $ hg debugsub -R cloned
69 69 path sub1
70 70 source ../sub1
71 71 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
72 72 $ hg debugsub -R cloned/sub1
73 73 path sub2
74 74 source ../sub2
75 75 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
76 76
77 77 Modifying deeply nested 'sub2'
78 78
79 79 $ echo modified > cloned/sub1/sub2/sub2
80 $ hg commit -m "deep nested modif should trigger a commit" -R cloned
80 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
81 81 committing subrepository sub1
82 82 committing subrepository sub1/sub2
83 83
84 84 Checking modified node ids
85 85
86 86 $ printf "cloned " ; hg id -R cloned
87 87 cloned ffe6649062fe tip
88 88 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
89 89 cloned/sub1 2ecb03bf44a9 tip
90 90 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
91 91 cloned/sub1/sub2 53dd3430bcaf tip
92 92
93 93 debugsub output for main and sub1
94 94
95 95 $ hg debugsub -R cloned
96 96 path sub1
97 97 source ../sub1
98 98 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
99 99 $ hg debugsub -R cloned/sub1
100 100 path sub2
101 101 source ../sub2
102 102 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
@@ -1,501 +1,501 b''
1 1 $ "$TESTDIR/hghave" git || exit 80
2 2
3 3 make git commits repeatable
4 4
5 5 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
6 6 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
7 7 $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
8 8 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
9 9 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
10 10 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
11 11
12 12 root hg repo
13 13
14 14 $ hg init t
15 15 $ cd t
16 16 $ echo a > a
17 17 $ hg add a
18 18 $ hg commit -m a
19 19 $ cd ..
20 20
21 21 new external git repo
22 22
23 23 $ mkdir gitroot
24 24 $ cd gitroot
25 25 $ git init -q
26 26 $ echo g > g
27 27 $ git add g
28 28 $ git commit -q -m g
29 29
30 30 add subrepo clone
31 31
32 32 $ cd ../t
33 33 $ echo 's = [git]../gitroot' > .hgsub
34 34 $ git clone -q ../gitroot s
35 35 $ hg add .hgsub
36 36 $ hg commit -m 'new git subrepo'
37 37 committing subrepository s
38 38 $ hg debugsub
39 39 path s
40 40 source ../gitroot
41 41 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
42 42
43 43 record a new commit from upstream from a different branch
44 44
45 45 $ cd ../gitroot
46 46 $ git checkout -q -b testing
47 47 $ echo gg >> g
48 48 $ git commit -q -a -m gg
49 49
50 50 $ cd ../t/s
51 51 $ git pull -q >/dev/null 2>/dev/null
52 52 $ git checkout -q -b testing origin/testing >/dev/null
53 53
54 54 $ cd ..
55 55 $ hg status --subrepos
56 56 M s/g
57 57 $ hg commit -m 'update git subrepo'
58 58 committing subrepository s
59 59 $ hg debugsub
60 60 path s
61 61 source ../gitroot
62 62 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
63 63
64 64 make $GITROOT pushable, by replacing it with a clone with nothing checked out
65 65
66 66 $ cd ..
67 67 $ git clone gitroot gitrootbare --bare -q
68 68 $ rm -rf gitroot
69 69 $ mv gitrootbare gitroot
70 70
71 71 clone root
72 72
73 73 $ cd t
74 74 $ hg clone . ../tc
75 75 updating to branch default
76 76 cloning subrepo s from $TESTTMP/gitroot
77 77 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 78 $ cd ../tc
79 79 $ hg debugsub
80 80 path s
81 81 source ../gitroot
82 82 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
83 83
84 84 update to previous substate
85 85
86 86 $ hg update 1 -q
87 87 $ cat s/g
88 88 g
89 89 $ hg debugsub
90 90 path s
91 91 source ../gitroot
92 92 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
93 93
94 94 clone root, make local change
95 95
96 96 $ cd ../t
97 97 $ hg clone . ../ta
98 98 updating to branch default
99 99 cloning subrepo s from $TESTTMP/gitroot
100 100 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 101
102 102 $ cd ../ta
103 103 $ echo ggg >> s/g
104 104 $ hg status --subrepos
105 105 M s/g
106 $ hg commit -m ggg
106 $ hg commit --subrepos -m ggg
107 107 committing subrepository s
108 108 $ hg debugsub
109 109 path s
110 110 source ../gitroot
111 111 revision 79695940086840c99328513acbe35f90fcd55e57
112 112
113 113 clone root separately, make different local change
114 114
115 115 $ cd ../t
116 116 $ hg clone . ../tb
117 117 updating to branch default
118 118 cloning subrepo s from $TESTTMP/gitroot
119 119 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 120
121 121 $ cd ../tb/s
122 122 $ echo f > f
123 123 $ git add f
124 124 $ cd ..
125 125
126 126 $ hg status --subrepos
127 127 A s/f
128 $ hg commit -m f
128 $ hg commit --subrepos -m f
129 129 committing subrepository s
130 130 $ hg debugsub
131 131 path s
132 132 source ../gitroot
133 133 revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
134 134
135 135 user b push changes
136 136
137 137 $ hg push 2>/dev/null
138 138 pushing to $TESTTMP/t
139 139 pushing branch testing of subrepo s
140 140 searching for changes
141 141 adding changesets
142 142 adding manifests
143 143 adding file changes
144 144 added 1 changesets with 1 changes to 1 files
145 145
146 146 user a pulls, merges, commits
147 147
148 148 $ cd ../ta
149 149 $ hg pull
150 150 pulling from $TESTTMP/t
151 151 searching for changes
152 152 adding changesets
153 153 adding manifests
154 154 adding file changes
155 155 added 1 changesets with 1 changes to 1 files (+1 heads)
156 156 (run 'hg heads' to see heads, 'hg merge' to merge)
157 157 $ hg merge 2>/dev/null
158 158 pulling subrepo s from $TESTTMP/gitroot
159 159 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 160 (branch merge, don't forget to commit)
161 161 $ cat s/f
162 162 f
163 163 $ cat s/g
164 164 g
165 165 gg
166 166 ggg
167 $ hg commit -m 'merge'
167 $ hg commit --subrepos -m 'merge'
168 168 committing subrepository s
169 169 $ hg status --subrepos --rev 1:5
170 170 M .hgsubstate
171 171 M s/g
172 172 A s/f
173 173 $ hg debugsub
174 174 path s
175 175 source ../gitroot
176 176 revision f47b465e1bce645dbf37232a00574aa1546ca8d3
177 177 $ hg push 2>/dev/null
178 178 pushing to $TESTTMP/t
179 179 pushing branch testing of subrepo s
180 180 searching for changes
181 181 adding changesets
182 182 adding manifests
183 183 adding file changes
184 184 added 2 changesets with 2 changes to 1 files
185 185
186 186 make upstream git changes
187 187
188 188 $ cd ..
189 189 $ git clone -q gitroot gitclone
190 190 $ cd gitclone
191 191 $ echo ff >> f
192 192 $ git commit -q -a -m ff
193 193 $ echo fff >> f
194 194 $ git commit -q -a -m fff
195 195 $ git push origin testing 2>/dev/null
196 196
197 197 make and push changes to hg without updating the subrepo
198 198
199 199 $ cd ../t
200 200 $ hg clone . ../td
201 201 updating to branch default
202 202 cloning subrepo s from $TESTTMP/gitroot
203 203 checking out detached HEAD in subrepo s
204 204 check out a git branch if you intend to make changes
205 205 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 206 $ cd ../td
207 207 $ echo aa >> a
208 208 $ hg commit -m aa
209 209 $ hg push
210 210 pushing to $TESTTMP/t
211 211 searching for changes
212 212 adding changesets
213 213 adding manifests
214 214 adding file changes
215 215 added 1 changesets with 1 changes to 1 files
216 216
217 217 sync to upstream git, distribute changes
218 218
219 219 $ cd ../ta
220 220 $ hg pull -u -q
221 221 $ cd s
222 222 $ git pull -q >/dev/null 2>/dev/null
223 223 $ cd ..
224 224 $ hg commit -m 'git upstream sync'
225 225 committing subrepository s
226 226 $ hg debugsub
227 227 path s
228 228 source ../gitroot
229 229 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
230 230 $ hg push -q
231 231
232 232 $ cd ../tb
233 233 $ hg pull -q
234 234 $ hg update 2>/dev/null
235 235 pulling subrepo s from $TESTTMP/gitroot
236 236 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 237 $ hg debugsub
238 238 path s
239 239 source ../gitroot
240 240 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
241 241
242 242 update to a revision without the subrepo, keeping the local git repository
243 243
244 244 $ cd ../t
245 245 $ hg up 0
246 246 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
247 247 $ ls -a s
248 248 .
249 249 ..
250 250 .git
251 251
252 252 $ hg up 2
253 253 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 254 $ ls -a s
255 255 .
256 256 ..
257 257 .git
258 258 g
259 259
260 260 archive subrepos
261 261
262 262 $ cd ../tc
263 263 $ hg pull -q
264 264 $ hg archive --subrepos -r 5 ../archive 2>/dev/null
265 265 pulling subrepo s from $TESTTMP/gitroot
266 266 $ cd ../archive
267 267 $ cat s/f
268 268 f
269 269 $ cat s/g
270 270 g
271 271 gg
272 272 ggg
273 273
274 274 create nested repo
275 275
276 276 $ cd ..
277 277 $ hg init outer
278 278 $ cd outer
279 279 $ echo b>b
280 280 $ hg add b
281 281 $ hg commit -m b
282 282
283 283 $ hg clone ../t inner
284 284 updating to branch default
285 285 cloning subrepo s from $TESTTMP/gitroot
286 286 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 287 $ echo inner = inner > .hgsub
288 288 $ hg add .hgsub
289 289 $ hg commit -m 'nested sub'
290 290 committing subrepository inner
291 291
292 292 nested commit
293 293
294 294 $ echo ffff >> inner/s/f
295 295 $ hg status --subrepos
296 296 M inner/s/f
297 $ hg commit -m nested
297 $ hg commit --subrepos -m nested
298 298 committing subrepository inner
299 299 committing subrepository inner/s
300 300
301 301 nested archive
302 302
303 303 $ hg archive --subrepos ../narchive
304 304 $ ls ../narchive/inner/s | grep -v pax_global_header
305 305 f
306 306 g
307 307
308 308 relative source expansion
309 309
310 310 $ cd ..
311 311 $ mkdir d
312 312 $ hg clone t d/t
313 313 updating to branch default
314 314 cloning subrepo s from $TESTTMP/gitroot
315 315 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 316
317 317 Don't crash if the subrepo is missing
318 318
319 319 $ hg clone t missing -q
320 320 $ cd missing
321 321 $ rm -rf s
322 322 $ hg status -S
323 323 $ hg sum | grep commit
324 324 commit: 1 subrepos
325 325 $ hg push -q
326 326 abort: subrepo s is missing
327 327 [255]
328 $ hg commit -qm missing
328 $ hg commit --subrepos -qm missing
329 329 abort: subrepo s is missing
330 330 [255]
331 331 $ hg update -C
332 332 cloning subrepo s from $TESTTMP/gitroot
333 333 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 334 $ hg sum | grep commit
335 335 commit: (clean)
336 336
337 337 Don't crash if the .hgsubstate entry is missing
338 338
339 339 $ hg update 1 -q
340 340 $ hg rm .hgsubstate
341 341 $ hg commit .hgsubstate -m 'no substate'
342 342 created new head
343 343 $ hg tag -l nosubstate
344 344 $ hg manifest
345 345 .hgsub
346 346 a
347 347
348 348 $ hg status -S
349 349 $ hg sum | grep commit
350 350 commit: 1 subrepos
351 351
352 352 $ hg commit -m 'restore substate'
353 353 committing subrepository s
354 354 $ hg manifest
355 355 .hgsub
356 356 .hgsubstate
357 357 a
358 358 $ hg sum | grep commit
359 359 commit: (clean)
360 360
361 361 $ hg update -qC nosubstate
362 362 $ ls s
363 363
364 364 Check hg update --clean
365 365 $ cd $TESTTMP/ta
366 366 $ echo > s/g
367 367 $ cd s
368 368 $ echo c1 > f1
369 369 $ echo c1 > f2
370 370 $ git add f1
371 371 $ cd ..
372 372 $ hg status -S
373 373 M s/g
374 374 A s/f1
375 375 $ ls s
376 376 f
377 377 f1
378 378 f2
379 379 g
380 380 $ hg update --clean
381 381 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 382 $ hg status -S
383 383 $ ls s
384 384 f
385 385 f1
386 386 f2
387 387 g
388 388
389 389 Sticky subrepositories, no changes
390 390 $ cd $TESTTMP/ta
391 391 $ hg id -n
392 392 7
393 393 $ cd s
394 394 $ git rev-parse HEAD
395 395 32a343883b74769118bb1d3b4b1fbf9156f4dddc
396 396 $ cd ..
397 397 $ hg update 1 > /dev/null 2>&1
398 398 $ hg id -n
399 399 1
400 400 $ cd s
401 401 $ git rev-parse HEAD
402 402 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
403 403 $ cd ..
404 404
405 405 Sticky subrepositorys, file changes
406 406 $ touch s/f1
407 407 $ cd s
408 408 $ git add f1
409 409 $ cd ..
410 410 $ hg id -n
411 411 1
412 412 $ cd s
413 413 $ git rev-parse HEAD
414 414 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
415 415 $ cd ..
416 416 $ hg update 4
417 417 subrepository sources for s differ
418 418 use (l)ocal source (da5f5b1) or (r)emote source (aa84837)?
419 419 l
420 420 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 421 $ hg id -n
422 422 4+
423 423 $ cd s
424 424 $ git rev-parse HEAD
425 425 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
426 426 $ cd ..
427 427 $ hg update --clean tip > /dev/null 2>&1
428 428
429 429 Sticky subrepository, revision updates
430 430 $ hg id -n
431 431 7
432 432 $ cd s
433 433 $ git rev-parse HEAD
434 434 32a343883b74769118bb1d3b4b1fbf9156f4dddc
435 435 $ cd ..
436 436 $ cd s
437 437 $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
438 438 Previous HEAD position was 32a3438... fff
439 439 HEAD is now at aa84837... f
440 440 $ cd ..
441 441 $ hg update 1
442 442 subrepository sources for s differ (in checked out version)
443 443 use (l)ocal source (32a3438) or (r)emote source (da5f5b1)?
444 444 l
445 445 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
446 446 $ hg id -n
447 447 1+
448 448 $ cd s
449 449 $ git rev-parse HEAD
450 450 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
451 451 $ cd ..
452 452
453 453 Sticky subrepository, file changes and revision updates
454 454 $ touch s/f1
455 455 $ cd s
456 456 $ git add f1
457 457 $ git rev-parse HEAD
458 458 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
459 459 $ cd ..
460 460 $ hg id -n
461 461 1+
462 462 $ hg update 7
463 463 subrepository sources for s differ
464 464 use (l)ocal source (32a3438) or (r)emote source (32a3438)?
465 465 l
466 466 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
467 467 $ hg id -n
468 468 7
469 469 $ cd s
470 470 $ git rev-parse HEAD
471 471 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
472 472 $ cd ..
473 473
474 474 Sticky repository, update --clean
475 475 $ hg update --clean tip
476 476 Previous HEAD position was aa84837... f
477 477 HEAD is now at 32a3438... fff
478 478 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
479 479 $ hg id -n
480 480 7
481 481 $ cd s
482 482 $ git rev-parse HEAD
483 483 32a343883b74769118bb1d3b4b1fbf9156f4dddc
484 484 $ cd ..
485 485
486 486 Test subrepo already at intended revision:
487 487 $ cd s
488 488 $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
489 489 HEAD is now at 32a3438... fff
490 490 $ cd ..
491 491 $ hg update 1
492 492 Previous HEAD position was 32a3438... fff
493 493 HEAD is now at da5f5b1... g
494 494 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
495 495 $ hg id -n
496 496 1
497 497 $ cd s
498 498 $ git rev-parse HEAD
499 499 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
500 500 $ cd ..
501 501
@@ -1,470 +1,477 b''
1 1 Create test repository:
2 2
3 3 $ hg init repo
4 4 $ cd repo
5 5 $ echo x1 > x.txt
6 6
7 7 $ hg init foo
8 8 $ cd foo
9 9 $ echo y1 > y.txt
10 10
11 11 $ hg init bar
12 12 $ cd bar
13 13 $ echo z1 > z.txt
14 14
15 15 $ cd ..
16 16 $ echo 'bar = bar' > .hgsub
17 17
18 18 $ cd ..
19 19 $ echo 'foo = foo' > .hgsub
20 20
21 21 Add files --- .hgsub files must go first to trigger subrepos:
22 22
23 23 $ hg add -S .hgsub
24 24 $ hg add -S foo/.hgsub
25 25 $ hg add -S foo/bar
26 26 adding foo/bar/z.txt
27 27 $ hg add -S
28 28 adding x.txt
29 29 adding foo/y.txt
30 30
31 31 Test recursive status without committing anything:
32 32
33 33 $ hg status -S
34 34 A .hgsub
35 35 A foo/.hgsub
36 36 A foo/bar/z.txt
37 37 A foo/y.txt
38 38 A x.txt
39 39
40 40 Test recursive diff without committing anything:
41 41
42 42 $ hg diff --nodates -S foo
43 43 diff -r 000000000000 foo/.hgsub
44 44 --- /dev/null
45 45 +++ b/foo/.hgsub
46 46 @@ -0,0 +1,1 @@
47 47 +bar = bar
48 48 diff -r 000000000000 foo/y.txt
49 49 --- /dev/null
50 50 +++ b/foo/y.txt
51 51 @@ -0,0 +1,1 @@
52 52 +y1
53 53 diff -r 000000000000 foo/bar/z.txt
54 54 --- /dev/null
55 55 +++ b/foo/bar/z.txt
56 56 @@ -0,0 +1,1 @@
57 57 +z1
58 58
59 59 Commits:
60 60
61 $ hg commit -m 0-0-0
61 $ hg commit -m fails
62 abort: uncommitted changes in subrepo foo
63 (use --subrepos for recursive commit)
64 [255]
65
66 The --subrepos flag overwrite the config setting:
67
68 $ hg commit -m 0-0-0 --config ui.commitsubrepos=No --subrepos
62 69 committing subrepository foo
63 70 committing subrepository foo/bar
64 71
65 72 $ cd foo
66 73 $ echo y2 >> y.txt
67 74 $ hg commit -m 0-1-0
68 75
69 76 $ cd bar
70 77 $ echo z2 >> z.txt
71 78 $ hg commit -m 0-1-1
72 79
73 80 $ cd ..
74 81 $ hg commit -m 0-2-1
75 82 committing subrepository bar
76 83
77 84 $ cd ..
78 85 $ hg commit -m 1-2-1
79 86 committing subrepository foo
80 87
81 88 Change working directory:
82 89
83 90 $ echo y3 >> foo/y.txt
84 91 $ echo z3 >> foo/bar/z.txt
85 92 $ hg status -S
86 93 M foo/bar/z.txt
87 94 M foo/y.txt
88 95 $ hg diff --nodates -S
89 96 diff -r d254738c5f5e foo/y.txt
90 97 --- a/foo/y.txt
91 98 +++ b/foo/y.txt
92 99 @@ -1,2 +1,3 @@
93 100 y1
94 101 y2
95 102 +y3
96 103 diff -r 9647f22de499 foo/bar/z.txt
97 104 --- a/foo/bar/z.txt
98 105 +++ b/foo/bar/z.txt
99 106 @@ -1,2 +1,3 @@
100 107 z1
101 108 z2
102 109 +z3
103 110
104 111 Status call crossing repository boundaries:
105 112
106 113 $ hg status -S foo/bar/z.txt
107 114 M foo/bar/z.txt
108 115 $ hg status -S -I 'foo/?.txt'
109 116 M foo/y.txt
110 117 $ hg status -S -I '**/?.txt'
111 118 M foo/bar/z.txt
112 119 M foo/y.txt
113 120 $ hg diff --nodates -S -I '**/?.txt'
114 121 diff -r d254738c5f5e foo/y.txt
115 122 --- a/foo/y.txt
116 123 +++ b/foo/y.txt
117 124 @@ -1,2 +1,3 @@
118 125 y1
119 126 y2
120 127 +y3
121 128 diff -r 9647f22de499 foo/bar/z.txt
122 129 --- a/foo/bar/z.txt
123 130 +++ b/foo/bar/z.txt
124 131 @@ -1,2 +1,3 @@
125 132 z1
126 133 z2
127 134 +z3
128 135
129 136 Status from within a subdirectory:
130 137
131 138 $ mkdir dir
132 139 $ cd dir
133 140 $ echo a1 > a.txt
134 141 $ hg status -S
135 142 M foo/bar/z.txt
136 143 M foo/y.txt
137 144 ? dir/a.txt
138 145 $ hg diff --nodates -S
139 146 diff -r d254738c5f5e foo/y.txt
140 147 --- a/foo/y.txt
141 148 +++ b/foo/y.txt
142 149 @@ -1,2 +1,3 @@
143 150 y1
144 151 y2
145 152 +y3
146 153 diff -r 9647f22de499 foo/bar/z.txt
147 154 --- a/foo/bar/z.txt
148 155 +++ b/foo/bar/z.txt
149 156 @@ -1,2 +1,3 @@
150 157 z1
151 158 z2
152 159 +z3
153 160
154 161 Status with relative path:
155 162
156 163 $ hg status -S ..
157 164 M ../foo/bar/z.txt
158 165 M ../foo/y.txt
159 166 ? a.txt
160 167 $ hg diff --nodates -S ..
161 168 diff -r d254738c5f5e foo/y.txt
162 169 --- a/foo/y.txt
163 170 +++ b/foo/y.txt
164 171 @@ -1,2 +1,3 @@
165 172 y1
166 173 y2
167 174 +y3
168 175 diff -r 9647f22de499 foo/bar/z.txt
169 176 --- a/foo/bar/z.txt
170 177 +++ b/foo/bar/z.txt
171 178 @@ -1,2 +1,3 @@
172 179 z1
173 180 z2
174 181 +z3
175 182 $ cd ..
176 183
177 184 Cleanup and final commit:
178 185
179 186 $ rm -r dir
180 $ hg commit -m 2-3-2
187 $ hg commit --subrepos -m 2-3-2
181 188 committing subrepository foo
182 189 committing subrepository foo/bar
183 190
184 191 Log with the relationships between repo and its subrepo:
185 192
186 193 $ hg log --template '{rev}:{node|short} {desc}\n'
187 194 2:1326fa26d0c0 2-3-2
188 195 1:4b3c9ff4f66b 1-2-1
189 196 0:23376cbba0d8 0-0-0
190 197
191 198 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
192 199 3:65903cebad86 2-3-2
193 200 2:d254738c5f5e 0-2-1
194 201 1:8629ce7dcc39 0-1-0
195 202 0:af048e97ade2 0-0-0
196 203
197 204 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
198 205 2:31ecbdafd357 2-3-2
199 206 1:9647f22de499 0-1-1
200 207 0:4904098473f9 0-0-0
201 208
202 209 Status between revisions:
203 210
204 211 $ hg status -S
205 212 $ hg status -S --rev 0:1
206 213 M .hgsubstate
207 214 M foo/.hgsubstate
208 215 M foo/bar/z.txt
209 216 M foo/y.txt
210 217 $ hg diff --nodates -S -I '**/?.txt' --rev 0:1
211 218 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
212 219 --- a/foo/y.txt
213 220 +++ b/foo/y.txt
214 221 @@ -1,1 +1,2 @@
215 222 y1
216 223 +y2
217 224 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
218 225 --- a/foo/bar/z.txt
219 226 +++ b/foo/bar/z.txt
220 227 @@ -1,1 +1,2 @@
221 228 z1
222 229 +z2
223 230
224 231 Enable progress extension for archive tests:
225 232
226 233 $ cp $HGRCPATH $HGRCPATH.no-progress
227 234 $ cat >> $HGRCPATH <<EOF
228 235 > [extensions]
229 236 > progress =
230 237 > [progress]
231 238 > assume-tty = 1
232 239 > delay = 0
233 240 > format = topic bar number
234 241 > refresh = 0
235 242 > width = 60
236 243 > EOF
237 244
238 245 Test archiving to a directory tree (the doubled lines in the output
239 246 only show up in the test output, not in real usage):
240 247
241 248 $ hg archive --subrepos ../archive 2>&1 | $TESTDIR/filtercr.py
242 249
243 250 archiving [ ] 0/3
244 251 archiving [ ] 0/3
245 252 archiving [=============> ] 1/3
246 253 archiving [=============> ] 1/3
247 254 archiving [===========================> ] 2/3
248 255 archiving [===========================> ] 2/3
249 256 archiving [==========================================>] 3/3
250 257 archiving [==========================================>] 3/3
251 258
252 259 archiving (foo) [ ] 0/3
253 260 archiving (foo) [ ] 0/3
254 261 archiving (foo) [===========> ] 1/3
255 262 archiving (foo) [===========> ] 1/3
256 263 archiving (foo) [=======================> ] 2/3
257 264 archiving (foo) [=======================> ] 2/3
258 265 archiving (foo) [====================================>] 3/3
259 266 archiving (foo) [====================================>] 3/3
260 267
261 268 archiving (foo/bar) [ ] 0/1
262 269 archiving (foo/bar) [ ] 0/1
263 270 archiving (foo/bar) [================================>] 1/1
264 271 archiving (foo/bar) [================================>] 1/1
265 272 \r (esc)
266 273 $ find ../archive | sort
267 274 ../archive
268 275 ../archive/.hg_archival.txt
269 276 ../archive/.hgsub
270 277 ../archive/.hgsubstate
271 278 ../archive/foo
272 279 ../archive/foo/.hgsub
273 280 ../archive/foo/.hgsubstate
274 281 ../archive/foo/bar
275 282 ../archive/foo/bar/z.txt
276 283 ../archive/foo/y.txt
277 284 ../archive/x.txt
278 285
279 286 Test archiving to zip file (unzip output is unstable):
280 287
281 288 $ hg archive --subrepos ../archive.zip 2>&1 | $TESTDIR/filtercr.py
282 289
283 290 archiving [ ] 0/3
284 291 archiving [ ] 0/3
285 292 archiving [=============> ] 1/3
286 293 archiving [=============> ] 1/3
287 294 archiving [===========================> ] 2/3
288 295 archiving [===========================> ] 2/3
289 296 archiving [==========================================>] 3/3
290 297 archiving [==========================================>] 3/3
291 298
292 299 archiving (foo) [ ] 0/3
293 300 archiving (foo) [ ] 0/3
294 301 archiving (foo) [===========> ] 1/3
295 302 archiving (foo) [===========> ] 1/3
296 303 archiving (foo) [=======================> ] 2/3
297 304 archiving (foo) [=======================> ] 2/3
298 305 archiving (foo) [====================================>] 3/3
299 306 archiving (foo) [====================================>] 3/3
300 307
301 308 archiving (foo/bar) [ ] 0/1
302 309 archiving (foo/bar) [ ] 0/1
303 310 archiving (foo/bar) [================================>] 1/1
304 311 archiving (foo/bar) [================================>] 1/1
305 312 \r (esc)
306 313
307 314 Test archiving a revision that references a subrepo that is not yet
308 315 cloned:
309 316
310 317 $ hg clone -U . ../empty
311 318 $ cd ../empty
312 319 $ hg archive --subrepos -r tip ../archive.tar.gz 2>&1 | $TESTDIR/filtercr.py
313 320
314 321 archiving [ ] 0/3
315 322 archiving [ ] 0/3
316 323 archiving [=============> ] 1/3
317 324 archiving [=============> ] 1/3
318 325 archiving [===========================> ] 2/3
319 326 archiving [===========================> ] 2/3
320 327 archiving [==========================================>] 3/3
321 328 archiving [==========================================>] 3/3
322 329
323 330 archiving (foo) [ ] 0/3
324 331 archiving (foo) [ ] 0/3
325 332 archiving (foo) [===========> ] 1/3
326 333 archiving (foo) [===========> ] 1/3
327 334 archiving (foo) [=======================> ] 2/3
328 335 archiving (foo) [=======================> ] 2/3
329 336 archiving (foo) [====================================>] 3/3
330 337 archiving (foo) [====================================>] 3/3
331 338
332 339 archiving (foo/bar) [ ] 0/1
333 340 archiving (foo/bar) [ ] 0/1
334 341 archiving (foo/bar) [================================>] 1/1
335 342 archiving (foo/bar) [================================>] 1/1
336 343
337 344 cloning subrepo foo from $TESTTMP/repo/foo
338 345 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar
339 346
340 347 The newly cloned subrepos contain no working copy:
341 348
342 349 $ hg -R foo summary
343 350 parent: -1:000000000000 (no revision checked out)
344 351 branch: default
345 352 commit: (clean)
346 353 update: 4 new changesets (update)
347 354
348 355 Disable progress extension and cleanup:
349 356
350 357 $ mv $HGRCPATH.no-progress $HGRCPATH
351 358
352 359 Test archiving when there is a directory in the way for a subrepo
353 360 created by archive:
354 361
355 362 $ hg clone -U . ../almost-empty
356 363 $ cd ../almost-empty
357 364 $ mkdir foo
358 365 $ echo f > foo/f
359 366 $ hg archive --subrepos -r tip archive
360 367 cloning subrepo foo from $TESTTMP/empty/foo
361 368 abort: destination '$TESTTMP/almost-empty/foo' is not empty
362 369 [255]
363 370
364 371 Clone and test outgoing:
365 372
366 373 $ cd ..
367 374 $ hg clone repo repo2
368 375 updating to branch default
369 376 cloning subrepo foo from $TESTTMP/repo/foo
370 377 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar
371 378 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 379 $ cd repo2
373 380 $ hg outgoing -S
374 381 comparing with $TESTTMP/repo
375 382 searching for changes
376 383 no changes found
377 384 comparing with $TESTTMP/repo/foo
378 385 searching for changes
379 386 no changes found
380 387 comparing with $TESTTMP/repo/foo/bar
381 388 searching for changes
382 389 no changes found
383 390 [1]
384 391
385 392 Make nested change:
386 393
387 394 $ echo y4 >> foo/y.txt
388 395 $ hg diff --nodates -S
389 396 diff -r 65903cebad86 foo/y.txt
390 397 --- a/foo/y.txt
391 398 +++ b/foo/y.txt
392 399 @@ -1,3 +1,4 @@
393 400 y1
394 401 y2
395 402 y3
396 403 +y4
397 $ hg commit -m 3-4-2
404 $ hg commit --subrepos -m 3-4-2
398 405 committing subrepository foo
399 406 $ hg outgoing -S
400 407 comparing with $TESTTMP/repo
401 408 searching for changes
402 409 changeset: 3:2655b8ecc4ee
403 410 tag: tip
404 411 user: test
405 412 date: Thu Jan 01 00:00:00 1970 +0000
406 413 summary: 3-4-2
407 414
408 415 comparing with $TESTTMP/repo/foo
409 416 searching for changes
410 417 changeset: 4:e96193d6cb36
411 418 tag: tip
412 419 user: test
413 420 date: Thu Jan 01 00:00:00 1970 +0000
414 421 summary: 3-4-2
415 422
416 423 comparing with $TESTTMP/repo/foo/bar
417 424 searching for changes
418 425 no changes found
419 426
420 427
421 428 Switch to original repo and setup default path:
422 429
423 430 $ cd ../repo
424 431 $ echo '[paths]' >> .hg/hgrc
425 432 $ echo 'default = ../repo2' >> .hg/hgrc
426 433
427 434 Test incoming:
428 435
429 436 $ hg incoming -S
430 437 comparing with $TESTTMP/repo2
431 438 searching for changes
432 439 changeset: 3:2655b8ecc4ee
433 440 tag: tip
434 441 user: test
435 442 date: Thu Jan 01 00:00:00 1970 +0000
436 443 summary: 3-4-2
437 444
438 445 comparing with $TESTTMP/repo2/foo
439 446 searching for changes
440 447 changeset: 4:e96193d6cb36
441 448 tag: tip
442 449 user: test
443 450 date: Thu Jan 01 00:00:00 1970 +0000
444 451 summary: 3-4-2
445 452
446 453 comparing with $TESTTMP/repo2/foo/bar
447 454 searching for changes
448 455 no changes found
449 456
450 457 $ hg incoming -S --bundle incoming.hg
451 458 abort: cannot combine --bundle and --subrepos
452 459 [255]
453 460
454 461 Test missing subrepo:
455 462
456 463 $ rm -r foo
457 464 $ hg status -S
458 465 warning: error "unknown revision '65903cebad86f1a84bd4f1134f62fa7dcb7a1c98'" in subrepository "foo"
459 466
460 467 Issue2619: IndexError: list index out of range on hg add with subrepos
461 468 The subrepo must sorts after the explicit filename.
462 469
463 470 $ cd ..
464 471 $ hg init test
465 472 $ cd test
466 473 $ hg init x
467 474 $ echo "x = x" >> .hgsub
468 475 $ hg add .hgsub
469 476 $ touch a x/a
470 477 $ hg add a x/a
@@ -1,585 +1,585 b''
1 1 $ "$TESTDIR/hghave" svn || exit 80
2 2
3 3 $ fix_path()
4 4 > {
5 5 > tr '\\' /
6 6 > }
7 7
8 8 SVN wants all paths to start with a slash. Unfortunately, Windows ones
9 9 don't. Handle that.
10 10
11 11 $ escapedwd=`pwd | fix_path`
12 12 $ expr "$escapedwd" : '\/' > /dev/null || escapedwd="/$escapedwd"
13 13 $ escapedwd=`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$escapedwd"`
14 14
15 15 create subversion repo
16 16
17 17 $ SVNREPO="file://$escapedwd/svn-repo"
18 18 $ WCROOT="`pwd`/svn-wc"
19 19 $ svnadmin create svn-repo
20 20 $ svn co "$SVNREPO" svn-wc
21 21 Checked out revision 0.
22 22 $ cd svn-wc
23 23 $ mkdir src
24 24 $ echo alpha > src/alpha
25 25 $ svn add src
26 26 A src
27 27 A src/alpha
28 28 $ mkdir externals
29 29 $ echo other > externals/other
30 30 $ svn add externals
31 31 A externals
32 32 A externals/other
33 33 $ svn ci -m 'Add alpha'
34 34 Adding externals
35 35 Adding externals/other
36 36 Adding src
37 37 Adding src/alpha
38 38 Transmitting file data ..
39 39 Committed revision 1.
40 40 $ svn up
41 41 At revision 1.
42 42 $ echo "externals -r1 $SVNREPO/externals" > extdef
43 43 $ svn propset -F extdef svn:externals src
44 44 property 'svn:externals' set on 'src'
45 45 $ svn ci -m 'Setting externals'
46 46 Sending src
47 47
48 48 Committed revision 2.
49 49 $ cd ..
50 50
51 51 create hg repo
52 52
53 53 $ mkdir sub
54 54 $ cd sub
55 55 $ hg init t
56 56 $ cd t
57 57
58 58 first revision, no sub
59 59
60 60 $ echo a > a
61 61 $ hg ci -Am0
62 62 adding a
63 63
64 64 add first svn sub with leading whitespaces
65 65
66 66 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
67 67 $ echo "subdir/s = [svn] $SVNREPO/src" >> .hgsub
68 68 $ svn co --quiet "$SVNREPO"/src s
69 69 $ mkdir subdir
70 70 $ svn co --quiet "$SVNREPO"/src subdir/s
71 71 $ hg add .hgsub
72 72 $ hg ci -m1
73 73 committing subrepository s
74 74 committing subrepository subdir/s
75 75
76 76 make sure we avoid empty commits (issue2445)
77 77
78 78 $ hg sum
79 79 parent: 1:* tip (glob)
80 80 1
81 81 branch: default
82 82 commit: (clean)
83 83 update: (current)
84 84 $ hg ci -moops
85 85 nothing changed
86 86 [1]
87 87
88 88 debugsub
89 89
90 90 $ hg debugsub
91 91 path s
92 92 source file://*/svn-repo/src (glob)
93 93 revision 2
94 94 path subdir/s
95 95 source file://*/svn-repo/src (glob)
96 96 revision 2
97 97
98 98 change file in svn and hg, commit
99 99
100 100 $ echo a >> a
101 101 $ echo alpha >> s/alpha
102 102 $ hg sum
103 103 parent: 1:* tip (glob)
104 104 1
105 105 branch: default
106 106 commit: 1 modified, 1 subrepos
107 107 update: (current)
108 $ hg commit -m 'Message!'
108 $ hg commit --subrepos -m 'Message!'
109 109 committing subrepository s
110 110 Sending*s/alpha (glob)
111 111 Transmitting file data .
112 112 Committed revision 3.
113 113
114 114 Fetching external item into '$TESTTMP/sub/t/s/externals'
115 115 External at revision 1.
116 116
117 117 At revision 3.
118 118 $ hg debugsub
119 119 path s
120 120 source file://*/svn-repo/src (glob)
121 121 revision 3
122 122 path subdir/s
123 123 source file://*/svn-repo/src (glob)
124 124 revision 2
125 125
126 126 add an unrelated revision in svn and update the subrepo to without
127 127 bringing any changes.
128 128
129 129 $ svn mkdir "$SVNREPO/unrelated" -m 'create unrelated'
130 130
131 131 Committed revision 4.
132 132 $ svn up s
133 133
134 134 Fetching external item into 's/externals'
135 135 External at revision 1.
136 136
137 137 At revision 4.
138 138 $ hg sum
139 139 parent: 2:* tip (glob)
140 140 Message!
141 141 branch: default
142 142 commit: (clean)
143 143 update: (current)
144 144
145 145 $ echo a > s/a
146 146
147 147 should be empty despite change to s/a
148 148
149 149 $ hg st
150 150
151 151 add a commit from svn
152 152
153 153 $ cd "$WCROOT"/src
154 154 $ svn up
155 155 U alpha
156 156
157 157 Fetching external item into 'externals'
158 158 A externals/other
159 159 Updated external to revision 1.
160 160
161 161 Updated to revision 4.
162 162 $ echo xyz >> alpha
163 163 $ svn propset svn:mime-type 'text/xml' alpha
164 164 property 'svn:mime-type' set on 'alpha'
165 165 $ svn ci -m 'amend a from svn'
166 166 Sending src/alpha
167 167 Transmitting file data .
168 168 Committed revision 5.
169 169 $ cd ../../sub/t
170 170
171 171 this commit from hg will fail
172 172
173 173 $ echo zzz >> s/alpha
174 $ hg ci -m 'amend alpha from hg'
174 $ hg ci --subrepos -m 'amend alpha from hg'
175 175 committing subrepository s
176 176 abort: svn: Commit failed (details follow):
177 177 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
178 178 [255]
179 179 $ svn revert -q s/alpha
180 180
181 181 this commit fails because of meta changes
182 182
183 183 $ svn propset svn:mime-type 'text/html' s/alpha
184 184 property 'svn:mime-type' set on 's/alpha'
185 $ hg ci -m 'amend alpha from hg'
185 $ hg ci --subrepos -m 'amend alpha from hg'
186 186 committing subrepository s
187 187 abort: svn: Commit failed (details follow):
188 188 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
189 189 [255]
190 190 $ svn revert -q s/alpha
191 191
192 192 this commit fails because of externals changes
193 193
194 194 $ echo zzz > s/externals/other
195 $ hg ci -m 'amend externals from hg'
195 $ hg ci --subrepos -m 'amend externals from hg'
196 196 committing subrepository s
197 197 abort: cannot commit svn externals
198 198 [255]
199 199 $ hg diff --subrepos -r 1:2 | grep -v diff
200 200 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
201 201 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
202 202 @@ -1,2 +1,2 @@
203 203 -2 s
204 204 +3 s
205 205 2 subdir/s
206 206 --- a/a Thu Jan 01 00:00:00 1970 +0000
207 207 +++ b/a Thu Jan 01 00:00:00 1970 +0000
208 208 @@ -1,1 +1,2 @@
209 209 a
210 210 +a
211 211 $ svn revert -q s/externals/other
212 212
213 213 this commit fails because of externals meta changes
214 214
215 215 $ svn propset svn:mime-type 'text/html' s/externals/other
216 216 property 'svn:mime-type' set on 's/externals/other'
217 $ hg ci -m 'amend externals from hg'
217 $ hg ci --subrepos -m 'amend externals from hg'
218 218 committing subrepository s
219 219 abort: cannot commit svn externals
220 220 [255]
221 221 $ svn revert -q s/externals/other
222 222
223 223 clone
224 224
225 225 $ cd ..
226 226 $ hg clone t tc | fix_path
227 227 updating to branch default
228 228 A tc/s/alpha
229 229 U tc/s
230 230
231 231 Fetching external item into 'tc/s/externals'
232 232 A tc/s/externals/other
233 233 Checked out external at revision 1.
234 234
235 235 Checked out revision 3.
236 236 A tc/subdir/s/alpha
237 237 U tc/subdir/s
238 238
239 239 Fetching external item into 'tc/subdir/s/externals'
240 240 A tc/subdir/s/externals/other
241 241 Checked out external at revision 1.
242 242
243 243 Checked out revision 2.
244 244 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 245 $ cd tc
246 246
247 247 debugsub in clone
248 248
249 249 $ hg debugsub
250 250 path s
251 251 source file://*/svn-repo/src (glob)
252 252 revision 3
253 253 path subdir/s
254 254 source file://*/svn-repo/src (glob)
255 255 revision 2
256 256
257 257 verify subrepo is contained within the repo directory
258 258
259 259 $ python -c "import os.path; print os.path.exists('s')"
260 260 True
261 261
262 262 update to nullrev (must delete the subrepo)
263 263
264 264 $ hg up null
265 265 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
266 266 $ ls
267 267
268 268 Check hg update --clean
269 269 $ cd $TESTTMP/sub/t
270 270 $ cd s
271 271 $ echo c0 > alpha
272 272 $ echo c1 > f1
273 273 $ echo c1 > f2
274 274 $ svn add f1 -q
275 275 $ svn status
276 276 ? * a (glob)
277 277 X * externals (glob)
278 278 ? * f2 (glob)
279 279 M * alpha (glob)
280 280 A * f1 (glob)
281 281
282 282 Performing status on external item at 'externals'
283 283 $ cd ../..
284 284 $ hg -R t update -C
285 285
286 286 Fetching external item into 't/s/externals'
287 287 Checked out external at revision 1.
288 288
289 289 Checked out revision 3.
290 290 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
291 291 $ cd t/s
292 292 $ svn status
293 293 ? * a (glob)
294 294 X * externals (glob)
295 295 ? * f1 (glob)
296 296 ? * f2 (glob)
297 297
298 298 Performing status on external item at 'externals'
299 299
300 300 Sticky subrepositories, no changes
301 301 $ cd $TESTTMP/sub/t
302 302 $ hg id -n
303 303 2
304 304 $ cd s
305 305 $ svnversion
306 306 3
307 307 $ cd ..
308 308 $ hg update 1
309 309 U $TESTTMP/sub/t/s/alpha
310 310
311 311 Fetching external item into '$TESTTMP/sub/t/s/externals'
312 312 Checked out external at revision 1.
313 313
314 314 Checked out revision 2.
315 315 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 316 $ hg id -n
317 317 1
318 318 $ cd s
319 319 $ svnversion
320 320 2
321 321 $ cd ..
322 322
323 323 Sticky subrepositorys, file changes
324 324 $ touch s/f1
325 325 $ cd s
326 326 $ svn add f1
327 327 A f1
328 328 $ cd ..
329 329 $ hg id -n
330 330 1
331 331 $ cd s
332 332 $ svnversion
333 333 2M
334 334 $ cd ..
335 335 $ hg update tip
336 336 subrepository sources for s differ
337 337 use (l)ocal source (2) or (r)emote source (3)?
338 338 l
339 339 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 340 $ hg id -n
341 341 2+
342 342 $ cd s
343 343 $ svnversion
344 344 2M
345 345 $ cd ..
346 346 $ hg update --clean tip
347 347 U $TESTTMP/sub/t/s/alpha
348 348
349 349 Fetching external item into '$TESTTMP/sub/t/s/externals'
350 350 Checked out external at revision 1.
351 351
352 352 Checked out revision 3.
353 353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
354 354
355 355 Sticky subrepository, revision updates
356 356 $ hg id -n
357 357 2
358 358 $ cd s
359 359 $ svnversion
360 360 3
361 361 $ cd ..
362 362 $ cd s
363 363 $ svn update -r 1
364 364 U alpha
365 365 U .
366 366
367 367 Fetching external item into 'externals'
368 368 Updated external to revision 1.
369 369
370 370 Updated to revision 1.
371 371 $ cd ..
372 372 $ hg update 1
373 373 subrepository sources for s differ (in checked out version)
374 374 use (l)ocal source (1) or (r)emote source (2)?
375 375 l
376 376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 377 $ hg id -n
378 378 1+
379 379 $ cd s
380 380 $ svnversion
381 381 1
382 382 $ cd ..
383 383
384 384 Sticky subrepository, file changes and revision updates
385 385 $ touch s/f1
386 386 $ cd s
387 387 $ svn add f1
388 388 A f1
389 389 $ svnversion
390 390 1M
391 391 $ cd ..
392 392 $ hg id -n
393 393 1+
394 394 $ hg update tip
395 395 subrepository sources for s differ
396 396 use (l)ocal source (1) or (r)emote source (3)?
397 397 l
398 398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 399 $ hg id -n
400 400 2
401 401 $ cd s
402 402 $ svnversion
403 403 1M
404 404 $ cd ..
405 405
406 406 Sticky repository, update --clean
407 407 $ hg update --clean tip
408 408 U $TESTTMP/sub/t/s/alpha
409 409 U $TESTTMP/sub/t/s
410 410
411 411 Fetching external item into '$TESTTMP/sub/t/s/externals'
412 412 Checked out external at revision 1.
413 413
414 414 Checked out revision 3.
415 415 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 416 $ hg id -n
417 417 2
418 418 $ cd s
419 419 $ svnversion
420 420 3
421 421 $ cd ..
422 422
423 423 Test subrepo already at intended revision:
424 424 $ cd s
425 425 $ svn update -r 2
426 426 U alpha
427 427
428 428 Fetching external item into 'externals'
429 429 Updated external to revision 1.
430 430
431 431 Updated to revision 2.
432 432 $ cd ..
433 433 $ hg update 1
434 434 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
435 435 $ hg id -n
436 436 1+
437 437 $ cd s
438 438 $ svnversion
439 439 2
440 440 $ cd ..
441 441
442 442 Test case where subversion would fail to update the subrepo because there
443 443 are unknown directories being replaced by tracked ones (happens with rebase).
444 444
445 445 $ cd $WCROOT/src
446 446 $ mkdir dir
447 447 $ echo epsilon.py > dir/epsilon.py
448 448 $ svn add dir
449 449 A dir
450 450 A dir/epsilon.py
451 451 $ svn ci -m 'Add dir/epsilon.py'
452 452 Adding src/dir
453 453 Adding src/dir/epsilon.py
454 454 Transmitting file data .
455 455 Committed revision 6.
456 456 $ cd ../..
457 457 $ hg init rebaserepo
458 458 $ cd rebaserepo
459 459 $ svn co -r5 --quiet "$SVNREPO"/src s
460 460 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
461 461 $ hg add .hgsub
462 462 $ hg ci -m addsub
463 463 committing subrepository s
464 464 $ echo a > a
465 465 $ hg ci -Am adda
466 466 adding a
467 467 $ hg up 0
468 468 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
469 469 $ svn up -r6 s
470 470 A s/dir
471 471 A s/dir/epsilon.py
472 472
473 473 Fetching external item into 's/externals'
474 474 Updated external to revision 1.
475 475
476 476 Updated to revision 6.
477 477 $ hg ci -m updatesub
478 478 committing subrepository s
479 479 created new head
480 480 $ echo pyc > s/dir/epsilon.pyc
481 481 $ hg up 1
482 482 D $TESTTMP/rebaserepo/s/dir
483 483
484 484 Fetching external item into '$TESTTMP/rebaserepo/s/externals'
485 485 Checked out external at revision 1.
486 486
487 487 Checked out revision 5.
488 488 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 489 $ if "$TESTDIR/hghave" -q svn15; then
490 490 > hg up 2 >/dev/null 2>&1 || echo update failed
491 491 > fi
492 492
493 493 Modify one of the externals to point to a different path so we can
494 494 test having obstructions when switching branches on checkout:
495 495 $ hg checkout tip
496 496 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
497 497 $ echo "obstruct = [svn] $SVNREPO/externals" >> .hgsub
498 498 $ svn co -r5 --quiet "$SVNREPO"/externals obstruct
499 499 $ hg commit -m 'Start making obstructed wc'
500 500 committing subrepository obstruct
501 501 $ hg book other
502 502 $ hg co -r 'p1(tip)'
503 503 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
504 504 $ echo "obstruct = [svn] $SVNREPO/src" >> .hgsub
505 505 $ svn co -r5 --quiet "$SVNREPO"/src obstruct
506 506 $ hg commit -m 'Other branch which will be obstructed'
507 507 committing subrepository obstruct
508 508 created new head
509 509
510 510 Switching back to the head where we have another path mapped to the
511 511 same subrepo should work if the subrepo is clean.
512 512 $ hg co other
513 513 A $TESTTMP/rebaserepo/obstruct/other
514 514 Checked out revision 1.
515 515 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 516
517 517 This is surprising, but is also correct based on the current code:
518 518 $ echo "updating should (maybe) fail" > obstruct/other
519 519 $ hg co tip
520 520 abort: crosses branches (merge branches or use --clean to discard changes)
521 521 [255]
522 522
523 523 Point to a Subversion branch which has since been deleted and recreated
524 524 First, create that condition in the repository.
525 525
526 $ hg ci -m cleanup
526 $ hg ci --subrepos -m cleanup
527 527 committing subrepository obstruct
528 528 Sending obstruct/other
529 529 Transmitting file data .
530 530 Committed revision 7.
531 531 At revision 7.
532 532 $ svn mkdir -m "baseline" $SVNREPO/trunk
533 533
534 534 Committed revision 8.
535 535 $ svn copy -m "initial branch" $SVNREPO/trunk $SVNREPO/branch
536 536
537 537 Committed revision 9.
538 538 $ svn co --quiet "$SVNREPO"/branch tempwc
539 539 $ cd tempwc
540 540 $ echo "something old" > somethingold
541 541 $ svn add somethingold
542 542 A somethingold
543 543 $ svn ci -m 'Something old'
544 544 Adding somethingold
545 545 Transmitting file data .
546 546 Committed revision 10.
547 547 $ svn rm -m "remove branch" $SVNREPO/branch
548 548
549 549 Committed revision 11.
550 550 $ svn copy -m "recreate branch" $SVNREPO/trunk $SVNREPO/branch
551 551
552 552 Committed revision 12.
553 553 $ svn up
554 554 D somethingold
555 555 Updated to revision 12.
556 556 $ echo "something new" > somethingnew
557 557 $ svn add somethingnew
558 558 A somethingnew
559 559 $ svn ci -m 'Something new'
560 560 Adding somethingnew
561 561 Transmitting file data .
562 562 Committed revision 13.
563 563 $ cd ..
564 564 $ rm -rf tempwc
565 565 $ svn co "$SVNREPO/branch"@10 recreated
566 566 A recreated/somethingold
567 567 Checked out revision 10.
568 568 $ echo "recreated = [svn] $SVNREPO/branch" >> .hgsub
569 569 $ hg ci -m addsub
570 570 committing subrepository recreated
571 571 $ cd recreated
572 572 $ svn up
573 573 D somethingold
574 574 A somethingnew
575 575 Updated to revision 13.
576 576 $ cd ..
577 577 $ hg ci -m updatesub
578 578 committing subrepository recreated
579 579 $ hg up -r-2
580 580 D $TESTTMP/rebaserepo/recreated/somethingnew
581 581 A $TESTTMP/rebaserepo/recreated/somethingold
582 582 Checked out revision 10.
583 583 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 584 $ test -f recreated/somethingold
585 585
@@ -1,879 +1,885 b''
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5
1 6 $ rm -rf sub
2 7 $ mkdir sub
3 8 $ cd sub
4 9 $ hg init t
5 10 $ cd t
6 11
7 12 first revision, no sub
8 13
9 14 $ echo a > a
10 15 $ hg ci -Am0
11 16 adding a
12 17
13 18 add first sub
14 19
15 20 $ echo s = s > .hgsub
16 21 $ hg add .hgsub
17 22 $ hg init s
18 23 $ echo a > s/a
19 24
20 25 Issue2232: committing a subrepo without .hgsub
21 26
22 27 $ hg ci -mbad s
23 28 abort: can't commit subrepos without .hgsub
24 29 [255]
25 30
26 31 $ hg -R s ci -Ams0
27 32 adding a
28 33 $ hg sum
29 34 parent: 0:f7b1eb17ad24 tip
30 35 0
31 36 branch: default
32 37 commit: 1 added, 1 subrepos
33 38 update: (current)
34 39 $ hg ci -m1
35 40 committing subrepository s
36 41
37 42 Revert can't (yet) revert subrepos:
38 43
39 44 $ echo b > s/a
40 45 $ hg revert s
41 46 s: reverting subrepos is unsupported
42 47
43 48 Revert currently ignores subrepos by default
44 49
45 50 $ hg revert -a
46 51 $ hg revert -R s -a -C
47 52 reverting s/a
48 53
49 54 Issue2022: update -C
50 55
51 56 $ echo b > s/a
52 57 $ hg sum
53 58 parent: 1:7cf8cfea66e4 tip
54 59 1
55 60 branch: default
56 61 commit: 1 subrepos
57 62 update: (current)
58 63 $ hg co -C 1
59 64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 65 $ hg sum
61 66 parent: 1:7cf8cfea66e4 tip
62 67 1
63 68 branch: default
64 69 commit: (clean)
65 70 update: (current)
66 71
67 72 commands that require a clean repo should respect subrepos
68 73
69 74 $ echo b >> s/a
70 75 $ hg backout tip
71 76 abort: uncommitted changes in subrepo s
72 77 [255]
73 78 $ hg revert -C -R s s/a
74 79
75 80 add sub sub
76 81
77 82 $ echo ss = ss > s/.hgsub
78 83 $ hg init s/ss
79 84 $ echo a > s/ss/a
80 85 $ hg -R s add s/.hgsub
81 86 $ hg -R s/ss add s/ss/a
82 87 $ hg sum
83 88 parent: 1:7cf8cfea66e4 tip
84 89 1
85 90 branch: default
86 91 commit: 1 subrepos
87 92 update: (current)
88 93 $ hg ci -m2
89 94 committing subrepository s
90 95 committing subrepository s/ss
91 96 $ hg sum
92 97 parent: 2:df30734270ae tip
93 98 2
94 99 branch: default
95 100 commit: (clean)
96 101 update: (current)
97 102
98 103 bump sub rev (and check it is ignored by ui.commitsubrepos)
99 104
100 105 $ echo b > s/a
101 106 $ hg -R s ci -ms1
102 107 $ hg --config ui.commitsubrepos=no ci -m3
103 108 committing subrepository s
104 109
105 110 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
106 111
107 112 $ echo c > s/a
108 113 $ hg --config ui.commitsubrepos=no ci -m4
109 114 abort: uncommitted changes in subrepo s
115 (use --subrepos for recursive commit)
110 116 [255]
111 117 $ hg ci -m4
112 118 committing subrepository s
113 119 $ hg tip -R s
114 120 changeset: 3:1c833a7a9e3a
115 121 tag: tip
116 122 user: test
117 123 date: Thu Jan 01 00:00:00 1970 +0000
118 124 summary: 4
119 125
120 126
121 127 check caching
122 128
123 129 $ hg co 0
124 130 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
125 131 $ hg debugsub
126 132
127 133 restore
128 134
129 135 $ hg co
130 136 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
131 137 $ hg debugsub
132 138 path s
133 139 source s
134 140 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
135 141
136 142 new branch for merge tests
137 143
138 144 $ hg co 1
139 145 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 146 $ echo t = t >> .hgsub
141 147 $ hg init t
142 148 $ echo t > t/t
143 149 $ hg -R t add t
144 150 adding t/t
145 151
146 152 5
147 153
148 154 $ hg ci -m5 # add sub
149 155 committing subrepository t
150 156 created new head
151 157 $ echo t2 > t/t
152 158
153 159 6
154 160
155 161 $ hg st -R s
156 162 $ hg ci -m6 # change sub
157 163 committing subrepository t
158 164 $ hg debugsub
159 165 path s
160 166 source s
161 167 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
162 168 path t
163 169 source t
164 170 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
165 171 $ echo t3 > t/t
166 172
167 173 7
168 174
169 175 $ hg ci -m7 # change sub again for conflict test
170 176 committing subrepository t
171 177 $ hg rm .hgsub
172 178
173 179 8
174 180
175 181 $ hg ci -m8 # remove sub
176 182
177 183 merge tests
178 184
179 185 $ hg co -C 3
180 186 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
181 187 $ hg merge 5 # test adding
182 188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 189 (branch merge, don't forget to commit)
184 190 $ hg debugsub
185 191 path s
186 192 source s
187 193 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
188 194 path t
189 195 source t
190 196 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
191 197 $ hg ci -m9
192 198 created new head
193 199 $ hg merge 6 --debug # test change
194 200 searching for copies back to rev 2
195 201 resolving manifests
196 202 overwrite None partial False
197 203 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
198 204 .hgsubstate: versions differ -> m
199 205 updating: .hgsubstate 1/1 files (100.00%)
200 206 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
201 207 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
202 208 getting subrepo t
203 209 resolving manifests
204 210 overwrite True partial False
205 211 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
206 212 t: remote is newer -> g
207 213 updating: t 1/1 files (100.00%)
208 214 getting t
209 215 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 216 (branch merge, don't forget to commit)
211 217 $ hg debugsub
212 218 path s
213 219 source s
214 220 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
215 221 path t
216 222 source t
217 223 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
218 224 $ echo conflict > t/t
219 225 $ hg ci -m10
220 226 committing subrepository t
221 227 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
222 228 searching for copies back to rev 2
223 229 resolving manifests
224 230 overwrite None partial False
225 231 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
226 232 .hgsubstate: versions differ -> m
227 233 updating: .hgsubstate 1/1 files (100.00%)
228 234 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
229 235 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
230 236 merging subrepo t
231 237 searching for copies back to rev 2
232 238 resolving manifests
233 239 overwrite None partial False
234 240 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
235 241 t: versions differ -> m
236 242 preserving t for resolve of t
237 243 updating: t 1/1 files (100.00%)
238 244 picked tool 'internal:merge' for t (binary False symlink False)
239 245 merging t
240 246 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
241 247 warning: conflicts during merge.
242 248 merging t failed!
243 249 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
244 250 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
245 251 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 252 (branch merge, don't forget to commit)
247 253
248 254 should conflict
249 255
250 256 $ cat t/t
251 257 <<<<<<< local
252 258 conflict
253 259 =======
254 260 t3
255 261 >>>>>>> other
256 262
257 263 clone
258 264
259 265 $ cd ..
260 266 $ hg clone t tc
261 267 updating to branch default
262 268 cloning subrepo s from $TESTTMP/sub/t/s
263 269 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss
264 270 cloning subrepo t from $TESTTMP/sub/t/t
265 271 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 272 $ cd tc
267 273 $ hg debugsub
268 274 path s
269 275 source s
270 276 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
271 277 path t
272 278 source t
273 279 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
274 280
275 281 push
276 282
277 283 $ echo bah > t/t
278 284 $ hg ci -m11
279 285 committing subrepository t
280 286 $ hg push
281 287 pushing to $TESTTMP/sub/t
282 288 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
283 289 searching for changes
284 290 no changes found
285 291 pushing subrepo s to $TESTTMP/sub/t/s
286 292 searching for changes
287 293 no changes found
288 294 pushing subrepo t to $TESTTMP/sub/t/t
289 295 searching for changes
290 296 adding changesets
291 297 adding manifests
292 298 adding file changes
293 299 added 1 changesets with 1 changes to 1 files
294 300 searching for changes
295 301 adding changesets
296 302 adding manifests
297 303 adding file changes
298 304 added 1 changesets with 1 changes to 1 files
299 305
300 306 push -f
301 307
302 308 $ echo bah > s/a
303 309 $ hg ci -m12
304 310 committing subrepository s
305 311 $ hg push
306 312 pushing to $TESTTMP/sub/t
307 313 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
308 314 searching for changes
309 315 no changes found
310 316 pushing subrepo s to $TESTTMP/sub/t/s
311 317 searching for changes
312 318 abort: push creates new remote head 12a213df6fa9!
313 319 (did you forget to merge? use push -f to force)
314 320 [255]
315 321 $ hg push -f
316 322 pushing to $TESTTMP/sub/t
317 323 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
318 324 searching for changes
319 325 no changes found
320 326 pushing subrepo s to $TESTTMP/sub/t/s
321 327 searching for changes
322 328 adding changesets
323 329 adding manifests
324 330 adding file changes
325 331 added 1 changesets with 1 changes to 1 files (+1 heads)
326 332 pushing subrepo t to $TESTTMP/sub/t/t
327 333 searching for changes
328 334 no changes found
329 335 searching for changes
330 336 adding changesets
331 337 adding manifests
332 338 adding file changes
333 339 added 1 changesets with 1 changes to 1 files
334 340
335 341 update
336 342
337 343 $ cd ../t
338 344 $ hg up -C # discard our earlier merge
339 345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 346 $ echo blah > t/t
341 347 $ hg ci -m13
342 348 committing subrepository t
343 349
344 350 pull
345 351
346 352 $ cd ../tc
347 353 $ hg pull
348 354 pulling from $TESTTMP/sub/t
349 355 searching for changes
350 356 adding changesets
351 357 adding manifests
352 358 adding file changes
353 359 added 1 changesets with 1 changes to 1 files
354 360 (run 'hg update' to get a working copy)
355 361
356 362 should pull t
357 363
358 364 $ hg up
359 365 pulling subrepo t from $TESTTMP/sub/t/t
360 366 searching for changes
361 367 adding changesets
362 368 adding manifests
363 369 adding file changes
364 370 added 1 changesets with 1 changes to 1 files
365 371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 372 $ cat t/t
367 373 blah
368 374
369 375 bogus subrepo path aborts
370 376
371 377 $ echo 'bogus=[boguspath' >> .hgsub
372 378 $ hg ci -m 'bogus subrepo path'
373 379 abort: missing ] in subrepo source
374 380 [255]
375 381
376 382 Issue1986: merge aborts when trying to merge a subrepo that
377 383 shouldn't need merging
378 384
379 385 # subrepo layout
380 386 #
381 387 # o 5 br
382 388 # /|
383 389 # o | 4 default
384 390 # | |
385 391 # | o 3 br
386 392 # |/|
387 393 # o | 2 default
388 394 # | |
389 395 # | o 1 br
390 396 # |/
391 397 # o 0 default
392 398
393 399 $ cd ..
394 400 $ rm -rf sub
395 401 $ hg init main
396 402 $ cd main
397 403 $ hg init s
398 404 $ cd s
399 405 $ echo a > a
400 406 $ hg ci -Am1
401 407 adding a
402 408 $ hg branch br
403 409 marked working directory as branch br
404 410 $ echo a >> a
405 411 $ hg ci -m1
406 412 $ hg up default
407 413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
408 414 $ echo b > b
409 415 $ hg ci -Am1
410 416 adding b
411 417 $ hg up br
412 418 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
413 419 $ hg merge tip
414 420 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
415 421 (branch merge, don't forget to commit)
416 422 $ hg ci -m1
417 423 $ hg up 2
418 424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
419 425 $ echo c > c
420 426 $ hg ci -Am1
421 427 adding c
422 428 $ hg up 3
423 429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
424 430 $ hg merge 4
425 431 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 432 (branch merge, don't forget to commit)
427 433 $ hg ci -m1
428 434
429 435 # main repo layout:
430 436 #
431 437 # * <-- try to merge default into br again
432 438 # .`|
433 439 # . o 5 br --> substate = 5
434 440 # . |
435 441 # o | 4 default --> substate = 4
436 442 # | |
437 443 # | o 3 br --> substate = 2
438 444 # |/|
439 445 # o | 2 default --> substate = 2
440 446 # | |
441 447 # | o 1 br --> substate = 3
442 448 # |/
443 449 # o 0 default --> substate = 2
444 450
445 451 $ cd ..
446 452 $ echo 's = s' > .hgsub
447 453 $ hg -R s up 2
448 454 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
449 455 $ hg ci -Am1
450 456 adding .hgsub
451 457 committing subrepository s
452 458 $ hg branch br
453 459 marked working directory as branch br
454 460 $ echo b > b
455 461 $ hg -R s up 3
456 462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 463 $ hg ci -Am1
458 464 adding b
459 465 committing subrepository s
460 466 $ hg up default
461 467 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
462 468 $ echo c > c
463 469 $ hg ci -Am1
464 470 adding c
465 471 $ hg up 1
466 472 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
467 473 $ hg merge 2
468 474 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 475 (branch merge, don't forget to commit)
470 476 $ hg ci -m1
471 477 $ hg up 2
472 478 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
473 479 $ hg -R s up 4
474 480 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 481 $ echo d > d
476 482 $ hg ci -Am1
477 483 adding d
478 484 committing subrepository s
479 485 $ hg up 3
480 486 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
481 487 $ hg -R s up 5
482 488 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
483 489 $ echo e > e
484 490 $ hg ci -Am1
485 491 adding e
486 492 committing subrepository s
487 493
488 494 $ hg up 5
489 495 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
490 496 $ hg merge 4 # try to merge default into br again
491 497 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
492 498 (branch merge, don't forget to commit)
493 499 $ cd ..
494 500
495 501 test subrepo delete from .hgsubstate
496 502
497 503 $ hg init testdelete
498 504 $ mkdir testdelete/nested testdelete/nested2
499 505 $ hg init testdelete/nested
500 506 $ hg init testdelete/nested2
501 507 $ echo test > testdelete/nested/foo
502 508 $ echo test > testdelete/nested2/foo
503 509 $ hg -R testdelete/nested add
504 510 adding testdelete/nested/foo
505 511 $ hg -R testdelete/nested2 add
506 512 adding testdelete/nested2/foo
507 513 $ hg -R testdelete/nested ci -m test
508 514 $ hg -R testdelete/nested2 ci -m test
509 515 $ echo nested = nested > testdelete/.hgsub
510 516 $ echo nested2 = nested2 >> testdelete/.hgsub
511 517 $ hg -R testdelete add
512 518 adding testdelete/.hgsub
513 519 $ hg -R testdelete ci -m "nested 1 & 2 added"
514 520 committing subrepository nested
515 521 committing subrepository nested2
516 522 $ echo nested = nested > testdelete/.hgsub
517 523 $ hg -R testdelete ci -m "nested 2 deleted"
518 524 $ cat testdelete/.hgsubstate
519 525 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
520 526 $ hg -R testdelete remove testdelete/.hgsub
521 527 $ hg -R testdelete ci -m ".hgsub deleted"
522 528 $ cat testdelete/.hgsubstate
523 529 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
524 530
525 531 test repository cloning
526 532
527 533 $ mkdir mercurial mercurial2
528 534 $ hg init nested_absolute
529 535 $ echo test > nested_absolute/foo
530 536 $ hg -R nested_absolute add
531 537 adding nested_absolute/foo
532 538 $ hg -R nested_absolute ci -mtest
533 539 $ cd mercurial
534 540 $ hg init nested_relative
535 541 $ echo test2 > nested_relative/foo2
536 542 $ hg -R nested_relative add
537 543 adding nested_relative/foo2
538 544 $ hg -R nested_relative ci -mtest2
539 545 $ hg init main
540 546 $ echo "nested_relative = ../nested_relative" > main/.hgsub
541 547 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
542 548 $ hg -R main add
543 549 adding main/.hgsub
544 550 $ hg -R main ci -m "add subrepos"
545 551 committing subrepository nested_absolute
546 552 committing subrepository nested_relative
547 553 $ cd ..
548 554 $ hg clone mercurial/main mercurial2/main
549 555 updating to branch default
550 556 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
551 557 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
552 558 > mercurial2/main/nested_relative/.hg/hgrc
553 559 [paths]
554 560 default = $TESTTMP/sub/mercurial/nested_absolute
555 561 [paths]
556 562 default = $TESTTMP/sub/mercurial/nested_relative
557 563 $ rm -rf mercurial mercurial2
558 564
559 565 Issue1977: multirepo push should fail if subrepo push fails
560 566
561 567 $ hg init repo
562 568 $ hg init repo/s
563 569 $ echo a > repo/s/a
564 570 $ hg -R repo/s ci -Am0
565 571 adding a
566 572 $ echo s = s > repo/.hgsub
567 573 $ hg -R repo ci -Am1
568 574 adding .hgsub
569 575 committing subrepository s
570 576 $ hg clone repo repo2
571 577 updating to branch default
572 578 cloning subrepo s from $TESTTMP/sub/repo/s
573 579 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
574 580 $ hg -q -R repo2 pull -u
575 581 $ echo 1 > repo2/s/a
576 582 $ hg -R repo2/s ci -m2
577 583 $ hg -q -R repo2/s push
578 584 $ hg -R repo2/s up -C 0
579 585 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
580 586 $ echo 2 > repo2/s/a
581 587 $ hg -R repo2/s ci -m3
582 588 created new head
583 589 $ hg -R repo2 ci -m3
584 590 committing subrepository s
585 591 $ hg -q -R repo2 push
586 592 abort: push creates new remote head 9d66565e64e1!
587 593 (did you forget to merge? use push -f to force)
588 594 [255]
589 595 $ hg -R repo update
590 596 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
591 597 $ rm -rf repo2 repo
592 598
593 599
594 600 Issue1852 subrepos with relative paths always push/pull relative to default
595 601
596 602 Prepare a repo with subrepo
597 603
598 604 $ hg init issue1852a
599 605 $ cd issue1852a
600 606 $ hg init sub/repo
601 607 $ echo test > sub/repo/foo
602 608 $ hg -R sub/repo add sub/repo/foo
603 609 $ echo sub/repo = sub/repo > .hgsub
604 610 $ hg add .hgsub
605 611 $ hg ci -mtest
606 612 committing subrepository sub/repo
607 613 $ echo test >> sub/repo/foo
608 614 $ hg ci -mtest
609 615 committing subrepository sub/repo
610 616 $ cd ..
611 617
612 618 Create repo without default path, pull top repo, and see what happens on update
613 619
614 620 $ hg init issue1852b
615 621 $ hg -R issue1852b pull issue1852a
616 622 pulling from issue1852a
617 623 requesting all changes
618 624 adding changesets
619 625 adding manifests
620 626 adding file changes
621 627 added 2 changesets with 3 changes to 2 files
622 628 (run 'hg update' to get a working copy)
623 629 $ hg -R issue1852b update
624 630 abort: default path for subrepository sub/repo not found
625 631 [255]
626 632
627 633 Pull -u now doesn't help
628 634
629 635 $ hg -R issue1852b pull -u issue1852a
630 636 pulling from issue1852a
631 637 searching for changes
632 638 no changes found
633 639
634 640 Try the same, but with pull -u
635 641
636 642 $ hg init issue1852c
637 643 $ hg -R issue1852c pull -r0 -u issue1852a
638 644 pulling from issue1852a
639 645 adding changesets
640 646 adding manifests
641 647 adding file changes
642 648 added 1 changesets with 2 changes to 2 files
643 649 cloning subrepo sub/repo from issue1852a/sub/repo
644 650 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 651
646 652 Try to push from the other side
647 653
648 654 $ hg -R issue1852a push `pwd`/issue1852c
649 655 pushing to $TESTTMP/sub/issue1852c
650 656 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
651 657 searching for changes
652 658 no changes found
653 659 searching for changes
654 660 adding changesets
655 661 adding manifests
656 662 adding file changes
657 663 added 1 changesets with 1 changes to 1 files
658 664
659 665 Incoming and outgoing should not use the default path:
660 666
661 667 $ hg clone -q issue1852a issue1852d
662 668 $ hg -R issue1852d outgoing --subrepos issue1852c
663 669 comparing with issue1852c
664 670 searching for changes
665 671 no changes found
666 672 comparing with issue1852c/sub/repo
667 673 searching for changes
668 674 no changes found
669 675 [1]
670 676 $ hg -R issue1852d incoming --subrepos issue1852c
671 677 comparing with issue1852c
672 678 searching for changes
673 679 no changes found
674 680 comparing with issue1852c/sub/repo
675 681 searching for changes
676 682 no changes found
677 683 [1]
678 684
679 685 Check status of files when none of them belong to the first
680 686 subrepository:
681 687
682 688 $ hg init subrepo-status
683 689 $ cd subrepo-status
684 690 $ hg init subrepo-1
685 691 $ hg init subrepo-2
686 692 $ cd subrepo-2
687 693 $ touch file
688 694 $ hg add file
689 695 $ cd ..
690 696 $ echo subrepo-1 = subrepo-1 > .hgsub
691 697 $ echo subrepo-2 = subrepo-2 >> .hgsub
692 698 $ hg add .hgsub
693 699 $ hg ci -m 'Added subrepos'
694 700 committing subrepository subrepo-1
695 701 committing subrepository subrepo-2
696 702 $ hg st subrepo-2/file
697 703
698 704 Check hg update --clean
699 705 $ cd $TESTTMP/sub/t
700 706 $ rm -r t/t.orig
701 707 $ hg status -S --all
702 708 C .hgsub
703 709 C .hgsubstate
704 710 C a
705 711 C s/.hgsub
706 712 C s/.hgsubstate
707 713 C s/a
708 714 C s/ss/a
709 715 C t/t
710 716 $ echo c1 > s/a
711 717 $ cd s
712 718 $ echo c1 > b
713 719 $ echo c1 > c
714 720 $ hg add b
715 721 $ cd ..
716 722 $ hg status -S
717 723 M s/a
718 724 A s/b
719 725 ? s/c
720 726 $ hg update -C
721 727 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
722 728 $ hg status -S
723 729 ? s/b
724 730 ? s/c
725 731
726 732 Sticky subrepositories, no changes
727 733 $ cd $TESTTMP/sub/t
728 734 $ hg id
729 735 925c17564ef8 tip
730 736 $ hg -R s id
731 737 12a213df6fa9 tip
732 738 $ hg -R t id
733 739 52c0adc0515a tip
734 740 $ hg update 11
735 741 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
736 742 $ hg id
737 743 365661e5936a
738 744 $ hg -R s id
739 745 fc627a69481f
740 746 $ hg -R t id
741 747 e95bcfa18a35
742 748
743 749 Sticky subrepositorys, file changes
744 750 $ touch s/f1
745 751 $ touch t/f1
746 752 $ hg add -S s/f1
747 753 $ hg add -S t/f1
748 754 $ hg id
749 755 365661e5936a
750 756 $ hg -R s id
751 757 fc627a69481f+
752 758 $ hg -R t id
753 759 e95bcfa18a35+
754 760 $ hg update tip
755 761 subrepository sources for s differ
756 762 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
757 763 l
758 764 subrepository sources for t differ
759 765 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
760 766 l
761 767 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
762 768 $ hg id
763 769 925c17564ef8+ tip
764 770 $ hg -R s id
765 771 fc627a69481f+
766 772 $ hg -R t id
767 773 e95bcfa18a35+
768 774 $ hg update --clean tip
769 775 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
770 776
771 777 Sticky subrepository, revision updates
772 778 $ hg id
773 779 925c17564ef8 tip
774 780 $ hg -R s id
775 781 12a213df6fa9 tip
776 782 $ hg -R t id
777 783 52c0adc0515a tip
778 784 $ cd s
779 785 $ hg update -r -2
780 786 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
781 787 $ cd ../t
782 788 $ hg update -r 2
783 789 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
784 790 $ cd ..
785 791 $ hg update 10
786 792 subrepository sources for t differ (in checked out version)
787 793 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
788 794 l
789 795 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
790 796 $ hg id
791 797 e45c8b14af55+
792 798 $ hg -R s id
793 799 1c833a7a9e3a
794 800 $ hg -R t id
795 801 7af322bc1198
796 802
797 803 Sticky subrepository, file changes and revision updates
798 804 $ touch s/f1
799 805 $ touch t/f1
800 806 $ hg add -S s/f1
801 807 $ hg add -S t/f1
802 808 $ hg id
803 809 e45c8b14af55+
804 810 $ hg -R s id
805 811 1c833a7a9e3a+
806 812 $ hg -R t id
807 813 7af322bc1198+
808 814 $ hg update tip
809 815 subrepository sources for s differ
810 816 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
811 817 l
812 818 subrepository sources for t differ
813 819 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
814 820 l
815 821 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
816 822 $ hg id
817 823 925c17564ef8 tip
818 824 $ hg -R s id
819 825 1c833a7a9e3a+
820 826 $ hg -R t id
821 827 7af322bc1198+
822 828
823 829 Sticky repository, update --clean
824 830 $ hg update --clean tip
825 831 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
826 832 $ hg id
827 833 925c17564ef8 tip
828 834 $ hg -R s id
829 835 12a213df6fa9 tip
830 836 $ hg -R t id
831 837 52c0adc0515a tip
832 838
833 839 Test subrepo already at intended revision:
834 840 $ cd s
835 841 $ hg update fc627a69481f
836 842 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
837 843 $ cd ..
838 844 $ hg update 11
839 845 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
840 846 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
841 847 $ hg id -n
842 848 11+
843 849 $ hg -R s id
844 850 fc627a69481f
845 851 $ hg -R t id
846 852 e95bcfa18a35
847 853
848 854 Test that removing .hgsubstate doesn't break anything:
849 855
850 856 $ hg rm -f .hgsubstate
851 857 $ hg ci -mrm
852 858 committing subrepository s
853 859 committing subrepository t
854 860 created new head
855 861 $ hg log -vr tip
856 862 changeset: 14:3941e0aa5236
857 863 tag: tip
858 864 parent: 11:365661e5936a
859 865 user: test
860 866 date: Thu Jan 01 00:00:00 1970 +0000
861 867 description:
862 868 rm
863 869
864 870
865 871
866 872 Test that removing .hgsub removes .hgsubstate:
867 873
868 874 $ hg rm .hgsub
869 875 $ hg ci -mrm2
870 876 $ hg log -vr tip
871 877 changeset: 15:8b31de9d13d1
872 878 tag: tip
873 879 user: test
874 880 date: Thu Jan 01 00:00:00 1970 +0000
875 881 files: .hgsub .hgsubstate
876 882 description:
877 883 rm2
878 884
879 885
General Comments 0
You need to be logged in to leave comments. Login now