##// END OF EJS Templates
import: fix parent selection when importing merges...
Patrick Mezard -
r15511:6cae68a3 stable
parent child Browse files
Show More
@@ -0,0 +1,114
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "mq=" >> $HGRCPATH
3
4 $ tipparents() {
5 > hg parents --template "{rev}:{node|short} {desc|firstline}\n" -r tip
6 > }
7
8 Test import and merge diffs
9
10 $ hg init repo
11 $ cd repo
12 $ echo a > a
13 $ hg ci -Am adda
14 adding a
15 $ echo a >> a
16 $ hg ci -m changea
17 $ echo c > c
18 $ hg ci -Am addc
19 adding c
20 $ hg up 0
21 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
22 $ echo b > b
23 $ hg ci -Am addb
24 adding b
25 created new head
26 $ hg up 1
27 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 $ hg merge 3
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 (branch merge, don't forget to commit)
31 $ hg ci -m merge
32 $ hg export . > ../merge.diff
33 $ cd ..
34 $ hg clone -r2 repo repo2
35 adding changesets
36 adding manifests
37 adding file changes
38 added 3 changesets with 3 changes to 2 files
39 updating to branch default
40 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 $ cd repo2
42 $ hg pull -r3 ../repo
43 pulling from ../repo
44 searching for changes
45 adding changesets
46 adding manifests
47 adding file changes
48 added 1 changesets with 1 changes to 1 files (+1 heads)
49 (run 'hg heads' to see heads, 'hg merge' to merge)
50
51 Test without --exact and diff.p1 == workingdir.p1
52
53 $ hg up 1
54 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
55 $ hg import ../merge.diff
56 applying ../merge.diff
57 $ tipparents
58 1:540395c44225 changea
59 3:102a90ea7b4a addb
60 $ hg strip --no-backup tip
61 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
62
63 Test without --exact and diff.p1 != workingdir.p1
64
65 $ hg up 2
66 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 $ hg import ../merge.diff
68 applying ../merge.diff
69 $ tipparents
70 2:890ecaa90481 addc
71 $ hg strip --no-backup tip
72 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
73
74 Test with --exact
75
76 $ hg import --exact ../merge.diff
77 applying ../merge.diff
78 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
79 $ tipparents
80 1:540395c44225 changea
81 3:102a90ea7b4a addb
82 $ hg strip --no-backup tip
83 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
84
85 Test with --bypass and diff.p1 == workingdir.p1
86
87 $ hg up 1
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 $ hg import --bypass ../merge.diff
90 applying ../merge.diff
91 $ tipparents
92 1:540395c44225 changea
93 3:102a90ea7b4a addb
94 $ hg strip --no-backup tip
95
96 Test with --bypass and diff.p1 != workingdir.p1
97
98 $ hg up 2
99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 $ hg import --bypass ../merge.diff
101 applying ../merge.diff
102 $ tipparents
103 2:890ecaa90481 addc
104 $ hg strip --no-backup tip
105
106 Test with --bypass and --exact
107
108 $ hg import --bypass --exact ../merge.diff
109 applying ../merge.diff
110 $ tipparents
111 1:540395c44225 changea
112 3:102a90ea7b4a addb
113 $ hg strip --no-backup tip
114
@@ -1,5663 +1,5672
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 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 1170 if opts.get('subrepos'):
1171 1171 # Let --subrepos on the command line overide config setting.
1172 1172 ui.setconfig('ui', 'commitsubrepos', True)
1173 1173
1174 1174 extra = {}
1175 1175 if opts.get('close_branch'):
1176 1176 if repo['.'].node() not in repo.branchheads():
1177 1177 # The topo heads set is included in the branch heads set of the
1178 1178 # current branch, so it's sufficient to test branchheads
1179 1179 raise util.Abort(_('can only close branch heads'))
1180 1180 extra['close'] = 1
1181 1181 e = cmdutil.commiteditor
1182 1182 if opts.get('force_editor'):
1183 1183 e = cmdutil.commitforceeditor
1184 1184
1185 1185 def commitfunc(ui, repo, message, match, opts):
1186 1186 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1187 1187 editor=e, extra=extra)
1188 1188
1189 1189 branch = repo[None].branch()
1190 1190 bheads = repo.branchheads(branch)
1191 1191
1192 1192 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1193 1193 if not node:
1194 1194 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1195 1195 if stat[3]:
1196 1196 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1197 1197 % len(stat[3]))
1198 1198 else:
1199 1199 ui.status(_("nothing changed\n"))
1200 1200 return 1
1201 1201
1202 1202 ctx = repo[node]
1203 1203 parents = ctx.parents()
1204 1204
1205 1205 if (bheads and node not in bheads and not
1206 1206 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1207 1207 ui.status(_('created new head\n'))
1208 1208 # The message is not printed for initial roots. For the other
1209 1209 # changesets, it is printed in the following situations:
1210 1210 #
1211 1211 # Par column: for the 2 parents with ...
1212 1212 # N: null or no parent
1213 1213 # B: parent is on another named branch
1214 1214 # C: parent is a regular non head changeset
1215 1215 # H: parent was a branch head of the current branch
1216 1216 # Msg column: whether we print "created new head" message
1217 1217 # In the following, it is assumed that there already exists some
1218 1218 # initial branch heads of the current branch, otherwise nothing is
1219 1219 # printed anyway.
1220 1220 #
1221 1221 # Par Msg Comment
1222 1222 # NN y additional topo root
1223 1223 #
1224 1224 # BN y additional branch root
1225 1225 # CN y additional topo head
1226 1226 # HN n usual case
1227 1227 #
1228 1228 # BB y weird additional branch root
1229 1229 # CB y branch merge
1230 1230 # HB n merge with named branch
1231 1231 #
1232 1232 # CC y additional head from merge
1233 1233 # CH n merge with a head
1234 1234 #
1235 1235 # HH n head merge: head count decreases
1236 1236
1237 1237 if not opts.get('close_branch'):
1238 1238 for r in parents:
1239 1239 if r.extra().get('close') and r.branch() == branch:
1240 1240 ui.status(_('reopening closed branch head %d\n') % r)
1241 1241
1242 1242 if ui.debugflag:
1243 1243 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1244 1244 elif ui.verbose:
1245 1245 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1246 1246
1247 1247 @command('copy|cp',
1248 1248 [('A', 'after', None, _('record a copy that has already occurred')),
1249 1249 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1250 1250 ] + walkopts + dryrunopts,
1251 1251 _('[OPTION]... [SOURCE]... DEST'))
1252 1252 def copy(ui, repo, *pats, **opts):
1253 1253 """mark files as copied for the next commit
1254 1254
1255 1255 Mark dest as having copies of source files. If dest is a
1256 1256 directory, copies are put in that directory. If dest is a file,
1257 1257 the source must be a single file.
1258 1258
1259 1259 By default, this command copies the contents of files as they
1260 1260 exist in the working directory. If invoked with -A/--after, the
1261 1261 operation is recorded, but no copying is performed.
1262 1262
1263 1263 This command takes effect with the next commit. To undo a copy
1264 1264 before that, see :hg:`revert`.
1265 1265
1266 1266 Returns 0 on success, 1 if errors are encountered.
1267 1267 """
1268 1268 wlock = repo.wlock(False)
1269 1269 try:
1270 1270 return cmdutil.copy(ui, repo, pats, opts)
1271 1271 finally:
1272 1272 wlock.release()
1273 1273
1274 1274 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1275 1275 def debugancestor(ui, repo, *args):
1276 1276 """find the ancestor revision of two revisions in a given index"""
1277 1277 if len(args) == 3:
1278 1278 index, rev1, rev2 = args
1279 1279 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1280 1280 lookup = r.lookup
1281 1281 elif len(args) == 2:
1282 1282 if not repo:
1283 1283 raise util.Abort(_("there is no Mercurial repository here "
1284 1284 "(.hg not found)"))
1285 1285 rev1, rev2 = args
1286 1286 r = repo.changelog
1287 1287 lookup = repo.lookup
1288 1288 else:
1289 1289 raise util.Abort(_('either two or three arguments required'))
1290 1290 a = r.ancestor(lookup(rev1), lookup(rev2))
1291 1291 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1292 1292
1293 1293 @command('debugbuilddag',
1294 1294 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1295 1295 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1296 1296 ('n', 'new-file', None, _('add new file at each rev'))],
1297 1297 _('[OPTION]... [TEXT]'))
1298 1298 def debugbuilddag(ui, repo, text=None,
1299 1299 mergeable_file=False,
1300 1300 overwritten_file=False,
1301 1301 new_file=False):
1302 1302 """builds a repo with a given DAG from scratch in the current empty repo
1303 1303
1304 1304 The description of the DAG is read from stdin if not given on the
1305 1305 command line.
1306 1306
1307 1307 Elements:
1308 1308
1309 1309 - "+n" is a linear run of n nodes based on the current default parent
1310 1310 - "." is a single node based on the current default parent
1311 1311 - "$" resets the default parent to null (implied at the start);
1312 1312 otherwise the default parent is always the last node created
1313 1313 - "<p" sets the default parent to the backref p
1314 1314 - "*p" is a fork at parent p, which is a backref
1315 1315 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1316 1316 - "/p2" is a merge of the preceding node and p2
1317 1317 - ":tag" defines a local tag for the preceding node
1318 1318 - "@branch" sets the named branch for subsequent nodes
1319 1319 - "#...\\n" is a comment up to the end of the line
1320 1320
1321 1321 Whitespace between the above elements is ignored.
1322 1322
1323 1323 A backref is either
1324 1324
1325 1325 - a number n, which references the node curr-n, where curr is the current
1326 1326 node, or
1327 1327 - the name of a local tag you placed earlier using ":tag", or
1328 1328 - empty to denote the default parent.
1329 1329
1330 1330 All string valued-elements are either strictly alphanumeric, or must
1331 1331 be enclosed in double quotes ("..."), with "\\" as escape character.
1332 1332 """
1333 1333
1334 1334 if text is None:
1335 1335 ui.status(_("reading DAG from stdin\n"))
1336 1336 text = ui.fin.read()
1337 1337
1338 1338 cl = repo.changelog
1339 1339 if len(cl) > 0:
1340 1340 raise util.Abort(_('repository is not empty'))
1341 1341
1342 1342 # determine number of revs in DAG
1343 1343 total = 0
1344 1344 for type, data in dagparser.parsedag(text):
1345 1345 if type == 'n':
1346 1346 total += 1
1347 1347
1348 1348 if mergeable_file:
1349 1349 linesperrev = 2
1350 1350 # make a file with k lines per rev
1351 1351 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1352 1352 initialmergedlines.append("")
1353 1353
1354 1354 tags = []
1355 1355
1356 1356 tr = repo.transaction("builddag")
1357 1357 try:
1358 1358
1359 1359 at = -1
1360 1360 atbranch = 'default'
1361 1361 nodeids = []
1362 1362 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1363 1363 for type, data in dagparser.parsedag(text):
1364 1364 if type == 'n':
1365 1365 ui.note('node %s\n' % str(data))
1366 1366 id, ps = data
1367 1367
1368 1368 files = []
1369 1369 fctxs = {}
1370 1370
1371 1371 p2 = None
1372 1372 if mergeable_file:
1373 1373 fn = "mf"
1374 1374 p1 = repo[ps[0]]
1375 1375 if len(ps) > 1:
1376 1376 p2 = repo[ps[1]]
1377 1377 pa = p1.ancestor(p2)
1378 1378 base, local, other = [x[fn].data() for x in pa, p1, p2]
1379 1379 m3 = simplemerge.Merge3Text(base, local, other)
1380 1380 ml = [l.strip() for l in m3.merge_lines()]
1381 1381 ml.append("")
1382 1382 elif at > 0:
1383 1383 ml = p1[fn].data().split("\n")
1384 1384 else:
1385 1385 ml = initialmergedlines
1386 1386 ml[id * linesperrev] += " r%i" % id
1387 1387 mergedtext = "\n".join(ml)
1388 1388 files.append(fn)
1389 1389 fctxs[fn] = context.memfilectx(fn, mergedtext)
1390 1390
1391 1391 if overwritten_file:
1392 1392 fn = "of"
1393 1393 files.append(fn)
1394 1394 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1395 1395
1396 1396 if new_file:
1397 1397 fn = "nf%i" % id
1398 1398 files.append(fn)
1399 1399 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1400 1400 if len(ps) > 1:
1401 1401 if not p2:
1402 1402 p2 = repo[ps[1]]
1403 1403 for fn in p2:
1404 1404 if fn.startswith("nf"):
1405 1405 files.append(fn)
1406 1406 fctxs[fn] = p2[fn]
1407 1407
1408 1408 def fctxfn(repo, cx, path):
1409 1409 return fctxs.get(path)
1410 1410
1411 1411 if len(ps) == 0 or ps[0] < 0:
1412 1412 pars = [None, None]
1413 1413 elif len(ps) == 1:
1414 1414 pars = [nodeids[ps[0]], None]
1415 1415 else:
1416 1416 pars = [nodeids[p] for p in ps]
1417 1417 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1418 1418 date=(id, 0),
1419 1419 user="debugbuilddag",
1420 1420 extra={'branch': atbranch})
1421 1421 nodeid = repo.commitctx(cx)
1422 1422 nodeids.append(nodeid)
1423 1423 at = id
1424 1424 elif type == 'l':
1425 1425 id, name = data
1426 1426 ui.note('tag %s\n' % name)
1427 1427 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1428 1428 elif type == 'a':
1429 1429 ui.note('branch %s\n' % data)
1430 1430 atbranch = data
1431 1431 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1432 1432 tr.close()
1433 1433 finally:
1434 1434 ui.progress(_('building'), None)
1435 1435 tr.release()
1436 1436
1437 1437 if tags:
1438 1438 repo.opener.write("localtags", "".join(tags))
1439 1439
1440 1440 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1441 1441 def debugbundle(ui, bundlepath, all=None, **opts):
1442 1442 """lists the contents of a bundle"""
1443 1443 f = url.open(ui, bundlepath)
1444 1444 try:
1445 1445 gen = changegroup.readbundle(f, bundlepath)
1446 1446 if all:
1447 1447 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1448 1448
1449 1449 def showchunks(named):
1450 1450 ui.write("\n%s\n" % named)
1451 1451 chain = None
1452 1452 while True:
1453 1453 chunkdata = gen.deltachunk(chain)
1454 1454 if not chunkdata:
1455 1455 break
1456 1456 node = chunkdata['node']
1457 1457 p1 = chunkdata['p1']
1458 1458 p2 = chunkdata['p2']
1459 1459 cs = chunkdata['cs']
1460 1460 deltabase = chunkdata['deltabase']
1461 1461 delta = chunkdata['delta']
1462 1462 ui.write("%s %s %s %s %s %s\n" %
1463 1463 (hex(node), hex(p1), hex(p2),
1464 1464 hex(cs), hex(deltabase), len(delta)))
1465 1465 chain = node
1466 1466
1467 1467 chunkdata = gen.changelogheader()
1468 1468 showchunks("changelog")
1469 1469 chunkdata = gen.manifestheader()
1470 1470 showchunks("manifest")
1471 1471 while True:
1472 1472 chunkdata = gen.filelogheader()
1473 1473 if not chunkdata:
1474 1474 break
1475 1475 fname = chunkdata['filename']
1476 1476 showchunks(fname)
1477 1477 else:
1478 1478 chunkdata = gen.changelogheader()
1479 1479 chain = None
1480 1480 while True:
1481 1481 chunkdata = gen.deltachunk(chain)
1482 1482 if not chunkdata:
1483 1483 break
1484 1484 node = chunkdata['node']
1485 1485 ui.write("%s\n" % hex(node))
1486 1486 chain = node
1487 1487 finally:
1488 1488 f.close()
1489 1489
1490 1490 @command('debugcheckstate', [], '')
1491 1491 def debugcheckstate(ui, repo):
1492 1492 """validate the correctness of the current dirstate"""
1493 1493 parent1, parent2 = repo.dirstate.parents()
1494 1494 m1 = repo[parent1].manifest()
1495 1495 m2 = repo[parent2].manifest()
1496 1496 errors = 0
1497 1497 for f in repo.dirstate:
1498 1498 state = repo.dirstate[f]
1499 1499 if state in "nr" and f not in m1:
1500 1500 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1501 1501 errors += 1
1502 1502 if state in "a" and f in m1:
1503 1503 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1504 1504 errors += 1
1505 1505 if state in "m" and f not in m1 and f not in m2:
1506 1506 ui.warn(_("%s in state %s, but not in either manifest\n") %
1507 1507 (f, state))
1508 1508 errors += 1
1509 1509 for f in m1:
1510 1510 state = repo.dirstate[f]
1511 1511 if state not in "nrm":
1512 1512 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1513 1513 errors += 1
1514 1514 if errors:
1515 1515 error = _(".hg/dirstate inconsistent with current parent's manifest")
1516 1516 raise util.Abort(error)
1517 1517
1518 1518 @command('debugcommands', [], _('[COMMAND]'))
1519 1519 def debugcommands(ui, cmd='', *args):
1520 1520 """list all available commands and options"""
1521 1521 for cmd, vals in sorted(table.iteritems()):
1522 1522 cmd = cmd.split('|')[0].strip('^')
1523 1523 opts = ', '.join([i[1] for i in vals[1]])
1524 1524 ui.write('%s: %s\n' % (cmd, opts))
1525 1525
1526 1526 @command('debugcomplete',
1527 1527 [('o', 'options', None, _('show the command options'))],
1528 1528 _('[-o] CMD'))
1529 1529 def debugcomplete(ui, cmd='', **opts):
1530 1530 """returns the completion list associated with the given command"""
1531 1531
1532 1532 if opts.get('options'):
1533 1533 options = []
1534 1534 otables = [globalopts]
1535 1535 if cmd:
1536 1536 aliases, entry = cmdutil.findcmd(cmd, table, False)
1537 1537 otables.append(entry[1])
1538 1538 for t in otables:
1539 1539 for o in t:
1540 1540 if "(DEPRECATED)" in o[3]:
1541 1541 continue
1542 1542 if o[0]:
1543 1543 options.append('-%s' % o[0])
1544 1544 options.append('--%s' % o[1])
1545 1545 ui.write("%s\n" % "\n".join(options))
1546 1546 return
1547 1547
1548 1548 cmdlist = cmdutil.findpossible(cmd, table)
1549 1549 if ui.verbose:
1550 1550 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1551 1551 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1552 1552
1553 1553 @command('debugdag',
1554 1554 [('t', 'tags', None, _('use tags as labels')),
1555 1555 ('b', 'branches', None, _('annotate with branch names')),
1556 1556 ('', 'dots', None, _('use dots for runs')),
1557 1557 ('s', 'spaces', None, _('separate elements by spaces'))],
1558 1558 _('[OPTION]... [FILE [REV]...]'))
1559 1559 def debugdag(ui, repo, file_=None, *revs, **opts):
1560 1560 """format the changelog or an index DAG as a concise textual description
1561 1561
1562 1562 If you pass a revlog index, the revlog's DAG is emitted. If you list
1563 1563 revision numbers, they get labelled in the output as rN.
1564 1564
1565 1565 Otherwise, the changelog DAG of the current repo is emitted.
1566 1566 """
1567 1567 spaces = opts.get('spaces')
1568 1568 dots = opts.get('dots')
1569 1569 if file_:
1570 1570 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1571 1571 revs = set((int(r) for r in revs))
1572 1572 def events():
1573 1573 for r in rlog:
1574 1574 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1575 1575 if r in revs:
1576 1576 yield 'l', (r, "r%i" % r)
1577 1577 elif repo:
1578 1578 cl = repo.changelog
1579 1579 tags = opts.get('tags')
1580 1580 branches = opts.get('branches')
1581 1581 if tags:
1582 1582 labels = {}
1583 1583 for l, n in repo.tags().items():
1584 1584 labels.setdefault(cl.rev(n), []).append(l)
1585 1585 def events():
1586 1586 b = "default"
1587 1587 for r in cl:
1588 1588 if branches:
1589 1589 newb = cl.read(cl.node(r))[5]['branch']
1590 1590 if newb != b:
1591 1591 yield 'a', newb
1592 1592 b = newb
1593 1593 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1594 1594 if tags:
1595 1595 ls = labels.get(r)
1596 1596 if ls:
1597 1597 for l in ls:
1598 1598 yield 'l', (r, l)
1599 1599 else:
1600 1600 raise util.Abort(_('need repo for changelog dag'))
1601 1601
1602 1602 for line in dagparser.dagtextlines(events(),
1603 1603 addspaces=spaces,
1604 1604 wraplabels=True,
1605 1605 wrapannotations=True,
1606 1606 wrapnonlinear=dots,
1607 1607 usedots=dots,
1608 1608 maxlinewidth=70):
1609 1609 ui.write(line)
1610 1610 ui.write("\n")
1611 1611
1612 1612 @command('debugdata',
1613 1613 [('c', 'changelog', False, _('open changelog')),
1614 1614 ('m', 'manifest', False, _('open manifest'))],
1615 1615 _('-c|-m|FILE REV'))
1616 1616 def debugdata(ui, repo, file_, rev = None, **opts):
1617 1617 """dump the contents of a data file revision"""
1618 1618 if opts.get('changelog') or opts.get('manifest'):
1619 1619 file_, rev = None, file_
1620 1620 elif rev is None:
1621 1621 raise error.CommandError('debugdata', _('invalid arguments'))
1622 1622 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1623 1623 try:
1624 1624 ui.write(r.revision(r.lookup(rev)))
1625 1625 except KeyError:
1626 1626 raise util.Abort(_('invalid revision identifier %s') % rev)
1627 1627
1628 1628 @command('debugdate',
1629 1629 [('e', 'extended', None, _('try extended date formats'))],
1630 1630 _('[-e] DATE [RANGE]'))
1631 1631 def debugdate(ui, date, range=None, **opts):
1632 1632 """parse and display a date"""
1633 1633 if opts["extended"]:
1634 1634 d = util.parsedate(date, util.extendeddateformats)
1635 1635 else:
1636 1636 d = util.parsedate(date)
1637 1637 ui.write("internal: %s %s\n" % d)
1638 1638 ui.write("standard: %s\n" % util.datestr(d))
1639 1639 if range:
1640 1640 m = util.matchdate(range)
1641 1641 ui.write("match: %s\n" % m(d[0]))
1642 1642
1643 1643 @command('debugdiscovery',
1644 1644 [('', 'old', None, _('use old-style discovery')),
1645 1645 ('', 'nonheads', None,
1646 1646 _('use old-style discovery with non-heads included')),
1647 1647 ] + remoteopts,
1648 1648 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1649 1649 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1650 1650 """runs the changeset discovery protocol in isolation"""
1651 1651 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1652 1652 remote = hg.peer(repo, opts, remoteurl)
1653 1653 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1654 1654
1655 1655 # make sure tests are repeatable
1656 1656 random.seed(12323)
1657 1657
1658 1658 def doit(localheads, remoteheads):
1659 1659 if opts.get('old'):
1660 1660 if localheads:
1661 1661 raise util.Abort('cannot use localheads with old style discovery')
1662 1662 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1663 1663 force=True)
1664 1664 common = set(common)
1665 1665 if not opts.get('nonheads'):
1666 1666 ui.write("unpruned common: %s\n" % " ".join([short(n)
1667 1667 for n in common]))
1668 1668 dag = dagutil.revlogdag(repo.changelog)
1669 1669 all = dag.ancestorset(dag.internalizeall(common))
1670 1670 common = dag.externalizeall(dag.headsetofconnecteds(all))
1671 1671 else:
1672 1672 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1673 1673 common = set(common)
1674 1674 rheads = set(hds)
1675 1675 lheads = set(repo.heads())
1676 1676 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1677 1677 if lheads <= common:
1678 1678 ui.write("local is subset\n")
1679 1679 elif rheads <= common:
1680 1680 ui.write("remote is subset\n")
1681 1681
1682 1682 serverlogs = opts.get('serverlog')
1683 1683 if serverlogs:
1684 1684 for filename in serverlogs:
1685 1685 logfile = open(filename, 'r')
1686 1686 try:
1687 1687 line = logfile.readline()
1688 1688 while line:
1689 1689 parts = line.strip().split(';')
1690 1690 op = parts[1]
1691 1691 if op == 'cg':
1692 1692 pass
1693 1693 elif op == 'cgss':
1694 1694 doit(parts[2].split(' '), parts[3].split(' '))
1695 1695 elif op == 'unb':
1696 1696 doit(parts[3].split(' '), parts[2].split(' '))
1697 1697 line = logfile.readline()
1698 1698 finally:
1699 1699 logfile.close()
1700 1700
1701 1701 else:
1702 1702 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1703 1703 opts.get('remote_head'))
1704 1704 localrevs = opts.get('local_head')
1705 1705 doit(localrevs, remoterevs)
1706 1706
1707 1707 @command('debugfileset', [], ('REVSPEC'))
1708 1708 def debugfileset(ui, repo, expr):
1709 1709 '''parse and apply a fileset specification'''
1710 1710 if ui.verbose:
1711 1711 tree = fileset.parse(expr)[0]
1712 1712 ui.note(tree, "\n")
1713 1713
1714 1714 for f in fileset.getfileset(repo[None], expr):
1715 1715 ui.write("%s\n" % f)
1716 1716
1717 1717 @command('debugfsinfo', [], _('[PATH]'))
1718 1718 def debugfsinfo(ui, path = "."):
1719 1719 """show information detected about current filesystem"""
1720 1720 util.writefile('.debugfsinfo', '')
1721 1721 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1722 1722 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1723 1723 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1724 1724 and 'yes' or 'no'))
1725 1725 os.unlink('.debugfsinfo')
1726 1726
1727 1727 @command('debuggetbundle',
1728 1728 [('H', 'head', [], _('id of head node'), _('ID')),
1729 1729 ('C', 'common', [], _('id of common node'), _('ID')),
1730 1730 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1731 1731 _('REPO FILE [-H|-C ID]...'))
1732 1732 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1733 1733 """retrieves a bundle from a repo
1734 1734
1735 1735 Every ID must be a full-length hex node id string. Saves the bundle to the
1736 1736 given file.
1737 1737 """
1738 1738 repo = hg.peer(ui, opts, repopath)
1739 1739 if not repo.capable('getbundle'):
1740 1740 raise util.Abort("getbundle() not supported by target repository")
1741 1741 args = {}
1742 1742 if common:
1743 1743 args['common'] = [bin(s) for s in common]
1744 1744 if head:
1745 1745 args['heads'] = [bin(s) for s in head]
1746 1746 bundle = repo.getbundle('debug', **args)
1747 1747
1748 1748 bundletype = opts.get('type', 'bzip2').lower()
1749 1749 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1750 1750 bundletype = btypes.get(bundletype)
1751 1751 if bundletype not in changegroup.bundletypes:
1752 1752 raise util.Abort(_('unknown bundle type specified with --type'))
1753 1753 changegroup.writebundle(bundle, bundlepath, bundletype)
1754 1754
1755 1755 @command('debugignore', [], '')
1756 1756 def debugignore(ui, repo, *values, **opts):
1757 1757 """display the combined ignore pattern"""
1758 1758 ignore = repo.dirstate._ignore
1759 1759 includepat = getattr(ignore, 'includepat', None)
1760 1760 if includepat is not None:
1761 1761 ui.write("%s\n" % includepat)
1762 1762 else:
1763 1763 raise util.Abort(_("no ignore patterns found"))
1764 1764
1765 1765 @command('debugindex',
1766 1766 [('c', 'changelog', False, _('open changelog')),
1767 1767 ('m', 'manifest', False, _('open manifest')),
1768 1768 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1769 1769 _('[-f FORMAT] -c|-m|FILE'))
1770 1770 def debugindex(ui, repo, file_ = None, **opts):
1771 1771 """dump the contents of an index file"""
1772 1772 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1773 1773 format = opts.get('format', 0)
1774 1774 if format not in (0, 1):
1775 1775 raise util.Abort(_("unknown format %d") % format)
1776 1776
1777 1777 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1778 1778 if generaldelta:
1779 1779 basehdr = ' delta'
1780 1780 else:
1781 1781 basehdr = ' base'
1782 1782
1783 1783 if format == 0:
1784 1784 ui.write(" rev offset length " + basehdr + " linkrev"
1785 1785 " nodeid p1 p2\n")
1786 1786 elif format == 1:
1787 1787 ui.write(" rev flag offset length"
1788 1788 " size " + basehdr + " link p1 p2 nodeid\n")
1789 1789
1790 1790 for i in r:
1791 1791 node = r.node(i)
1792 1792 if generaldelta:
1793 1793 base = r.deltaparent(i)
1794 1794 else:
1795 1795 base = r.chainbase(i)
1796 1796 if format == 0:
1797 1797 try:
1798 1798 pp = r.parents(node)
1799 1799 except:
1800 1800 pp = [nullid, nullid]
1801 1801 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1802 1802 i, r.start(i), r.length(i), base, r.linkrev(i),
1803 1803 short(node), short(pp[0]), short(pp[1])))
1804 1804 elif format == 1:
1805 1805 pr = r.parentrevs(i)
1806 1806 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1807 1807 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1808 1808 base, r.linkrev(i), pr[0], pr[1], short(node)))
1809 1809
1810 1810 @command('debugindexdot', [], _('FILE'))
1811 1811 def debugindexdot(ui, repo, file_):
1812 1812 """dump an index DAG as a graphviz dot file"""
1813 1813 r = None
1814 1814 if repo:
1815 1815 filelog = repo.file(file_)
1816 1816 if len(filelog):
1817 1817 r = filelog
1818 1818 if not r:
1819 1819 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1820 1820 ui.write("digraph G {\n")
1821 1821 for i in r:
1822 1822 node = r.node(i)
1823 1823 pp = r.parents(node)
1824 1824 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1825 1825 if pp[1] != nullid:
1826 1826 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1827 1827 ui.write("}\n")
1828 1828
1829 1829 @command('debuginstall', [], '')
1830 1830 def debuginstall(ui):
1831 1831 '''test Mercurial installation
1832 1832
1833 1833 Returns 0 on success.
1834 1834 '''
1835 1835
1836 1836 def writetemp(contents):
1837 1837 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1838 1838 f = os.fdopen(fd, "wb")
1839 1839 f.write(contents)
1840 1840 f.close()
1841 1841 return name
1842 1842
1843 1843 problems = 0
1844 1844
1845 1845 # encoding
1846 1846 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1847 1847 try:
1848 1848 encoding.fromlocal("test")
1849 1849 except util.Abort, inst:
1850 1850 ui.write(" %s\n" % inst)
1851 1851 ui.write(_(" (check that your locale is properly set)\n"))
1852 1852 problems += 1
1853 1853
1854 1854 # compiled modules
1855 1855 ui.status(_("Checking installed modules (%s)...\n")
1856 1856 % os.path.dirname(__file__))
1857 1857 try:
1858 1858 import bdiff, mpatch, base85, osutil
1859 1859 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1860 1860 except Exception, inst:
1861 1861 ui.write(" %s\n" % inst)
1862 1862 ui.write(_(" One or more extensions could not be found"))
1863 1863 ui.write(_(" (check that you compiled the extensions)\n"))
1864 1864 problems += 1
1865 1865
1866 1866 # templates
1867 1867 import templater
1868 1868 p = templater.templatepath()
1869 1869 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1870 1870 try:
1871 1871 templater.templater(templater.templatepath("map-cmdline.default"))
1872 1872 except Exception, inst:
1873 1873 ui.write(" %s\n" % inst)
1874 1874 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1875 1875 problems += 1
1876 1876
1877 1877 # editor
1878 1878 ui.status(_("Checking commit editor...\n"))
1879 1879 editor = ui.geteditor()
1880 1880 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1881 1881 if not cmdpath:
1882 1882 if editor == 'vi':
1883 1883 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1884 1884 ui.write(_(" (specify a commit editor in your configuration"
1885 1885 " file)\n"))
1886 1886 else:
1887 1887 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1888 1888 ui.write(_(" (specify a commit editor in your configuration"
1889 1889 " file)\n"))
1890 1890 problems += 1
1891 1891
1892 1892 # check username
1893 1893 ui.status(_("Checking username...\n"))
1894 1894 try:
1895 1895 ui.username()
1896 1896 except util.Abort, e:
1897 1897 ui.write(" %s\n" % e)
1898 1898 ui.write(_(" (specify a username in your configuration file)\n"))
1899 1899 problems += 1
1900 1900
1901 1901 if not problems:
1902 1902 ui.status(_("No problems detected\n"))
1903 1903 else:
1904 1904 ui.write(_("%s problems detected,"
1905 1905 " please check your install!\n") % problems)
1906 1906
1907 1907 return problems
1908 1908
1909 1909 @command('debugknown', [], _('REPO ID...'))
1910 1910 def debugknown(ui, repopath, *ids, **opts):
1911 1911 """test whether node ids are known to a repo
1912 1912
1913 1913 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1914 1914 indicating unknown/known.
1915 1915 """
1916 1916 repo = hg.peer(ui, opts, repopath)
1917 1917 if not repo.capable('known'):
1918 1918 raise util.Abort("known() not supported by target repository")
1919 1919 flags = repo.known([bin(s) for s in ids])
1920 1920 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1921 1921
1922 1922 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1923 1923 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1924 1924 '''access the pushkey key/value protocol
1925 1925
1926 1926 With two args, list the keys in the given namespace.
1927 1927
1928 1928 With five args, set a key to new if it currently is set to old.
1929 1929 Reports success or failure.
1930 1930 '''
1931 1931
1932 1932 target = hg.peer(ui, {}, repopath)
1933 1933 if keyinfo:
1934 1934 key, old, new = keyinfo
1935 1935 r = target.pushkey(namespace, key, old, new)
1936 1936 ui.status(str(r) + '\n')
1937 1937 return not r
1938 1938 else:
1939 1939 for k, v in target.listkeys(namespace).iteritems():
1940 1940 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1941 1941 v.encode('string-escape')))
1942 1942
1943 1943 @command('debugrebuildstate',
1944 1944 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1945 1945 _('[-r REV] [REV]'))
1946 1946 def debugrebuildstate(ui, repo, rev="tip"):
1947 1947 """rebuild the dirstate as it would look like for the given revision"""
1948 1948 ctx = scmutil.revsingle(repo, rev)
1949 1949 wlock = repo.wlock()
1950 1950 try:
1951 1951 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1952 1952 finally:
1953 1953 wlock.release()
1954 1954
1955 1955 @command('debugrename',
1956 1956 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1957 1957 _('[-r REV] FILE'))
1958 1958 def debugrename(ui, repo, file1, *pats, **opts):
1959 1959 """dump rename information"""
1960 1960
1961 1961 ctx = scmutil.revsingle(repo, opts.get('rev'))
1962 1962 m = scmutil.match(ctx, (file1,) + pats, opts)
1963 1963 for abs in ctx.walk(m):
1964 1964 fctx = ctx[abs]
1965 1965 o = fctx.filelog().renamed(fctx.filenode())
1966 1966 rel = m.rel(abs)
1967 1967 if o:
1968 1968 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1969 1969 else:
1970 1970 ui.write(_("%s not renamed\n") % rel)
1971 1971
1972 1972 @command('debugrevlog',
1973 1973 [('c', 'changelog', False, _('open changelog')),
1974 1974 ('m', 'manifest', False, _('open manifest')),
1975 1975 ('d', 'dump', False, _('dump index data'))],
1976 1976 _('-c|-m|FILE'))
1977 1977 def debugrevlog(ui, repo, file_ = None, **opts):
1978 1978 """show data and statistics about a revlog"""
1979 1979 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1980 1980
1981 1981 if opts.get("dump"):
1982 1982 numrevs = len(r)
1983 1983 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1984 1984 " rawsize totalsize compression heads\n")
1985 1985 ts = 0
1986 1986 heads = set()
1987 1987 for rev in xrange(numrevs):
1988 1988 dbase = r.deltaparent(rev)
1989 1989 if dbase == -1:
1990 1990 dbase = rev
1991 1991 cbase = r.chainbase(rev)
1992 1992 p1, p2 = r.parentrevs(rev)
1993 1993 rs = r.rawsize(rev)
1994 1994 ts = ts + rs
1995 1995 heads -= set(r.parentrevs(rev))
1996 1996 heads.add(rev)
1997 1997 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1998 1998 (rev, p1, p2, r.start(rev), r.end(rev),
1999 1999 r.start(dbase), r.start(cbase),
2000 2000 r.start(p1), r.start(p2),
2001 2001 rs, ts, ts / r.end(rev), len(heads)))
2002 2002 return 0
2003 2003
2004 2004 v = r.version
2005 2005 format = v & 0xFFFF
2006 2006 flags = []
2007 2007 gdelta = False
2008 2008 if v & revlog.REVLOGNGINLINEDATA:
2009 2009 flags.append('inline')
2010 2010 if v & revlog.REVLOGGENERALDELTA:
2011 2011 gdelta = True
2012 2012 flags.append('generaldelta')
2013 2013 if not flags:
2014 2014 flags = ['(none)']
2015 2015
2016 2016 nummerges = 0
2017 2017 numfull = 0
2018 2018 numprev = 0
2019 2019 nump1 = 0
2020 2020 nump2 = 0
2021 2021 numother = 0
2022 2022 nump1prev = 0
2023 2023 nump2prev = 0
2024 2024 chainlengths = []
2025 2025
2026 2026 datasize = [None, 0, 0L]
2027 2027 fullsize = [None, 0, 0L]
2028 2028 deltasize = [None, 0, 0L]
2029 2029
2030 2030 def addsize(size, l):
2031 2031 if l[0] is None or size < l[0]:
2032 2032 l[0] = size
2033 2033 if size > l[1]:
2034 2034 l[1] = size
2035 2035 l[2] += size
2036 2036
2037 2037 numrevs = len(r)
2038 2038 for rev in xrange(numrevs):
2039 2039 p1, p2 = r.parentrevs(rev)
2040 2040 delta = r.deltaparent(rev)
2041 2041 if format > 0:
2042 2042 addsize(r.rawsize(rev), datasize)
2043 2043 if p2 != nullrev:
2044 2044 nummerges += 1
2045 2045 size = r.length(rev)
2046 2046 if delta == nullrev:
2047 2047 chainlengths.append(0)
2048 2048 numfull += 1
2049 2049 addsize(size, fullsize)
2050 2050 else:
2051 2051 chainlengths.append(chainlengths[delta] + 1)
2052 2052 addsize(size, deltasize)
2053 2053 if delta == rev - 1:
2054 2054 numprev += 1
2055 2055 if delta == p1:
2056 2056 nump1prev += 1
2057 2057 elif delta == p2:
2058 2058 nump2prev += 1
2059 2059 elif delta == p1:
2060 2060 nump1 += 1
2061 2061 elif delta == p2:
2062 2062 nump2 += 1
2063 2063 elif delta != nullrev:
2064 2064 numother += 1
2065 2065
2066 2066 numdeltas = numrevs - numfull
2067 2067 numoprev = numprev - nump1prev - nump2prev
2068 2068 totalrawsize = datasize[2]
2069 2069 datasize[2] /= numrevs
2070 2070 fulltotal = fullsize[2]
2071 2071 fullsize[2] /= numfull
2072 2072 deltatotal = deltasize[2]
2073 2073 deltasize[2] /= numrevs - numfull
2074 2074 totalsize = fulltotal + deltatotal
2075 2075 avgchainlen = sum(chainlengths) / numrevs
2076 2076 compratio = totalrawsize / totalsize
2077 2077
2078 2078 basedfmtstr = '%%%dd\n'
2079 2079 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2080 2080
2081 2081 def dfmtstr(max):
2082 2082 return basedfmtstr % len(str(max))
2083 2083 def pcfmtstr(max, padding=0):
2084 2084 return basepcfmtstr % (len(str(max)), ' ' * padding)
2085 2085
2086 2086 def pcfmt(value, total):
2087 2087 return (value, 100 * float(value) / total)
2088 2088
2089 2089 ui.write('format : %d\n' % format)
2090 2090 ui.write('flags : %s\n' % ', '.join(flags))
2091 2091
2092 2092 ui.write('\n')
2093 2093 fmt = pcfmtstr(totalsize)
2094 2094 fmt2 = dfmtstr(totalsize)
2095 2095 ui.write('revisions : ' + fmt2 % numrevs)
2096 2096 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2097 2097 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2098 2098 ui.write('revisions : ' + fmt2 % numrevs)
2099 2099 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2100 2100 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2101 2101 ui.write('revision size : ' + fmt2 % totalsize)
2102 2102 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2103 2103 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2104 2104
2105 2105 ui.write('\n')
2106 2106 fmt = dfmtstr(max(avgchainlen, compratio))
2107 2107 ui.write('avg chain length : ' + fmt % avgchainlen)
2108 2108 ui.write('compression ratio : ' + fmt % compratio)
2109 2109
2110 2110 if format > 0:
2111 2111 ui.write('\n')
2112 2112 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2113 2113 % tuple(datasize))
2114 2114 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2115 2115 % tuple(fullsize))
2116 2116 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2117 2117 % tuple(deltasize))
2118 2118
2119 2119 if numdeltas > 0:
2120 2120 ui.write('\n')
2121 2121 fmt = pcfmtstr(numdeltas)
2122 2122 fmt2 = pcfmtstr(numdeltas, 4)
2123 2123 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2124 2124 if numprev > 0:
2125 2125 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2126 2126 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2127 2127 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2128 2128 if gdelta:
2129 2129 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2130 2130 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2131 2131 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2132 2132
2133 2133 @command('debugrevspec', [], ('REVSPEC'))
2134 2134 def debugrevspec(ui, repo, expr):
2135 2135 '''parse and apply a revision specification'''
2136 2136 if ui.verbose:
2137 2137 tree = revset.parse(expr)[0]
2138 2138 ui.note(tree, "\n")
2139 2139 newtree = revset.findaliases(ui, tree)
2140 2140 if newtree != tree:
2141 2141 ui.note(newtree, "\n")
2142 2142 func = revset.match(ui, expr)
2143 2143 for c in func(repo, range(len(repo))):
2144 2144 ui.write("%s\n" % c)
2145 2145
2146 2146 @command('debugsetparents', [], _('REV1 [REV2]'))
2147 2147 def debugsetparents(ui, repo, rev1, rev2=None):
2148 2148 """manually set the parents of the current working directory
2149 2149
2150 2150 This is useful for writing repository conversion tools, but should
2151 2151 be used with care.
2152 2152
2153 2153 Returns 0 on success.
2154 2154 """
2155 2155
2156 2156 r1 = scmutil.revsingle(repo, rev1).node()
2157 2157 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2158 2158
2159 2159 wlock = repo.wlock()
2160 2160 try:
2161 2161 repo.dirstate.setparents(r1, r2)
2162 2162 finally:
2163 2163 wlock.release()
2164 2164
2165 2165 @command('debugstate',
2166 2166 [('', 'nodates', None, _('do not display the saved mtime')),
2167 2167 ('', 'datesort', None, _('sort by saved mtime'))],
2168 2168 _('[OPTION]...'))
2169 2169 def debugstate(ui, repo, nodates=None, datesort=None):
2170 2170 """show the contents of the current dirstate"""
2171 2171 timestr = ""
2172 2172 showdate = not nodates
2173 2173 if datesort:
2174 2174 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2175 2175 else:
2176 2176 keyfunc = None # sort by filename
2177 2177 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2178 2178 if showdate:
2179 2179 if ent[3] == -1:
2180 2180 # Pad or slice to locale representation
2181 2181 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2182 2182 time.localtime(0)))
2183 2183 timestr = 'unset'
2184 2184 timestr = (timestr[:locale_len] +
2185 2185 ' ' * (locale_len - len(timestr)))
2186 2186 else:
2187 2187 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2188 2188 time.localtime(ent[3]))
2189 2189 if ent[1] & 020000:
2190 2190 mode = 'lnk'
2191 2191 else:
2192 2192 mode = '%3o' % (ent[1] & 0777)
2193 2193 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2194 2194 for f in repo.dirstate.copies():
2195 2195 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2196 2196
2197 2197 @command('debugsub',
2198 2198 [('r', 'rev', '',
2199 2199 _('revision to check'), _('REV'))],
2200 2200 _('[-r REV] [REV]'))
2201 2201 def debugsub(ui, repo, rev=None):
2202 2202 ctx = scmutil.revsingle(repo, rev, None)
2203 2203 for k, v in sorted(ctx.substate.items()):
2204 2204 ui.write('path %s\n' % k)
2205 2205 ui.write(' source %s\n' % v[0])
2206 2206 ui.write(' revision %s\n' % v[1])
2207 2207
2208 2208 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2209 2209 def debugwalk(ui, repo, *pats, **opts):
2210 2210 """show how files match on given patterns"""
2211 2211 m = scmutil.match(repo[None], pats, opts)
2212 2212 items = list(repo.walk(m))
2213 2213 if not items:
2214 2214 return
2215 2215 fmt = 'f %%-%ds %%-%ds %%s' % (
2216 2216 max([len(abs) for abs in items]),
2217 2217 max([len(m.rel(abs)) for abs in items]))
2218 2218 for abs in items:
2219 2219 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2220 2220 ui.write("%s\n" % line.rstrip())
2221 2221
2222 2222 @command('debugwireargs',
2223 2223 [('', 'three', '', 'three'),
2224 2224 ('', 'four', '', 'four'),
2225 2225 ('', 'five', '', 'five'),
2226 2226 ] + remoteopts,
2227 2227 _('REPO [OPTIONS]... [ONE [TWO]]'))
2228 2228 def debugwireargs(ui, repopath, *vals, **opts):
2229 2229 repo = hg.peer(ui, opts, repopath)
2230 2230 for opt in remoteopts:
2231 2231 del opts[opt[1]]
2232 2232 args = {}
2233 2233 for k, v in opts.iteritems():
2234 2234 if v:
2235 2235 args[k] = v
2236 2236 # run twice to check that we don't mess up the stream for the next command
2237 2237 res1 = repo.debugwireargs(*vals, **args)
2238 2238 res2 = repo.debugwireargs(*vals, **args)
2239 2239 ui.write("%s\n" % res1)
2240 2240 if res1 != res2:
2241 2241 ui.warn("%s\n" % res2)
2242 2242
2243 2243 @command('^diff',
2244 2244 [('r', 'rev', [], _('revision'), _('REV')),
2245 2245 ('c', 'change', '', _('change made by revision'), _('REV'))
2246 2246 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2247 2247 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2248 2248 def diff(ui, repo, *pats, **opts):
2249 2249 """diff repository (or selected files)
2250 2250
2251 2251 Show differences between revisions for the specified files.
2252 2252
2253 2253 Differences between files are shown using the unified diff format.
2254 2254
2255 2255 .. note::
2256 2256 diff may generate unexpected results for merges, as it will
2257 2257 default to comparing against the working directory's first
2258 2258 parent changeset if no revisions are specified.
2259 2259
2260 2260 When two revision arguments are given, then changes are shown
2261 2261 between those revisions. If only one revision is specified then
2262 2262 that revision is compared to the working directory, and, when no
2263 2263 revisions are specified, the working directory files are compared
2264 2264 to its parent.
2265 2265
2266 2266 Alternatively you can specify -c/--change with a revision to see
2267 2267 the changes in that changeset relative to its first parent.
2268 2268
2269 2269 Without the -a/--text option, diff will avoid generating diffs of
2270 2270 files it detects as binary. With -a, diff will generate a diff
2271 2271 anyway, probably with undesirable results.
2272 2272
2273 2273 Use the -g/--git option to generate diffs in the git extended diff
2274 2274 format. For more information, read :hg:`help diffs`.
2275 2275
2276 2276 .. container:: verbose
2277 2277
2278 2278 Examples:
2279 2279
2280 2280 - compare a file in the current working directory to its parent::
2281 2281
2282 2282 hg diff foo.c
2283 2283
2284 2284 - compare two historical versions of a directory, with rename info::
2285 2285
2286 2286 hg diff --git -r 1.0:1.2 lib/
2287 2287
2288 2288 - get change stats relative to the last change on some date::
2289 2289
2290 2290 hg diff --stat -r "date('may 2')"
2291 2291
2292 2292 - diff all newly-added files that contain a keyword::
2293 2293
2294 2294 hg diff "set:added() and grep(GNU)"
2295 2295
2296 2296 - compare a revision and its parents::
2297 2297
2298 2298 hg diff -c 9353 # compare against first parent
2299 2299 hg diff -r 9353^:9353 # same using revset syntax
2300 2300 hg diff -r 9353^2:9353 # compare against the second parent
2301 2301
2302 2302 Returns 0 on success.
2303 2303 """
2304 2304
2305 2305 revs = opts.get('rev')
2306 2306 change = opts.get('change')
2307 2307 stat = opts.get('stat')
2308 2308 reverse = opts.get('reverse')
2309 2309
2310 2310 if revs and change:
2311 2311 msg = _('cannot specify --rev and --change at the same time')
2312 2312 raise util.Abort(msg)
2313 2313 elif change:
2314 2314 node2 = scmutil.revsingle(repo, change, None).node()
2315 2315 node1 = repo[node2].p1().node()
2316 2316 else:
2317 2317 node1, node2 = scmutil.revpair(repo, revs)
2318 2318
2319 2319 if reverse:
2320 2320 node1, node2 = node2, node1
2321 2321
2322 2322 diffopts = patch.diffopts(ui, opts)
2323 2323 m = scmutil.match(repo[node2], pats, opts)
2324 2324 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2325 2325 listsubrepos=opts.get('subrepos'))
2326 2326
2327 2327 @command('^export',
2328 2328 [('o', 'output', '',
2329 2329 _('print output to file with formatted name'), _('FORMAT')),
2330 2330 ('', 'switch-parent', None, _('diff against the second parent')),
2331 2331 ('r', 'rev', [], _('revisions to export'), _('REV')),
2332 2332 ] + diffopts,
2333 2333 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2334 2334 def export(ui, repo, *changesets, **opts):
2335 2335 """dump the header and diffs for one or more changesets
2336 2336
2337 2337 Print the changeset header and diffs for one or more revisions.
2338 2338
2339 2339 The information shown in the changeset header is: author, date,
2340 2340 branch name (if non-default), changeset hash, parent(s) and commit
2341 2341 comment.
2342 2342
2343 2343 .. note::
2344 2344 export may generate unexpected diff output for merge
2345 2345 changesets, as it will compare the merge changeset against its
2346 2346 first parent only.
2347 2347
2348 2348 Output may be to a file, in which case the name of the file is
2349 2349 given using a format string. The formatting rules are as follows:
2350 2350
2351 2351 :``%%``: literal "%" character
2352 2352 :``%H``: changeset hash (40 hexadecimal digits)
2353 2353 :``%N``: number of patches being generated
2354 2354 :``%R``: changeset revision number
2355 2355 :``%b``: basename of the exporting repository
2356 2356 :``%h``: short-form changeset hash (12 hexadecimal digits)
2357 2357 :``%m``: first line of the commit message (only alphanumeric characters)
2358 2358 :``%n``: zero-padded sequence number, starting at 1
2359 2359 :``%r``: zero-padded changeset revision number
2360 2360
2361 2361 Without the -a/--text option, export will avoid generating diffs
2362 2362 of files it detects as binary. With -a, export will generate a
2363 2363 diff anyway, probably with undesirable results.
2364 2364
2365 2365 Use the -g/--git option to generate diffs in the git extended diff
2366 2366 format. See :hg:`help diffs` for more information.
2367 2367
2368 2368 With the --switch-parent option, the diff will be against the
2369 2369 second parent. It can be useful to review a merge.
2370 2370
2371 2371 .. container:: verbose
2372 2372
2373 2373 Examples:
2374 2374
2375 2375 - use export and import to transplant a bugfix to the current
2376 2376 branch::
2377 2377
2378 2378 hg export -r 9353 | hg import -
2379 2379
2380 2380 - export all the changesets between two revisions to a file with
2381 2381 rename information::
2382 2382
2383 2383 hg export --git -r 123:150 > changes.txt
2384 2384
2385 2385 - split outgoing changes into a series of patches with
2386 2386 descriptive names::
2387 2387
2388 2388 hg export -r "outgoing()" -o "%n-%m.patch"
2389 2389
2390 2390 Returns 0 on success.
2391 2391 """
2392 2392 changesets += tuple(opts.get('rev', []))
2393 2393 if not changesets:
2394 2394 raise util.Abort(_("export requires at least one changeset"))
2395 2395 revs = scmutil.revrange(repo, changesets)
2396 2396 if len(revs) > 1:
2397 2397 ui.note(_('exporting patches:\n'))
2398 2398 else:
2399 2399 ui.note(_('exporting patch:\n'))
2400 2400 cmdutil.export(repo, revs, template=opts.get('output'),
2401 2401 switch_parent=opts.get('switch_parent'),
2402 2402 opts=patch.diffopts(ui, opts))
2403 2403
2404 2404 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2405 2405 def forget(ui, repo, *pats, **opts):
2406 2406 """forget the specified files on the next commit
2407 2407
2408 2408 Mark the specified files so they will no longer be tracked
2409 2409 after the next commit.
2410 2410
2411 2411 This only removes files from the current branch, not from the
2412 2412 entire project history, and it does not delete them from the
2413 2413 working directory.
2414 2414
2415 2415 To undo a forget before the next commit, see :hg:`add`.
2416 2416
2417 2417 .. container:: verbose
2418 2418
2419 2419 Examples:
2420 2420
2421 2421 - forget newly-added binary files::
2422 2422
2423 2423 hg forget "set:added() and binary()"
2424 2424
2425 2425 - forget files that would be excluded by .hgignore::
2426 2426
2427 2427 hg forget "set:hgignore()"
2428 2428
2429 2429 Returns 0 on success.
2430 2430 """
2431 2431
2432 2432 if not pats:
2433 2433 raise util.Abort(_('no files specified'))
2434 2434
2435 2435 m = scmutil.match(repo[None], pats, opts)
2436 2436 s = repo.status(match=m, clean=True)
2437 2437 forget = sorted(s[0] + s[1] + s[3] + s[6])
2438 2438 errs = 0
2439 2439
2440 2440 for f in m.files():
2441 2441 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2442 2442 if os.path.exists(m.rel(f)):
2443 2443 ui.warn(_('not removing %s: file is already untracked\n')
2444 2444 % m.rel(f))
2445 2445 errs = 1
2446 2446
2447 2447 for f in forget:
2448 2448 if ui.verbose or not m.exact(f):
2449 2449 ui.status(_('removing %s\n') % m.rel(f))
2450 2450
2451 2451 repo[None].forget(forget)
2452 2452 return errs
2453 2453
2454 2454 @command(
2455 2455 'graft',
2456 2456 [('c', 'continue', False, _('resume interrupted graft')),
2457 2457 ('e', 'edit', False, _('invoke editor on commit messages')),
2458 2458 ('D', 'currentdate', False,
2459 2459 _('record the current date as commit date')),
2460 2460 ('U', 'currentuser', False,
2461 2461 _('record the current user as committer'), _('DATE'))]
2462 2462 + commitopts2 + mergetoolopts,
2463 2463 _('[OPTION]... REVISION...'))
2464 2464 def graft(ui, repo, *revs, **opts):
2465 2465 '''copy changes from other branches onto the current branch
2466 2466
2467 2467 This command uses Mercurial's merge logic to copy individual
2468 2468 changes from other branches without merging branches in the
2469 2469 history graph. This is sometimes known as 'backporting' or
2470 2470 'cherry-picking'. By default, graft will copy user, date, and
2471 2471 description from the source changesets.
2472 2472
2473 2473 Changesets that are ancestors of the current revision, that have
2474 2474 already been grafted, or that are merges will be skipped.
2475 2475
2476 2476 If a graft merge results in conflicts, the graft process is
2477 2477 aborted so that the current merge can be manually resolved. Once
2478 2478 all conflicts are addressed, the graft process can be continued
2479 2479 with the -c/--continue option.
2480 2480
2481 2481 .. note::
2482 2482 The -c/--continue option does not reapply earlier options.
2483 2483
2484 2484 .. container:: verbose
2485 2485
2486 2486 Examples:
2487 2487
2488 2488 - copy a single change to the stable branch and edit its description::
2489 2489
2490 2490 hg update stable
2491 2491 hg graft --edit 9393
2492 2492
2493 2493 - graft a range of changesets with one exception, updating dates::
2494 2494
2495 2495 hg graft -D "2085::2093 and not 2091"
2496 2496
2497 2497 - continue a graft after resolving conflicts::
2498 2498
2499 2499 hg graft -c
2500 2500
2501 2501 - show the source of a grafted changeset::
2502 2502
2503 2503 hg log --debug -r tip
2504 2504
2505 2505 Returns 0 on successful completion.
2506 2506 '''
2507 2507
2508 2508 if not opts.get('user') and opts.get('currentuser'):
2509 2509 opts['user'] = ui.username()
2510 2510 if not opts.get('date') and opts.get('currentdate'):
2511 2511 opts['date'] = "%d %d" % util.makedate()
2512 2512
2513 2513 editor = None
2514 2514 if opts.get('edit'):
2515 2515 editor = cmdutil.commitforceeditor
2516 2516
2517 2517 cont = False
2518 2518 if opts['continue']:
2519 2519 cont = True
2520 2520 if revs:
2521 2521 raise util.Abort(_("can't specify --continue and revisions"))
2522 2522 # read in unfinished revisions
2523 2523 try:
2524 2524 nodes = repo.opener.read('graftstate').splitlines()
2525 2525 revs = [repo[node].rev() for node in nodes]
2526 2526 except IOError, inst:
2527 2527 if inst.errno != errno.ENOENT:
2528 2528 raise
2529 2529 raise util.Abort(_("no graft state found, can't continue"))
2530 2530 else:
2531 2531 cmdutil.bailifchanged(repo)
2532 2532 if not revs:
2533 2533 raise util.Abort(_('no revisions specified'))
2534 2534 revs = scmutil.revrange(repo, revs)
2535 2535
2536 2536 # check for merges
2537 2537 for ctx in repo.set('%ld and merge()', revs):
2538 2538 ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev())
2539 2539 revs.remove(ctx.rev())
2540 2540 if not revs:
2541 2541 return -1
2542 2542
2543 2543 # check for ancestors of dest branch
2544 2544 for ctx in repo.set('::. and %ld', revs):
2545 2545 ui.warn(_('skipping ancestor revision %s\n') % ctx.rev())
2546 2546 revs.remove(ctx.rev())
2547 2547 if not revs:
2548 2548 return -1
2549 2549
2550 2550 # analyze revs for earlier grafts
2551 2551 ids = {}
2552 2552 for ctx in repo.set("%ld", revs):
2553 2553 ids[ctx.hex()] = ctx.rev()
2554 2554 n = ctx.extra().get('source')
2555 2555 if n:
2556 2556 ids[n] = ctx.rev()
2557 2557
2558 2558 # check ancestors for earlier grafts
2559 2559 ui.debug('scanning for duplicate grafts\n')
2560 2560 for ctx in repo.set("::. - ::%ld", revs):
2561 2561 n = ctx.extra().get('source')
2562 2562 if n in ids:
2563 2563 r = repo[n].rev()
2564 2564 if r in revs:
2565 2565 ui.warn(_('skipping already grafted revision %s\n') % r)
2566 2566 revs.remove(r)
2567 2567 elif ids[n] in revs:
2568 2568 ui.warn(_('skipping already grafted revision %s '
2569 2569 '(same origin %d)\n') % (ids[n], r))
2570 2570 revs.remove(ids[n])
2571 2571 elif ctx.hex() in ids:
2572 2572 r = ids[ctx.hex()]
2573 2573 ui.warn(_('skipping already grafted revision %s '
2574 2574 '(was grafted from %d)\n') % (r, ctx.rev()))
2575 2575 revs.remove(r)
2576 2576 if not revs:
2577 2577 return -1
2578 2578
2579 2579 for pos, ctx in enumerate(repo.set("%ld", revs)):
2580 2580 current = repo['.']
2581 2581 ui.status(_('grafting revision %s\n') % ctx.rev())
2582 2582
2583 2583 # we don't merge the first commit when continuing
2584 2584 if not cont:
2585 2585 # perform the graft merge with p1(rev) as 'ancestor'
2586 2586 try:
2587 2587 # ui.forcemerge is an internal variable, do not document
2588 2588 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2589 2589 stats = mergemod.update(repo, ctx.node(), True, True, False,
2590 2590 ctx.p1().node())
2591 2591 finally:
2592 2592 ui.setconfig('ui', 'forcemerge', '')
2593 2593 # drop the second merge parent
2594 2594 repo.dirstate.setparents(current.node(), nullid)
2595 2595 repo.dirstate.write()
2596 2596 # fix up dirstate for copies and renames
2597 2597 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2598 2598 # report any conflicts
2599 2599 if stats and stats[3] > 0:
2600 2600 # write out state for --continue
2601 2601 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2602 2602 repo.opener.write('graftstate', ''.join(nodelines))
2603 2603 raise util.Abort(
2604 2604 _("unresolved conflicts, can't continue"),
2605 2605 hint=_('use hg resolve and hg graft --continue'))
2606 2606 else:
2607 2607 cont = False
2608 2608
2609 2609 # commit
2610 2610 source = ctx.extra().get('source')
2611 2611 if not source:
2612 2612 source = ctx.hex()
2613 2613 extra = {'source': source}
2614 2614 user = ctx.user()
2615 2615 if opts.get('user'):
2616 2616 user = opts['user']
2617 2617 date = ctx.date()
2618 2618 if opts.get('date'):
2619 2619 date = opts['date']
2620 2620 repo.commit(text=ctx.description(), user=user,
2621 2621 date=date, extra=extra, editor=editor)
2622 2622
2623 2623 # remove state when we complete successfully
2624 2624 if os.path.exists(repo.join('graftstate')):
2625 2625 util.unlinkpath(repo.join('graftstate'))
2626 2626
2627 2627 return 0
2628 2628
2629 2629 @command('grep',
2630 2630 [('0', 'print0', None, _('end fields with NUL')),
2631 2631 ('', 'all', None, _('print all revisions that match')),
2632 2632 ('a', 'text', None, _('treat all files as text')),
2633 2633 ('f', 'follow', None,
2634 2634 _('follow changeset history,'
2635 2635 ' or file history across copies and renames')),
2636 2636 ('i', 'ignore-case', None, _('ignore case when matching')),
2637 2637 ('l', 'files-with-matches', None,
2638 2638 _('print only filenames and revisions that match')),
2639 2639 ('n', 'line-number', None, _('print matching line numbers')),
2640 2640 ('r', 'rev', [],
2641 2641 _('only search files changed within revision range'), _('REV')),
2642 2642 ('u', 'user', None, _('list the author (long with -v)')),
2643 2643 ('d', 'date', None, _('list the date (short with -q)')),
2644 2644 ] + walkopts,
2645 2645 _('[OPTION]... PATTERN [FILE]...'))
2646 2646 def grep(ui, repo, pattern, *pats, **opts):
2647 2647 """search for a pattern in specified files and revisions
2648 2648
2649 2649 Search revisions of files for a regular expression.
2650 2650
2651 2651 This command behaves differently than Unix grep. It only accepts
2652 2652 Python/Perl regexps. It searches repository history, not the
2653 2653 working directory. It always prints the revision number in which a
2654 2654 match appears.
2655 2655
2656 2656 By default, grep only prints output for the first revision of a
2657 2657 file in which it finds a match. To get it to print every revision
2658 2658 that contains a change in match status ("-" for a match that
2659 2659 becomes a non-match, or "+" for a non-match that becomes a match),
2660 2660 use the --all flag.
2661 2661
2662 2662 Returns 0 if a match is found, 1 otherwise.
2663 2663 """
2664 2664 reflags = 0
2665 2665 if opts.get('ignore_case'):
2666 2666 reflags |= re.I
2667 2667 try:
2668 2668 regexp = re.compile(pattern, reflags)
2669 2669 except re.error, inst:
2670 2670 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2671 2671 return 1
2672 2672 sep, eol = ':', '\n'
2673 2673 if opts.get('print0'):
2674 2674 sep = eol = '\0'
2675 2675
2676 2676 getfile = util.lrucachefunc(repo.file)
2677 2677
2678 2678 def matchlines(body):
2679 2679 begin = 0
2680 2680 linenum = 0
2681 2681 while True:
2682 2682 match = regexp.search(body, begin)
2683 2683 if not match:
2684 2684 break
2685 2685 mstart, mend = match.span()
2686 2686 linenum += body.count('\n', begin, mstart) + 1
2687 2687 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2688 2688 begin = body.find('\n', mend) + 1 or len(body) + 1
2689 2689 lend = begin - 1
2690 2690 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2691 2691
2692 2692 class linestate(object):
2693 2693 def __init__(self, line, linenum, colstart, colend):
2694 2694 self.line = line
2695 2695 self.linenum = linenum
2696 2696 self.colstart = colstart
2697 2697 self.colend = colend
2698 2698
2699 2699 def __hash__(self):
2700 2700 return hash((self.linenum, self.line))
2701 2701
2702 2702 def __eq__(self, other):
2703 2703 return self.line == other.line
2704 2704
2705 2705 matches = {}
2706 2706 copies = {}
2707 2707 def grepbody(fn, rev, body):
2708 2708 matches[rev].setdefault(fn, [])
2709 2709 m = matches[rev][fn]
2710 2710 for lnum, cstart, cend, line in matchlines(body):
2711 2711 s = linestate(line, lnum, cstart, cend)
2712 2712 m.append(s)
2713 2713
2714 2714 def difflinestates(a, b):
2715 2715 sm = difflib.SequenceMatcher(None, a, b)
2716 2716 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2717 2717 if tag == 'insert':
2718 2718 for i in xrange(blo, bhi):
2719 2719 yield ('+', b[i])
2720 2720 elif tag == 'delete':
2721 2721 for i in xrange(alo, ahi):
2722 2722 yield ('-', a[i])
2723 2723 elif tag == 'replace':
2724 2724 for i in xrange(alo, ahi):
2725 2725 yield ('-', a[i])
2726 2726 for i in xrange(blo, bhi):
2727 2727 yield ('+', b[i])
2728 2728
2729 2729 def display(fn, ctx, pstates, states):
2730 2730 rev = ctx.rev()
2731 2731 datefunc = ui.quiet and util.shortdate or util.datestr
2732 2732 found = False
2733 2733 filerevmatches = {}
2734 2734 def binary():
2735 2735 flog = getfile(fn)
2736 2736 return util.binary(flog.read(ctx.filenode(fn)))
2737 2737
2738 2738 if opts.get('all'):
2739 2739 iter = difflinestates(pstates, states)
2740 2740 else:
2741 2741 iter = [('', l) for l in states]
2742 2742 for change, l in iter:
2743 2743 cols = [fn, str(rev)]
2744 2744 before, match, after = None, None, None
2745 2745 if opts.get('line_number'):
2746 2746 cols.append(str(l.linenum))
2747 2747 if opts.get('all'):
2748 2748 cols.append(change)
2749 2749 if opts.get('user'):
2750 2750 cols.append(ui.shortuser(ctx.user()))
2751 2751 if opts.get('date'):
2752 2752 cols.append(datefunc(ctx.date()))
2753 2753 if opts.get('files_with_matches'):
2754 2754 c = (fn, rev)
2755 2755 if c in filerevmatches:
2756 2756 continue
2757 2757 filerevmatches[c] = 1
2758 2758 else:
2759 2759 before = l.line[:l.colstart]
2760 2760 match = l.line[l.colstart:l.colend]
2761 2761 after = l.line[l.colend:]
2762 2762 ui.write(sep.join(cols))
2763 2763 if before is not None:
2764 2764 if not opts.get('text') and binary():
2765 2765 ui.write(sep + " Binary file matches")
2766 2766 else:
2767 2767 ui.write(sep + before)
2768 2768 ui.write(match, label='grep.match')
2769 2769 ui.write(after)
2770 2770 ui.write(eol)
2771 2771 found = True
2772 2772 return found
2773 2773
2774 2774 skip = {}
2775 2775 revfiles = {}
2776 2776 matchfn = scmutil.match(repo[None], pats, opts)
2777 2777 found = False
2778 2778 follow = opts.get('follow')
2779 2779
2780 2780 def prep(ctx, fns):
2781 2781 rev = ctx.rev()
2782 2782 pctx = ctx.p1()
2783 2783 parent = pctx.rev()
2784 2784 matches.setdefault(rev, {})
2785 2785 matches.setdefault(parent, {})
2786 2786 files = revfiles.setdefault(rev, [])
2787 2787 for fn in fns:
2788 2788 flog = getfile(fn)
2789 2789 try:
2790 2790 fnode = ctx.filenode(fn)
2791 2791 except error.LookupError:
2792 2792 continue
2793 2793
2794 2794 copied = flog.renamed(fnode)
2795 2795 copy = follow and copied and copied[0]
2796 2796 if copy:
2797 2797 copies.setdefault(rev, {})[fn] = copy
2798 2798 if fn in skip:
2799 2799 if copy:
2800 2800 skip[copy] = True
2801 2801 continue
2802 2802 files.append(fn)
2803 2803
2804 2804 if fn not in matches[rev]:
2805 2805 grepbody(fn, rev, flog.read(fnode))
2806 2806
2807 2807 pfn = copy or fn
2808 2808 if pfn not in matches[parent]:
2809 2809 try:
2810 2810 fnode = pctx.filenode(pfn)
2811 2811 grepbody(pfn, parent, flog.read(fnode))
2812 2812 except error.LookupError:
2813 2813 pass
2814 2814
2815 2815 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2816 2816 rev = ctx.rev()
2817 2817 parent = ctx.p1().rev()
2818 2818 for fn in sorted(revfiles.get(rev, [])):
2819 2819 states = matches[rev][fn]
2820 2820 copy = copies.get(rev, {}).get(fn)
2821 2821 if fn in skip:
2822 2822 if copy:
2823 2823 skip[copy] = True
2824 2824 continue
2825 2825 pstates = matches.get(parent, {}).get(copy or fn, [])
2826 2826 if pstates or states:
2827 2827 r = display(fn, ctx, pstates, states)
2828 2828 found = found or r
2829 2829 if r and not opts.get('all'):
2830 2830 skip[fn] = True
2831 2831 if copy:
2832 2832 skip[copy] = True
2833 2833 del matches[rev]
2834 2834 del revfiles[rev]
2835 2835
2836 2836 return not found
2837 2837
2838 2838 @command('heads',
2839 2839 [('r', 'rev', '',
2840 2840 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2841 2841 ('t', 'topo', False, _('show topological heads only')),
2842 2842 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2843 2843 ('c', 'closed', False, _('show normal and closed branch heads')),
2844 2844 ] + templateopts,
2845 2845 _('[-ac] [-r STARTREV] [REV]...'))
2846 2846 def heads(ui, repo, *branchrevs, **opts):
2847 2847 """show current repository heads or show branch heads
2848 2848
2849 2849 With no arguments, show all repository branch heads.
2850 2850
2851 2851 Repository "heads" are changesets with no child changesets. They are
2852 2852 where development generally takes place and are the usual targets
2853 2853 for update and merge operations. Branch heads are changesets that have
2854 2854 no child changeset on the same branch.
2855 2855
2856 2856 If one or more REVs are given, only branch heads on the branches
2857 2857 associated with the specified changesets are shown. This means
2858 2858 that you can use :hg:`heads foo` to see the heads on a branch
2859 2859 named ``foo``.
2860 2860
2861 2861 If -c/--closed is specified, also show branch heads marked closed
2862 2862 (see :hg:`commit --close-branch`).
2863 2863
2864 2864 If STARTREV is specified, only those heads that are descendants of
2865 2865 STARTREV will be displayed.
2866 2866
2867 2867 If -t/--topo is specified, named branch mechanics will be ignored and only
2868 2868 changesets without children will be shown.
2869 2869
2870 2870 Returns 0 if matching heads are found, 1 if not.
2871 2871 """
2872 2872
2873 2873 start = None
2874 2874 if 'rev' in opts:
2875 2875 start = scmutil.revsingle(repo, opts['rev'], None).node()
2876 2876
2877 2877 if opts.get('topo'):
2878 2878 heads = [repo[h] for h in repo.heads(start)]
2879 2879 else:
2880 2880 heads = []
2881 2881 for branch in repo.branchmap():
2882 2882 heads += repo.branchheads(branch, start, opts.get('closed'))
2883 2883 heads = [repo[h] for h in heads]
2884 2884
2885 2885 if branchrevs:
2886 2886 branches = set(repo[br].branch() for br in branchrevs)
2887 2887 heads = [h for h in heads if h.branch() in branches]
2888 2888
2889 2889 if opts.get('active') and branchrevs:
2890 2890 dagheads = repo.heads(start)
2891 2891 heads = [h for h in heads if h.node() in dagheads]
2892 2892
2893 2893 if branchrevs:
2894 2894 haveheads = set(h.branch() for h in heads)
2895 2895 if branches - haveheads:
2896 2896 headless = ', '.join(b for b in branches - haveheads)
2897 2897 msg = _('no open branch heads found on branches %s')
2898 2898 if opts.get('rev'):
2899 2899 msg += _(' (started at %s)' % opts['rev'])
2900 2900 ui.warn((msg + '\n') % headless)
2901 2901
2902 2902 if not heads:
2903 2903 return 1
2904 2904
2905 2905 heads = sorted(heads, key=lambda x: -x.rev())
2906 2906 displayer = cmdutil.show_changeset(ui, repo, opts)
2907 2907 for ctx in heads:
2908 2908 displayer.show(ctx)
2909 2909 displayer.close()
2910 2910
2911 2911 @command('help',
2912 2912 [('e', 'extension', None, _('show only help for extensions')),
2913 2913 ('c', 'command', None, _('show only help for commands'))],
2914 2914 _('[-ec] [TOPIC]'))
2915 2915 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2916 2916 """show help for a given topic or a help overview
2917 2917
2918 2918 With no arguments, print a list of commands with short help messages.
2919 2919
2920 2920 Given a topic, extension, or command name, print help for that
2921 2921 topic.
2922 2922
2923 2923 Returns 0 if successful.
2924 2924 """
2925 2925
2926 2926 textwidth = min(ui.termwidth(), 80) - 2
2927 2927
2928 2928 def optrst(options):
2929 2929 data = []
2930 2930 multioccur = False
2931 2931 for option in options:
2932 2932 if len(option) == 5:
2933 2933 shortopt, longopt, default, desc, optlabel = option
2934 2934 else:
2935 2935 shortopt, longopt, default, desc = option
2936 2936 optlabel = _("VALUE") # default label
2937 2937
2938 2938 if _("DEPRECATED") in desc and not ui.verbose:
2939 2939 continue
2940 2940
2941 2941 so = ''
2942 2942 if shortopt:
2943 2943 so = '-' + shortopt
2944 2944 lo = '--' + longopt
2945 2945 if default:
2946 2946 desc += _(" (default: %s)") % default
2947 2947
2948 2948 if isinstance(default, list):
2949 2949 lo += " %s [+]" % optlabel
2950 2950 multioccur = True
2951 2951 elif (default is not None) and not isinstance(default, bool):
2952 2952 lo += " %s" % optlabel
2953 2953
2954 2954 data.append((so, lo, desc))
2955 2955
2956 2956 rst = minirst.maketable(data, 1)
2957 2957
2958 2958 if multioccur:
2959 2959 rst += _("\n[+] marked option can be specified multiple times\n")
2960 2960
2961 2961 return rst
2962 2962
2963 2963 # list all option lists
2964 2964 def opttext(optlist, width):
2965 2965 rst = ''
2966 2966 if not optlist:
2967 2967 return ''
2968 2968
2969 2969 for title, options in optlist:
2970 2970 rst += '\n%s\n' % title
2971 2971 if options:
2972 2972 rst += "\n"
2973 2973 rst += optrst(options)
2974 2974 rst += '\n'
2975 2975
2976 2976 return '\n' + minirst.format(rst, width)
2977 2977
2978 2978 def addglobalopts(optlist, aliases):
2979 2979 if ui.quiet:
2980 2980 return []
2981 2981
2982 2982 if ui.verbose:
2983 2983 optlist.append((_("global options:"), globalopts))
2984 2984 if name == 'shortlist':
2985 2985 optlist.append((_('use "hg help" for the full list '
2986 2986 'of commands'), ()))
2987 2987 else:
2988 2988 if name == 'shortlist':
2989 2989 msg = _('use "hg help" for the full list of commands '
2990 2990 'or "hg -v" for details')
2991 2991 elif name and not full:
2992 2992 msg = _('use "hg help %s" to show the full help text' % name)
2993 2993 elif aliases:
2994 2994 msg = _('use "hg -v help%s" to show builtin aliases and '
2995 2995 'global options') % (name and " " + name or "")
2996 2996 else:
2997 2997 msg = _('use "hg -v help %s" to show more info') % name
2998 2998 optlist.append((msg, ()))
2999 2999
3000 3000 def helpcmd(name):
3001 3001 try:
3002 3002 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3003 3003 except error.AmbiguousCommand, inst:
3004 3004 # py3k fix: except vars can't be used outside the scope of the
3005 3005 # except block, nor can be used inside a lambda. python issue4617
3006 3006 prefix = inst.args[0]
3007 3007 select = lambda c: c.lstrip('^').startswith(prefix)
3008 3008 helplist(select)
3009 3009 return
3010 3010
3011 3011 # check if it's an invalid alias and display its error if it is
3012 3012 if getattr(entry[0], 'badalias', False):
3013 3013 if not unknowncmd:
3014 3014 entry[0](ui)
3015 3015 return
3016 3016
3017 3017 rst = ""
3018 3018
3019 3019 # synopsis
3020 3020 if len(entry) > 2:
3021 3021 if entry[2].startswith('hg'):
3022 3022 rst += "%s\n" % entry[2]
3023 3023 else:
3024 3024 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3025 3025 else:
3026 3026 rst += 'hg %s\n' % aliases[0]
3027 3027
3028 3028 # aliases
3029 3029 if full and not ui.quiet and len(aliases) > 1:
3030 3030 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3031 3031
3032 3032 # description
3033 3033 doc = gettext(entry[0].__doc__)
3034 3034 if not doc:
3035 3035 doc = _("(no help text available)")
3036 3036 if util.safehasattr(entry[0], 'definition'): # aliased command
3037 3037 if entry[0].definition.startswith('!'): # shell alias
3038 3038 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3039 3039 else:
3040 3040 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3041 3041 if ui.quiet or not full:
3042 3042 doc = doc.splitlines()[0]
3043 3043 rst += "\n" + doc + "\n"
3044 3044
3045 3045 # check if this command shadows a non-trivial (multi-line)
3046 3046 # extension help text
3047 3047 try:
3048 3048 mod = extensions.find(name)
3049 3049 doc = gettext(mod.__doc__) or ''
3050 3050 if '\n' in doc.strip():
3051 3051 msg = _('use "hg help -e %s" to show help for '
3052 3052 'the %s extension') % (name, name)
3053 3053 rst += '\n%s\n' % msg
3054 3054 except KeyError:
3055 3055 pass
3056 3056
3057 3057 # options
3058 3058 if not ui.quiet and entry[1]:
3059 3059 rst += '\noptions:\n\n'
3060 3060 rst += optrst(entry[1])
3061 3061
3062 3062 if ui.verbose:
3063 3063 rst += '\nglobal options:\n\n'
3064 3064 rst += optrst(globalopts)
3065 3065
3066 3066 keep = ui.verbose and ['verbose'] or []
3067 3067 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3068 3068 ui.write(formatted)
3069 3069
3070 3070 if not ui.verbose:
3071 3071 if not full:
3072 3072 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3073 3073 % name)
3074 3074 elif not ui.quiet:
3075 3075 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3076 3076
3077 3077
3078 3078 def helplist(select=None):
3079 3079 # list of commands
3080 3080 if name == "shortlist":
3081 3081 header = _('basic commands:\n\n')
3082 3082 else:
3083 3083 header = _('list of commands:\n\n')
3084 3084
3085 3085 h = {}
3086 3086 cmds = {}
3087 3087 for c, e in table.iteritems():
3088 3088 f = c.split("|", 1)[0]
3089 3089 if select and not select(f):
3090 3090 continue
3091 3091 if (not select and name != 'shortlist' and
3092 3092 e[0].__module__ != __name__):
3093 3093 continue
3094 3094 if name == "shortlist" and not f.startswith("^"):
3095 3095 continue
3096 3096 f = f.lstrip("^")
3097 3097 if not ui.debugflag and f.startswith("debug"):
3098 3098 continue
3099 3099 doc = e[0].__doc__
3100 3100 if doc and 'DEPRECATED' in doc and not ui.verbose:
3101 3101 continue
3102 3102 doc = gettext(doc)
3103 3103 if not doc:
3104 3104 doc = _("(no help text available)")
3105 3105 h[f] = doc.splitlines()[0].rstrip()
3106 3106 cmds[f] = c.lstrip("^")
3107 3107
3108 3108 if not h:
3109 3109 ui.status(_('no commands defined\n'))
3110 3110 return
3111 3111
3112 3112 ui.status(header)
3113 3113 fns = sorted(h)
3114 3114 m = max(map(len, fns))
3115 3115 for f in fns:
3116 3116 if ui.verbose:
3117 3117 commands = cmds[f].replace("|",", ")
3118 3118 ui.write(" %s:\n %s\n"%(commands, h[f]))
3119 3119 else:
3120 3120 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3121 3121 initindent=' %-*s ' % (m, f),
3122 3122 hangindent=' ' * (m + 4))))
3123 3123
3124 3124 if not name:
3125 3125 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3126 3126 if text:
3127 3127 ui.write("\n%s" % minirst.format(text, textwidth))
3128 3128
3129 3129 ui.write(_("\nadditional help topics:\n\n"))
3130 3130 topics = []
3131 3131 for names, header, doc in help.helptable:
3132 3132 topics.append((sorted(names, key=len, reverse=True)[0], header))
3133 3133 topics_len = max([len(s[0]) for s in topics])
3134 3134 for t, desc in topics:
3135 3135 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3136 3136
3137 3137 optlist = []
3138 3138 addglobalopts(optlist, True)
3139 3139 ui.write(opttext(optlist, textwidth))
3140 3140
3141 3141 def helptopic(name):
3142 3142 for names, header, doc in help.helptable:
3143 3143 if name in names:
3144 3144 break
3145 3145 else:
3146 3146 raise error.UnknownCommand(name)
3147 3147
3148 3148 # description
3149 3149 if not doc:
3150 3150 doc = _("(no help text available)")
3151 3151 if util.safehasattr(doc, '__call__'):
3152 3152 doc = doc()
3153 3153
3154 3154 ui.write("%s\n\n" % header)
3155 3155 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3156 3156 try:
3157 3157 cmdutil.findcmd(name, table)
3158 3158 ui.write(_('\nuse "hg help -c %s" to see help for '
3159 3159 'the %s command\n') % (name, name))
3160 3160 except error.UnknownCommand:
3161 3161 pass
3162 3162
3163 3163 def helpext(name):
3164 3164 try:
3165 3165 mod = extensions.find(name)
3166 3166 doc = gettext(mod.__doc__) or _('no help text available')
3167 3167 except KeyError:
3168 3168 mod = None
3169 3169 doc = extensions.disabledext(name)
3170 3170 if not doc:
3171 3171 raise error.UnknownCommand(name)
3172 3172
3173 3173 if '\n' not in doc:
3174 3174 head, tail = doc, ""
3175 3175 else:
3176 3176 head, tail = doc.split('\n', 1)
3177 3177 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3178 3178 if tail:
3179 3179 ui.write(minirst.format(tail, textwidth))
3180 3180 ui.status('\n')
3181 3181
3182 3182 if mod:
3183 3183 try:
3184 3184 ct = mod.cmdtable
3185 3185 except AttributeError:
3186 3186 ct = {}
3187 3187 modcmds = set([c.split('|', 1)[0] for c in ct])
3188 3188 helplist(modcmds.__contains__)
3189 3189 else:
3190 3190 ui.write(_('use "hg help extensions" for information on enabling '
3191 3191 'extensions\n'))
3192 3192
3193 3193 def helpextcmd(name):
3194 3194 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3195 3195 doc = gettext(mod.__doc__).splitlines()[0]
3196 3196
3197 3197 msg = help.listexts(_("'%s' is provided by the following "
3198 3198 "extension:") % cmd, {ext: doc}, indent=4)
3199 3199 ui.write(minirst.format(msg, textwidth))
3200 3200 ui.write('\n')
3201 3201 ui.write(_('use "hg help extensions" for information on enabling '
3202 3202 'extensions\n'))
3203 3203
3204 3204 if name and name != 'shortlist':
3205 3205 i = None
3206 3206 if unknowncmd:
3207 3207 queries = (helpextcmd,)
3208 3208 elif opts.get('extension'):
3209 3209 queries = (helpext,)
3210 3210 elif opts.get('command'):
3211 3211 queries = (helpcmd,)
3212 3212 else:
3213 3213 queries = (helptopic, helpcmd, helpext, helpextcmd)
3214 3214 for f in queries:
3215 3215 try:
3216 3216 f(name)
3217 3217 i = None
3218 3218 break
3219 3219 except error.UnknownCommand, inst:
3220 3220 i = inst
3221 3221 if i:
3222 3222 raise i
3223 3223 else:
3224 3224 # program name
3225 3225 ui.status(_("Mercurial Distributed SCM\n"))
3226 3226 ui.status('\n')
3227 3227 helplist()
3228 3228
3229 3229
3230 3230 @command('identify|id',
3231 3231 [('r', 'rev', '',
3232 3232 _('identify the specified revision'), _('REV')),
3233 3233 ('n', 'num', None, _('show local revision number')),
3234 3234 ('i', 'id', None, _('show global revision id')),
3235 3235 ('b', 'branch', None, _('show branch')),
3236 3236 ('t', 'tags', None, _('show tags')),
3237 3237 ('B', 'bookmarks', None, _('show bookmarks'))],
3238 3238 _('[-nibtB] [-r REV] [SOURCE]'))
3239 3239 def identify(ui, repo, source=None, rev=None,
3240 3240 num=None, id=None, branch=None, tags=None, bookmarks=None):
3241 3241 """identify the working copy or specified revision
3242 3242
3243 3243 Print a summary identifying the repository state at REV using one or
3244 3244 two parent hash identifiers, followed by a "+" if the working
3245 3245 directory has uncommitted changes, the branch name (if not default),
3246 3246 a list of tags, and a list of bookmarks.
3247 3247
3248 3248 When REV is not given, print a summary of the current state of the
3249 3249 repository.
3250 3250
3251 3251 Specifying a path to a repository root or Mercurial bundle will
3252 3252 cause lookup to operate on that repository/bundle.
3253 3253
3254 3254 .. container:: verbose
3255 3255
3256 3256 Examples:
3257 3257
3258 3258 - generate a build identifier for the working directory::
3259 3259
3260 3260 hg id --id > build-id.dat
3261 3261
3262 3262 - find the revision corresponding to a tag::
3263 3263
3264 3264 hg id -n -r 1.3
3265 3265
3266 3266 - check the most recent revision of a remote repository::
3267 3267
3268 3268 hg id -r tip http://selenic.com/hg/
3269 3269
3270 3270 Returns 0 if successful.
3271 3271 """
3272 3272
3273 3273 if not repo and not source:
3274 3274 raise util.Abort(_("there is no Mercurial repository here "
3275 3275 "(.hg not found)"))
3276 3276
3277 3277 hexfunc = ui.debugflag and hex or short
3278 3278 default = not (num or id or branch or tags or bookmarks)
3279 3279 output = []
3280 3280 revs = []
3281 3281
3282 3282 if source:
3283 3283 source, branches = hg.parseurl(ui.expandpath(source))
3284 3284 repo = hg.peer(ui, {}, source)
3285 3285 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3286 3286
3287 3287 if not repo.local():
3288 3288 if num or branch or tags:
3289 3289 raise util.Abort(
3290 3290 _("can't query remote revision number, branch, or tags"))
3291 3291 if not rev and revs:
3292 3292 rev = revs[0]
3293 3293 if not rev:
3294 3294 rev = "tip"
3295 3295
3296 3296 remoterev = repo.lookup(rev)
3297 3297 if default or id:
3298 3298 output = [hexfunc(remoterev)]
3299 3299
3300 3300 def getbms():
3301 3301 bms = []
3302 3302
3303 3303 if 'bookmarks' in repo.listkeys('namespaces'):
3304 3304 hexremoterev = hex(remoterev)
3305 3305 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3306 3306 if bmr == hexremoterev]
3307 3307
3308 3308 return bms
3309 3309
3310 3310 if bookmarks:
3311 3311 output.extend(getbms())
3312 3312 elif default and not ui.quiet:
3313 3313 # multiple bookmarks for a single parent separated by '/'
3314 3314 bm = '/'.join(getbms())
3315 3315 if bm:
3316 3316 output.append(bm)
3317 3317 else:
3318 3318 if not rev:
3319 3319 ctx = repo[None]
3320 3320 parents = ctx.parents()
3321 3321 changed = ""
3322 3322 if default or id or num:
3323 3323 changed = util.any(repo.status()) and "+" or ""
3324 3324 if default or id:
3325 3325 output = ["%s%s" %
3326 3326 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3327 3327 if num:
3328 3328 output.append("%s%s" %
3329 3329 ('+'.join([str(p.rev()) for p in parents]), changed))
3330 3330 else:
3331 3331 ctx = scmutil.revsingle(repo, rev)
3332 3332 if default or id:
3333 3333 output = [hexfunc(ctx.node())]
3334 3334 if num:
3335 3335 output.append(str(ctx.rev()))
3336 3336
3337 3337 if default and not ui.quiet:
3338 3338 b = ctx.branch()
3339 3339 if b != 'default':
3340 3340 output.append("(%s)" % b)
3341 3341
3342 3342 # multiple tags for a single parent separated by '/'
3343 3343 t = '/'.join(ctx.tags())
3344 3344 if t:
3345 3345 output.append(t)
3346 3346
3347 3347 # multiple bookmarks for a single parent separated by '/'
3348 3348 bm = '/'.join(ctx.bookmarks())
3349 3349 if bm:
3350 3350 output.append(bm)
3351 3351 else:
3352 3352 if branch:
3353 3353 output.append(ctx.branch())
3354 3354
3355 3355 if tags:
3356 3356 output.extend(ctx.tags())
3357 3357
3358 3358 if bookmarks:
3359 3359 output.extend(ctx.bookmarks())
3360 3360
3361 3361 ui.write("%s\n" % ' '.join(output))
3362 3362
3363 3363 @command('import|patch',
3364 3364 [('p', 'strip', 1,
3365 3365 _('directory strip option for patch. This has the same '
3366 3366 'meaning as the corresponding patch option'), _('NUM')),
3367 3367 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3368 3368 ('e', 'edit', False, _('invoke editor on commit messages')),
3369 3369 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3370 3370 ('', 'no-commit', None,
3371 3371 _("don't commit, just update the working directory")),
3372 3372 ('', 'bypass', None,
3373 3373 _("apply patch without touching the working directory")),
3374 3374 ('', 'exact', None,
3375 3375 _('apply patch to the nodes from which it was generated')),
3376 3376 ('', 'import-branch', None,
3377 3377 _('use any branch information in patch (implied by --exact)'))] +
3378 3378 commitopts + commitopts2 + similarityopts,
3379 3379 _('[OPTION]... PATCH...'))
3380 3380 def import_(ui, repo, patch1=None, *patches, **opts):
3381 3381 """import an ordered set of patches
3382 3382
3383 3383 Import a list of patches and commit them individually (unless
3384 3384 --no-commit is specified).
3385 3385
3386 3386 If there are outstanding changes in the working directory, import
3387 3387 will abort unless given the -f/--force flag.
3388 3388
3389 3389 You can import a patch straight from a mail message. Even patches
3390 3390 as attachments work (to use the body part, it must have type
3391 3391 text/plain or text/x-patch). From and Subject headers of email
3392 3392 message are used as default committer and commit message. All
3393 3393 text/plain body parts before first diff are added to commit
3394 3394 message.
3395 3395
3396 3396 If the imported patch was generated by :hg:`export`, user and
3397 3397 description from patch override values from message headers and
3398 3398 body. Values given on command line with -m/--message and -u/--user
3399 3399 override these.
3400 3400
3401 3401 If --exact is specified, import will set the working directory to
3402 3402 the parent of each patch before applying it, and will abort if the
3403 3403 resulting changeset has a different ID than the one recorded in
3404 3404 the patch. This may happen due to character set problems or other
3405 3405 deficiencies in the text patch format.
3406 3406
3407 3407 Use --bypass to apply and commit patches directly to the
3408 3408 repository, not touching the working directory. Without --exact,
3409 3409 patches will be applied on top of the working directory parent
3410 3410 revision.
3411 3411
3412 3412 With -s/--similarity, hg will attempt to discover renames and
3413 3413 copies in the patch in the same way as 'addremove'.
3414 3414
3415 3415 To read a patch from standard input, use "-" as the patch name. If
3416 3416 a URL is specified, the patch will be downloaded from it.
3417 3417 See :hg:`help dates` for a list of formats valid for -d/--date.
3418 3418
3419 3419 .. container:: verbose
3420 3420
3421 3421 Examples:
3422 3422
3423 3423 - import a traditional patch from a website and detect renames::
3424 3424
3425 3425 hg import -s 80 http://example.com/bugfix.patch
3426 3426
3427 3427 - import a changeset from an hgweb server::
3428 3428
3429 3429 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3430 3430
3431 3431 - import all the patches in an Unix-style mbox::
3432 3432
3433 3433 hg import incoming-patches.mbox
3434 3434
3435 3435 - attempt to exactly restore an exported changeset (not always
3436 3436 possible)::
3437 3437
3438 3438 hg import --exact proposed-fix.patch
3439 3439
3440 3440 Returns 0 on success.
3441 3441 """
3442 3442
3443 3443 if not patch1:
3444 3444 raise util.Abort(_('need at least one patch to import'))
3445 3445
3446 3446 patches = (patch1,) + patches
3447 3447
3448 3448 date = opts.get('date')
3449 3449 if date:
3450 3450 opts['date'] = util.parsedate(date)
3451 3451
3452 3452 editor = cmdutil.commiteditor
3453 3453 if opts.get('edit'):
3454 3454 editor = cmdutil.commitforceeditor
3455 3455
3456 3456 update = not opts.get('bypass')
3457 3457 if not update and opts.get('no_commit'):
3458 3458 raise util.Abort(_('cannot use --no-commit with --bypass'))
3459 3459 try:
3460 3460 sim = float(opts.get('similarity') or 0)
3461 3461 except ValueError:
3462 3462 raise util.Abort(_('similarity must be a number'))
3463 3463 if sim < 0 or sim > 100:
3464 3464 raise util.Abort(_('similarity must be between 0 and 100'))
3465 3465 if sim and not update:
3466 3466 raise util.Abort(_('cannot use --similarity with --bypass'))
3467 3467
3468 3468 if (opts.get('exact') or not opts.get('force')) and update:
3469 3469 cmdutil.bailifchanged(repo)
3470 3470
3471 3471 base = opts["base"]
3472 3472 strip = opts["strip"]
3473 3473 wlock = lock = tr = None
3474 3474 msgs = []
3475 3475
3476 3476 def checkexact(repo, n, nodeid):
3477 3477 if opts.get('exact') and hex(n) != nodeid:
3478 3478 repo.rollback()
3479 3479 raise util.Abort(_('patch is damaged or loses information'))
3480 3480
3481 3481 def tryone(ui, hunk, parents):
3482 3482 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3483 3483 patch.extract(ui, hunk)
3484 3484
3485 3485 if not tmpname:
3486 3486 return (None, None)
3487 3487 msg = _('applied to working directory')
3488 3488
3489 3489 try:
3490 3490 cmdline_message = cmdutil.logmessage(ui, opts)
3491 3491 if cmdline_message:
3492 3492 # pickup the cmdline msg
3493 3493 message = cmdline_message
3494 3494 elif message:
3495 3495 # pickup the patch msg
3496 3496 message = message.strip()
3497 3497 else:
3498 3498 # launch the editor
3499 3499 message = None
3500 3500 ui.debug('message:\n%s\n' % message)
3501 3501
3502 3502 if len(parents) == 1:
3503 3503 parents.append(repo[nullid])
3504 3504 if opts.get('exact'):
3505 3505 if not nodeid or not p1:
3506 3506 raise util.Abort(_('not a Mercurial patch'))
3507 3507 p1 = repo[p1]
3508 3508 p2 = repo[p2 or nullid]
3509 3509 elif p2:
3510 3510 try:
3511 3511 p1 = repo[p1]
3512 3512 p2 = repo[p2]
3513 # Without any options, consider p2 only if the
3514 # patch is being applied on top of the recorded
3515 # first parent.
3516 if p1 != parents[0]:
3517 p1 = parents[0]
3518 p2 = repo[nullid]
3513 3519 except error.RepoError:
3514 3520 p1, p2 = parents
3515 3521 else:
3516 3522 p1, p2 = parents
3517 3523
3518 3524 n = None
3519 3525 if update:
3520 if opts.get('exact') and p1 != parents[0]:
3526 if p1 != parents[0]:
3521 3527 hg.clean(repo, p1.node())
3522 if p1 != parents[0] and p2 != parents[1]:
3528 if p2 != parents[1]:
3523 3529 repo.dirstate.setparents(p1.node(), p2.node())
3524 3530
3525 3531 if opts.get('exact') or opts.get('import_branch'):
3526 3532 repo.dirstate.setbranch(branch or 'default')
3527 3533
3528 3534 files = set()
3529 3535 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3530 3536 eolmode=None, similarity=sim / 100.0)
3531 3537 files = list(files)
3532 3538 if opts.get('no_commit'):
3533 3539 if message:
3534 3540 msgs.append(message)
3535 3541 else:
3536 if opts.get('exact'):
3542 if opts.get('exact') or p2:
3543 # If you got here, you either use --force and know what
3544 # you are doing or used --exact or a merge patch while
3545 # being updated to its first parent.
3537 3546 m = None
3538 3547 else:
3539 3548 m = scmutil.matchfiles(repo, files or [])
3540 3549 n = repo.commit(message, opts.get('user') or user,
3541 3550 opts.get('date') or date, match=m,
3542 3551 editor=editor)
3543 3552 checkexact(repo, n, nodeid)
3544 3553 else:
3545 3554 if opts.get('exact') or opts.get('import_branch'):
3546 3555 branch = branch or 'default'
3547 3556 else:
3548 3557 branch = p1.branch()
3549 3558 store = patch.filestore()
3550 3559 try:
3551 3560 files = set()
3552 3561 try:
3553 3562 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3554 3563 files, eolmode=None)
3555 3564 except patch.PatchError, e:
3556 3565 raise util.Abort(str(e))
3557 3566 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3558 3567 message,
3559 3568 opts.get('user') or user,
3560 3569 opts.get('date') or date,
3561 3570 branch, files, store,
3562 3571 editor=cmdutil.commiteditor)
3563 3572 repo.savecommitmessage(memctx.description())
3564 3573 n = memctx.commit()
3565 3574 checkexact(repo, n, nodeid)
3566 3575 finally:
3567 3576 store.close()
3568 3577 if n:
3569 3578 # i18n: refers to a short changeset id
3570 3579 msg = _('created %s') % short(n)
3571 3580 return (msg, n)
3572 3581 finally:
3573 3582 os.unlink(tmpname)
3574 3583
3575 3584 try:
3576 3585 try:
3577 3586 wlock = repo.wlock()
3578 3587 lock = repo.lock()
3579 3588 tr = repo.transaction('import')
3580 3589 parents = repo.parents()
3581 3590 for patchurl in patches:
3582 3591 if patchurl == '-':
3583 3592 ui.status(_('applying patch from stdin\n'))
3584 3593 patchfile = ui.fin
3585 3594 patchurl = 'stdin' # for error message
3586 3595 else:
3587 3596 patchurl = os.path.join(base, patchurl)
3588 3597 ui.status(_('applying %s\n') % patchurl)
3589 3598 patchfile = url.open(ui, patchurl)
3590 3599
3591 3600 haspatch = False
3592 3601 for hunk in patch.split(patchfile):
3593 3602 (msg, node) = tryone(ui, hunk, parents)
3594 3603 if msg:
3595 3604 haspatch = True
3596 3605 ui.note(msg + '\n')
3597 3606 if update or opts.get('exact'):
3598 3607 parents = repo.parents()
3599 3608 else:
3600 3609 parents = [repo[node]]
3601 3610
3602 3611 if not haspatch:
3603 3612 raise util.Abort(_('%s: no diffs found') % patchurl)
3604 3613
3605 3614 tr.close()
3606 3615 if msgs:
3607 3616 repo.savecommitmessage('\n* * *\n'.join(msgs))
3608 3617 except:
3609 3618 # wlock.release() indirectly calls dirstate.write(): since
3610 3619 # we're crashing, we do not want to change the working dir
3611 3620 # parent after all, so make sure it writes nothing
3612 3621 repo.dirstate.invalidate()
3613 3622 raise
3614 3623 finally:
3615 3624 if tr:
3616 3625 tr.release()
3617 3626 release(lock, wlock)
3618 3627
3619 3628 @command('incoming|in',
3620 3629 [('f', 'force', None,
3621 3630 _('run even if remote repository is unrelated')),
3622 3631 ('n', 'newest-first', None, _('show newest record first')),
3623 3632 ('', 'bundle', '',
3624 3633 _('file to store the bundles into'), _('FILE')),
3625 3634 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3626 3635 ('B', 'bookmarks', False, _("compare bookmarks")),
3627 3636 ('b', 'branch', [],
3628 3637 _('a specific branch you would like to pull'), _('BRANCH')),
3629 3638 ] + logopts + remoteopts + subrepoopts,
3630 3639 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3631 3640 def incoming(ui, repo, source="default", **opts):
3632 3641 """show new changesets found in source
3633 3642
3634 3643 Show new changesets found in the specified path/URL or the default
3635 3644 pull location. These are the changesets that would have been pulled
3636 3645 if a pull at the time you issued this command.
3637 3646
3638 3647 For remote repository, using --bundle avoids downloading the
3639 3648 changesets twice if the incoming is followed by a pull.
3640 3649
3641 3650 See pull for valid source format details.
3642 3651
3643 3652 Returns 0 if there are incoming changes, 1 otherwise.
3644 3653 """
3645 3654 if opts.get('bundle') and opts.get('subrepos'):
3646 3655 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3647 3656
3648 3657 if opts.get('bookmarks'):
3649 3658 source, branches = hg.parseurl(ui.expandpath(source),
3650 3659 opts.get('branch'))
3651 3660 other = hg.peer(repo, opts, source)
3652 3661 if 'bookmarks' not in other.listkeys('namespaces'):
3653 3662 ui.warn(_("remote doesn't support bookmarks\n"))
3654 3663 return 0
3655 3664 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3656 3665 return bookmarks.diff(ui, repo, other)
3657 3666
3658 3667 repo._subtoppath = ui.expandpath(source)
3659 3668 try:
3660 3669 return hg.incoming(ui, repo, source, opts)
3661 3670 finally:
3662 3671 del repo._subtoppath
3663 3672
3664 3673
3665 3674 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3666 3675 def init(ui, dest=".", **opts):
3667 3676 """create a new repository in the given directory
3668 3677
3669 3678 Initialize a new repository in the given directory. If the given
3670 3679 directory does not exist, it will be created.
3671 3680
3672 3681 If no directory is given, the current directory is used.
3673 3682
3674 3683 It is possible to specify an ``ssh://`` URL as the destination.
3675 3684 See :hg:`help urls` for more information.
3676 3685
3677 3686 Returns 0 on success.
3678 3687 """
3679 3688 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3680 3689
3681 3690 @command('locate',
3682 3691 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3683 3692 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3684 3693 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3685 3694 ] + walkopts,
3686 3695 _('[OPTION]... [PATTERN]...'))
3687 3696 def locate(ui, repo, *pats, **opts):
3688 3697 """locate files matching specific patterns
3689 3698
3690 3699 Print files under Mercurial control in the working directory whose
3691 3700 names match the given patterns.
3692 3701
3693 3702 By default, this command searches all directories in the working
3694 3703 directory. To search just the current directory and its
3695 3704 subdirectories, use "--include .".
3696 3705
3697 3706 If no patterns are given to match, this command prints the names
3698 3707 of all files under Mercurial control in the working directory.
3699 3708
3700 3709 If you want to feed the output of this command into the "xargs"
3701 3710 command, use the -0 option to both this command and "xargs". This
3702 3711 will avoid the problem of "xargs" treating single filenames that
3703 3712 contain whitespace as multiple filenames.
3704 3713
3705 3714 Returns 0 if a match is found, 1 otherwise.
3706 3715 """
3707 3716 end = opts.get('print0') and '\0' or '\n'
3708 3717 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3709 3718
3710 3719 ret = 1
3711 3720 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3712 3721 m.bad = lambda x, y: False
3713 3722 for abs in repo[rev].walk(m):
3714 3723 if not rev and abs not in repo.dirstate:
3715 3724 continue
3716 3725 if opts.get('fullpath'):
3717 3726 ui.write(repo.wjoin(abs), end)
3718 3727 else:
3719 3728 ui.write(((pats and m.rel(abs)) or abs), end)
3720 3729 ret = 0
3721 3730
3722 3731 return ret
3723 3732
3724 3733 @command('^log|history',
3725 3734 [('f', 'follow', None,
3726 3735 _('follow changeset history, or file history across copies and renames')),
3727 3736 ('', 'follow-first', None,
3728 3737 _('only follow the first parent of merge changesets')),
3729 3738 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3730 3739 ('C', 'copies', None, _('show copied files')),
3731 3740 ('k', 'keyword', [],
3732 3741 _('do case-insensitive search for a given text'), _('TEXT')),
3733 3742 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3734 3743 ('', 'removed', None, _('include revisions where files were removed')),
3735 3744 ('m', 'only-merges', None, _('show only merges')),
3736 3745 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3737 3746 ('', 'only-branch', [],
3738 3747 _('show only changesets within the given named branch (DEPRECATED)'),
3739 3748 _('BRANCH')),
3740 3749 ('b', 'branch', [],
3741 3750 _('show changesets within the given named branch'), _('BRANCH')),
3742 3751 ('P', 'prune', [],
3743 3752 _('do not display revision or any of its ancestors'), _('REV')),
3744 3753 ('', 'hidden', False, _('show hidden changesets')),
3745 3754 ] + logopts + walkopts,
3746 3755 _('[OPTION]... [FILE]'))
3747 3756 def log(ui, repo, *pats, **opts):
3748 3757 """show revision history of entire repository or files
3749 3758
3750 3759 Print the revision history of the specified files or the entire
3751 3760 project.
3752 3761
3753 3762 If no revision range is specified, the default is ``tip:0`` unless
3754 3763 --follow is set, in which case the working directory parent is
3755 3764 used as the starting revision.
3756 3765
3757 3766 File history is shown without following rename or copy history of
3758 3767 files. Use -f/--follow with a filename to follow history across
3759 3768 renames and copies. --follow without a filename will only show
3760 3769 ancestors or descendants of the starting revision.
3761 3770
3762 3771 By default this command prints revision number and changeset id,
3763 3772 tags, non-trivial parents, user, date and time, and a summary for
3764 3773 each commit. When the -v/--verbose switch is used, the list of
3765 3774 changed files and full commit message are shown.
3766 3775
3767 3776 .. note::
3768 3777 log -p/--patch may generate unexpected diff output for merge
3769 3778 changesets, as it will only compare the merge changeset against
3770 3779 its first parent. Also, only files different from BOTH parents
3771 3780 will appear in files:.
3772 3781
3773 3782 .. note::
3774 3783 for performance reasons, log FILE may omit duplicate changes
3775 3784 made on branches and will not show deletions. To see all
3776 3785 changes including duplicates and deletions, use the --removed
3777 3786 switch.
3778 3787
3779 3788 .. container:: verbose
3780 3789
3781 3790 Some examples:
3782 3791
3783 3792 - changesets with full descriptions and file lists::
3784 3793
3785 3794 hg log -v
3786 3795
3787 3796 - changesets ancestral to the working directory::
3788 3797
3789 3798 hg log -f
3790 3799
3791 3800 - last 10 commits on the current branch::
3792 3801
3793 3802 hg log -l 10 -b .
3794 3803
3795 3804 - changesets showing all modifications of a file, including removals::
3796 3805
3797 3806 hg log --removed file.c
3798 3807
3799 3808 - all changesets that touch a directory, with diffs, excluding merges::
3800 3809
3801 3810 hg log -Mp lib/
3802 3811
3803 3812 - all revision numbers that match a keyword::
3804 3813
3805 3814 hg log -k bug --template "{rev}\\n"
3806 3815
3807 3816 - check if a given changeset is included is a tagged release::
3808 3817
3809 3818 hg log -r "a21ccf and ancestor(1.9)"
3810 3819
3811 3820 - find all changesets by some user in a date range::
3812 3821
3813 3822 hg log -k alice -d "may 2008 to jul 2008"
3814 3823
3815 3824 - summary of all changesets after the last tag::
3816 3825
3817 3826 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3818 3827
3819 3828 See :hg:`help dates` for a list of formats valid for -d/--date.
3820 3829
3821 3830 See :hg:`help revisions` and :hg:`help revsets` for more about
3822 3831 specifying revisions.
3823 3832
3824 3833 Returns 0 on success.
3825 3834 """
3826 3835
3827 3836 matchfn = scmutil.match(repo[None], pats, opts)
3828 3837 limit = cmdutil.loglimit(opts)
3829 3838 count = 0
3830 3839
3831 3840 endrev = None
3832 3841 if opts.get('copies') and opts.get('rev'):
3833 3842 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3834 3843
3835 3844 df = False
3836 3845 if opts["date"]:
3837 3846 df = util.matchdate(opts["date"])
3838 3847
3839 3848 branches = opts.get('branch', []) + opts.get('only_branch', [])
3840 3849 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3841 3850
3842 3851 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3843 3852 def prep(ctx, fns):
3844 3853 rev = ctx.rev()
3845 3854 parents = [p for p in repo.changelog.parentrevs(rev)
3846 3855 if p != nullrev]
3847 3856 if opts.get('no_merges') and len(parents) == 2:
3848 3857 return
3849 3858 if opts.get('only_merges') and len(parents) != 2:
3850 3859 return
3851 3860 if opts.get('branch') and ctx.branch() not in opts['branch']:
3852 3861 return
3853 3862 if not opts.get('hidden') and ctx.hidden():
3854 3863 return
3855 3864 if df and not df(ctx.date()[0]):
3856 3865 return
3857 3866 if opts['user'] and not [k for k in opts['user']
3858 3867 if k.lower() in ctx.user().lower()]:
3859 3868 return
3860 3869 if opts.get('keyword'):
3861 3870 for k in [kw.lower() for kw in opts['keyword']]:
3862 3871 if (k in ctx.user().lower() or
3863 3872 k in ctx.description().lower() or
3864 3873 k in " ".join(ctx.files()).lower()):
3865 3874 break
3866 3875 else:
3867 3876 return
3868 3877
3869 3878 copies = None
3870 3879 if opts.get('copies') and rev:
3871 3880 copies = []
3872 3881 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3873 3882 for fn in ctx.files():
3874 3883 rename = getrenamed(fn, rev)
3875 3884 if rename:
3876 3885 copies.append((fn, rename[0]))
3877 3886
3878 3887 revmatchfn = None
3879 3888 if opts.get('patch') or opts.get('stat'):
3880 3889 if opts.get('follow') or opts.get('follow_first'):
3881 3890 # note: this might be wrong when following through merges
3882 3891 revmatchfn = scmutil.match(repo[None], fns, default='path')
3883 3892 else:
3884 3893 revmatchfn = matchfn
3885 3894
3886 3895 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3887 3896
3888 3897 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3889 3898 if count == limit:
3890 3899 break
3891 3900 if displayer.flush(ctx.rev()):
3892 3901 count += 1
3893 3902 displayer.close()
3894 3903
3895 3904 @command('manifest',
3896 3905 [('r', 'rev', '', _('revision to display'), _('REV')),
3897 3906 ('', 'all', False, _("list files from all revisions"))],
3898 3907 _('[-r REV]'))
3899 3908 def manifest(ui, repo, node=None, rev=None, **opts):
3900 3909 """output the current or given revision of the project manifest
3901 3910
3902 3911 Print a list of version controlled files for the given revision.
3903 3912 If no revision is given, the first parent of the working directory
3904 3913 is used, or the null revision if no revision is checked out.
3905 3914
3906 3915 With -v, print file permissions, symlink and executable bits.
3907 3916 With --debug, print file revision hashes.
3908 3917
3909 3918 If option --all is specified, the list of all files from all revisions
3910 3919 is printed. This includes deleted and renamed files.
3911 3920
3912 3921 Returns 0 on success.
3913 3922 """
3914 3923 if opts.get('all'):
3915 3924 if rev or node:
3916 3925 raise util.Abort(_("can't specify a revision with --all"))
3917 3926
3918 3927 res = []
3919 3928 prefix = "data/"
3920 3929 suffix = ".i"
3921 3930 plen = len(prefix)
3922 3931 slen = len(suffix)
3923 3932 lock = repo.lock()
3924 3933 try:
3925 3934 for fn, b, size in repo.store.datafiles():
3926 3935 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3927 3936 res.append(fn[plen:-slen])
3928 3937 finally:
3929 3938 lock.release()
3930 3939 for f in sorted(res):
3931 3940 ui.write("%s\n" % f)
3932 3941 return
3933 3942
3934 3943 if rev and node:
3935 3944 raise util.Abort(_("please specify just one revision"))
3936 3945
3937 3946 if not node:
3938 3947 node = rev
3939 3948
3940 3949 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3941 3950 ctx = scmutil.revsingle(repo, node)
3942 3951 for f in ctx:
3943 3952 if ui.debugflag:
3944 3953 ui.write("%40s " % hex(ctx.manifest()[f]))
3945 3954 if ui.verbose:
3946 3955 ui.write(decor[ctx.flags(f)])
3947 3956 ui.write("%s\n" % f)
3948 3957
3949 3958 @command('^merge',
3950 3959 [('f', 'force', None, _('force a merge with outstanding changes')),
3951 3960 ('r', 'rev', '', _('revision to merge'), _('REV')),
3952 3961 ('P', 'preview', None,
3953 3962 _('review revisions to merge (no merge is performed)'))
3954 3963 ] + mergetoolopts,
3955 3964 _('[-P] [-f] [[-r] REV]'))
3956 3965 def merge(ui, repo, node=None, **opts):
3957 3966 """merge working directory with another revision
3958 3967
3959 3968 The current working directory is updated with all changes made in
3960 3969 the requested revision since the last common predecessor revision.
3961 3970
3962 3971 Files that changed between either parent are marked as changed for
3963 3972 the next commit and a commit must be performed before any further
3964 3973 updates to the repository are allowed. The next commit will have
3965 3974 two parents.
3966 3975
3967 3976 ``--tool`` can be used to specify the merge tool used for file
3968 3977 merges. It overrides the HGMERGE environment variable and your
3969 3978 configuration files. See :hg:`help merge-tools` for options.
3970 3979
3971 3980 If no revision is specified, the working directory's parent is a
3972 3981 head revision, and the current branch contains exactly one other
3973 3982 head, the other head is merged with by default. Otherwise, an
3974 3983 explicit revision with which to merge with must be provided.
3975 3984
3976 3985 :hg:`resolve` must be used to resolve unresolved files.
3977 3986
3978 3987 To undo an uncommitted merge, use :hg:`update --clean .` which
3979 3988 will check out a clean copy of the original merge parent, losing
3980 3989 all changes.
3981 3990
3982 3991 Returns 0 on success, 1 if there are unresolved files.
3983 3992 """
3984 3993
3985 3994 if opts.get('rev') and node:
3986 3995 raise util.Abort(_("please specify just one revision"))
3987 3996 if not node:
3988 3997 node = opts.get('rev')
3989 3998
3990 3999 if not node:
3991 4000 branch = repo[None].branch()
3992 4001 bheads = repo.branchheads(branch)
3993 4002 if len(bheads) > 2:
3994 4003 raise util.Abort(_("branch '%s' has %d heads - "
3995 4004 "please merge with an explicit rev")
3996 4005 % (branch, len(bheads)),
3997 4006 hint=_("run 'hg heads .' to see heads"))
3998 4007
3999 4008 parent = repo.dirstate.p1()
4000 4009 if len(bheads) == 1:
4001 4010 if len(repo.heads()) > 1:
4002 4011 raise util.Abort(_("branch '%s' has one head - "
4003 4012 "please merge with an explicit rev")
4004 4013 % branch,
4005 4014 hint=_("run 'hg heads' to see all heads"))
4006 4015 msg = _('there is nothing to merge')
4007 4016 if parent != repo.lookup(repo[None].branch()):
4008 4017 msg = _('%s - use "hg update" instead') % msg
4009 4018 raise util.Abort(msg)
4010 4019
4011 4020 if parent not in bheads:
4012 4021 raise util.Abort(_('working directory not at a head revision'),
4013 4022 hint=_("use 'hg update' or merge with an "
4014 4023 "explicit revision"))
4015 4024 node = parent == bheads[0] and bheads[-1] or bheads[0]
4016 4025 else:
4017 4026 node = scmutil.revsingle(repo, node).node()
4018 4027
4019 4028 if opts.get('preview'):
4020 4029 # find nodes that are ancestors of p2 but not of p1
4021 4030 p1 = repo.lookup('.')
4022 4031 p2 = repo.lookup(node)
4023 4032 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4024 4033
4025 4034 displayer = cmdutil.show_changeset(ui, repo, opts)
4026 4035 for node in nodes:
4027 4036 displayer.show(repo[node])
4028 4037 displayer.close()
4029 4038 return 0
4030 4039
4031 4040 try:
4032 4041 # ui.forcemerge is an internal variable, do not document
4033 4042 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4034 4043 return hg.merge(repo, node, force=opts.get('force'))
4035 4044 finally:
4036 4045 ui.setconfig('ui', 'forcemerge', '')
4037 4046
4038 4047 @command('outgoing|out',
4039 4048 [('f', 'force', None, _('run even when the destination is unrelated')),
4040 4049 ('r', 'rev', [],
4041 4050 _('a changeset intended to be included in the destination'), _('REV')),
4042 4051 ('n', 'newest-first', None, _('show newest record first')),
4043 4052 ('B', 'bookmarks', False, _('compare bookmarks')),
4044 4053 ('b', 'branch', [], _('a specific branch you would like to push'),
4045 4054 _('BRANCH')),
4046 4055 ] + logopts + remoteopts + subrepoopts,
4047 4056 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4048 4057 def outgoing(ui, repo, dest=None, **opts):
4049 4058 """show changesets not found in the destination
4050 4059
4051 4060 Show changesets not found in the specified destination repository
4052 4061 or the default push location. These are the changesets that would
4053 4062 be pushed if a push was requested.
4054 4063
4055 4064 See pull for details of valid destination formats.
4056 4065
4057 4066 Returns 0 if there are outgoing changes, 1 otherwise.
4058 4067 """
4059 4068
4060 4069 if opts.get('bookmarks'):
4061 4070 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4062 4071 dest, branches = hg.parseurl(dest, opts.get('branch'))
4063 4072 other = hg.peer(repo, opts, dest)
4064 4073 if 'bookmarks' not in other.listkeys('namespaces'):
4065 4074 ui.warn(_("remote doesn't support bookmarks\n"))
4066 4075 return 0
4067 4076 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4068 4077 return bookmarks.diff(ui, other, repo)
4069 4078
4070 4079 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4071 4080 try:
4072 4081 return hg.outgoing(ui, repo, dest, opts)
4073 4082 finally:
4074 4083 del repo._subtoppath
4075 4084
4076 4085 @command('parents',
4077 4086 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4078 4087 ] + templateopts,
4079 4088 _('[-r REV] [FILE]'))
4080 4089 def parents(ui, repo, file_=None, **opts):
4081 4090 """show the parents of the working directory or revision
4082 4091
4083 4092 Print the working directory's parent revisions. If a revision is
4084 4093 given via -r/--rev, the parent of that revision will be printed.
4085 4094 If a file argument is given, the revision in which the file was
4086 4095 last changed (before the working directory revision or the
4087 4096 argument to --rev if given) is printed.
4088 4097
4089 4098 Returns 0 on success.
4090 4099 """
4091 4100
4092 4101 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4093 4102
4094 4103 if file_:
4095 4104 m = scmutil.match(ctx, (file_,), opts)
4096 4105 if m.anypats() or len(m.files()) != 1:
4097 4106 raise util.Abort(_('can only specify an explicit filename'))
4098 4107 file_ = m.files()[0]
4099 4108 filenodes = []
4100 4109 for cp in ctx.parents():
4101 4110 if not cp:
4102 4111 continue
4103 4112 try:
4104 4113 filenodes.append(cp.filenode(file_))
4105 4114 except error.LookupError:
4106 4115 pass
4107 4116 if not filenodes:
4108 4117 raise util.Abort(_("'%s' not found in manifest!") % file_)
4109 4118 fl = repo.file(file_)
4110 4119 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4111 4120 else:
4112 4121 p = [cp.node() for cp in ctx.parents()]
4113 4122
4114 4123 displayer = cmdutil.show_changeset(ui, repo, opts)
4115 4124 for n in p:
4116 4125 if n != nullid:
4117 4126 displayer.show(repo[n])
4118 4127 displayer.close()
4119 4128
4120 4129 @command('paths', [], _('[NAME]'))
4121 4130 def paths(ui, repo, search=None):
4122 4131 """show aliases for remote repositories
4123 4132
4124 4133 Show definition of symbolic path name NAME. If no name is given,
4125 4134 show definition of all available names.
4126 4135
4127 4136 Option -q/--quiet suppresses all output when searching for NAME
4128 4137 and shows only the path names when listing all definitions.
4129 4138
4130 4139 Path names are defined in the [paths] section of your
4131 4140 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4132 4141 repository, ``.hg/hgrc`` is used, too.
4133 4142
4134 4143 The path names ``default`` and ``default-push`` have a special
4135 4144 meaning. When performing a push or pull operation, they are used
4136 4145 as fallbacks if no location is specified on the command-line.
4137 4146 When ``default-push`` is set, it will be used for push and
4138 4147 ``default`` will be used for pull; otherwise ``default`` is used
4139 4148 as the fallback for both. When cloning a repository, the clone
4140 4149 source is written as ``default`` in ``.hg/hgrc``. Note that
4141 4150 ``default`` and ``default-push`` apply to all inbound (e.g.
4142 4151 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4143 4152 :hg:`bundle`) operations.
4144 4153
4145 4154 See :hg:`help urls` for more information.
4146 4155
4147 4156 Returns 0 on success.
4148 4157 """
4149 4158 if search:
4150 4159 for name, path in ui.configitems("paths"):
4151 4160 if name == search:
4152 4161 ui.status("%s\n" % util.hidepassword(path))
4153 4162 return
4154 4163 if not ui.quiet:
4155 4164 ui.warn(_("not found!\n"))
4156 4165 return 1
4157 4166 else:
4158 4167 for name, path in ui.configitems("paths"):
4159 4168 if ui.quiet:
4160 4169 ui.write("%s\n" % name)
4161 4170 else:
4162 4171 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4163 4172
4164 4173 def postincoming(ui, repo, modheads, optupdate, checkout):
4165 4174 if modheads == 0:
4166 4175 return
4167 4176 if optupdate:
4168 4177 try:
4169 4178 return hg.update(repo, checkout)
4170 4179 except util.Abort, inst:
4171 4180 ui.warn(_("not updating: %s\n" % str(inst)))
4172 4181 return 0
4173 4182 if modheads > 1:
4174 4183 currentbranchheads = len(repo.branchheads())
4175 4184 if currentbranchheads == modheads:
4176 4185 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4177 4186 elif currentbranchheads > 1:
4178 4187 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4179 4188 else:
4180 4189 ui.status(_("(run 'hg heads' to see heads)\n"))
4181 4190 else:
4182 4191 ui.status(_("(run 'hg update' to get a working copy)\n"))
4183 4192
4184 4193 @command('^pull',
4185 4194 [('u', 'update', None,
4186 4195 _('update to new branch head if changesets were pulled')),
4187 4196 ('f', 'force', None, _('run even when remote repository is unrelated')),
4188 4197 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4189 4198 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4190 4199 ('b', 'branch', [], _('a specific branch you would like to pull'),
4191 4200 _('BRANCH')),
4192 4201 ] + remoteopts,
4193 4202 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4194 4203 def pull(ui, repo, source="default", **opts):
4195 4204 """pull changes from the specified source
4196 4205
4197 4206 Pull changes from a remote repository to a local one.
4198 4207
4199 4208 This finds all changes from the repository at the specified path
4200 4209 or URL and adds them to a local repository (the current one unless
4201 4210 -R is specified). By default, this does not update the copy of the
4202 4211 project in the working directory.
4203 4212
4204 4213 Use :hg:`incoming` if you want to see what would have been added
4205 4214 by a pull at the time you issued this command. If you then decide
4206 4215 to add those changes to the repository, you should use :hg:`pull
4207 4216 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4208 4217
4209 4218 If SOURCE is omitted, the 'default' path will be used.
4210 4219 See :hg:`help urls` for more information.
4211 4220
4212 4221 Returns 0 on success, 1 if an update had unresolved files.
4213 4222 """
4214 4223 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4215 4224 other = hg.peer(repo, opts, source)
4216 4225 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4217 4226 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4218 4227
4219 4228 if opts.get('bookmark'):
4220 4229 if not revs:
4221 4230 revs = []
4222 4231 rb = other.listkeys('bookmarks')
4223 4232 for b in opts['bookmark']:
4224 4233 if b not in rb:
4225 4234 raise util.Abort(_('remote bookmark %s not found!') % b)
4226 4235 revs.append(rb[b])
4227 4236
4228 4237 if revs:
4229 4238 try:
4230 4239 revs = [other.lookup(rev) for rev in revs]
4231 4240 except error.CapabilityError:
4232 4241 err = _("other repository doesn't support revision lookup, "
4233 4242 "so a rev cannot be specified.")
4234 4243 raise util.Abort(err)
4235 4244
4236 4245 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4237 4246 bookmarks.updatefromremote(ui, repo, other)
4238 4247 if checkout:
4239 4248 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4240 4249 repo._subtoppath = source
4241 4250 try:
4242 4251 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4243 4252
4244 4253 finally:
4245 4254 del repo._subtoppath
4246 4255
4247 4256 # update specified bookmarks
4248 4257 if opts.get('bookmark'):
4249 4258 for b in opts['bookmark']:
4250 4259 # explicit pull overrides local bookmark if any
4251 4260 ui.status(_("importing bookmark %s\n") % b)
4252 4261 repo._bookmarks[b] = repo[rb[b]].node()
4253 4262 bookmarks.write(repo)
4254 4263
4255 4264 return ret
4256 4265
4257 4266 @command('^push',
4258 4267 [('f', 'force', None, _('force push')),
4259 4268 ('r', 'rev', [],
4260 4269 _('a changeset intended to be included in the destination'),
4261 4270 _('REV')),
4262 4271 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4263 4272 ('b', 'branch', [],
4264 4273 _('a specific branch you would like to push'), _('BRANCH')),
4265 4274 ('', 'new-branch', False, _('allow pushing a new branch')),
4266 4275 ] + remoteopts,
4267 4276 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4268 4277 def push(ui, repo, dest=None, **opts):
4269 4278 """push changes to the specified destination
4270 4279
4271 4280 Push changesets from the local repository to the specified
4272 4281 destination.
4273 4282
4274 4283 This operation is symmetrical to pull: it is identical to a pull
4275 4284 in the destination repository from the current one.
4276 4285
4277 4286 By default, push will not allow creation of new heads at the
4278 4287 destination, since multiple heads would make it unclear which head
4279 4288 to use. In this situation, it is recommended to pull and merge
4280 4289 before pushing.
4281 4290
4282 4291 Use --new-branch if you want to allow push to create a new named
4283 4292 branch that is not present at the destination. This allows you to
4284 4293 only create a new branch without forcing other changes.
4285 4294
4286 4295 Use -f/--force to override the default behavior and push all
4287 4296 changesets on all branches.
4288 4297
4289 4298 If -r/--rev is used, the specified revision and all its ancestors
4290 4299 will be pushed to the remote repository.
4291 4300
4292 4301 Please see :hg:`help urls` for important details about ``ssh://``
4293 4302 URLs. If DESTINATION is omitted, a default path will be used.
4294 4303
4295 4304 Returns 0 if push was successful, 1 if nothing to push.
4296 4305 """
4297 4306
4298 4307 if opts.get('bookmark'):
4299 4308 for b in opts['bookmark']:
4300 4309 # translate -B options to -r so changesets get pushed
4301 4310 if b in repo._bookmarks:
4302 4311 opts.setdefault('rev', []).append(b)
4303 4312 else:
4304 4313 # if we try to push a deleted bookmark, translate it to null
4305 4314 # this lets simultaneous -r, -b options continue working
4306 4315 opts.setdefault('rev', []).append("null")
4307 4316
4308 4317 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4309 4318 dest, branches = hg.parseurl(dest, opts.get('branch'))
4310 4319 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4311 4320 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4312 4321 other = hg.peer(repo, opts, dest)
4313 4322 if revs:
4314 4323 revs = [repo.lookup(rev) for rev in revs]
4315 4324
4316 4325 repo._subtoppath = dest
4317 4326 try:
4318 4327 # push subrepos depth-first for coherent ordering
4319 4328 c = repo['']
4320 4329 subs = c.substate # only repos that are committed
4321 4330 for s in sorted(subs):
4322 4331 if not c.sub(s).push(opts.get('force')):
4323 4332 return False
4324 4333 finally:
4325 4334 del repo._subtoppath
4326 4335 result = repo.push(other, opts.get('force'), revs=revs,
4327 4336 newbranch=opts.get('new_branch'))
4328 4337
4329 4338 result = (result == 0)
4330 4339
4331 4340 if opts.get('bookmark'):
4332 4341 rb = other.listkeys('bookmarks')
4333 4342 for b in opts['bookmark']:
4334 4343 # explicit push overrides remote bookmark if any
4335 4344 if b in repo._bookmarks:
4336 4345 ui.status(_("exporting bookmark %s\n") % b)
4337 4346 new = repo[b].hex()
4338 4347 elif b in rb:
4339 4348 ui.status(_("deleting remote bookmark %s\n") % b)
4340 4349 new = '' # delete
4341 4350 else:
4342 4351 ui.warn(_('bookmark %s does not exist on the local '
4343 4352 'or remote repository!\n') % b)
4344 4353 return 2
4345 4354 old = rb.get(b, '')
4346 4355 r = other.pushkey('bookmarks', b, old, new)
4347 4356 if not r:
4348 4357 ui.warn(_('updating bookmark %s failed!\n') % b)
4349 4358 if not result:
4350 4359 result = 2
4351 4360
4352 4361 return result
4353 4362
4354 4363 @command('recover', [])
4355 4364 def recover(ui, repo):
4356 4365 """roll back an interrupted transaction
4357 4366
4358 4367 Recover from an interrupted commit or pull.
4359 4368
4360 4369 This command tries to fix the repository status after an
4361 4370 interrupted operation. It should only be necessary when Mercurial
4362 4371 suggests it.
4363 4372
4364 4373 Returns 0 if successful, 1 if nothing to recover or verify fails.
4365 4374 """
4366 4375 if repo.recover():
4367 4376 return hg.verify(repo)
4368 4377 return 1
4369 4378
4370 4379 @command('^remove|rm',
4371 4380 [('A', 'after', None, _('record delete for missing files')),
4372 4381 ('f', 'force', None,
4373 4382 _('remove (and delete) file even if added or modified')),
4374 4383 ] + walkopts,
4375 4384 _('[OPTION]... FILE...'))
4376 4385 def remove(ui, repo, *pats, **opts):
4377 4386 """remove the specified files on the next commit
4378 4387
4379 4388 Schedule the indicated files for removal from the current branch.
4380 4389
4381 4390 This command schedules the files to be removed at the next commit.
4382 4391 To undo a remove before that, see :hg:`revert`. To undo added
4383 4392 files, see :hg:`forget`.
4384 4393
4385 4394 .. container:: verbose
4386 4395
4387 4396 -A/--after can be used to remove only files that have already
4388 4397 been deleted, -f/--force can be used to force deletion, and -Af
4389 4398 can be used to remove files from the next revision without
4390 4399 deleting them from the working directory.
4391 4400
4392 4401 The following table details the behavior of remove for different
4393 4402 file states (columns) and option combinations (rows). The file
4394 4403 states are Added [A], Clean [C], Modified [M] and Missing [!]
4395 4404 (as reported by :hg:`status`). The actions are Warn, Remove
4396 4405 (from branch) and Delete (from disk):
4397 4406
4398 4407 ======= == == == ==
4399 4408 A C M !
4400 4409 ======= == == == ==
4401 4410 none W RD W R
4402 4411 -f R RD RD R
4403 4412 -A W W W R
4404 4413 -Af R R R R
4405 4414 ======= == == == ==
4406 4415
4407 4416 Note that remove never deletes files in Added [A] state from the
4408 4417 working directory, not even if option --force is specified.
4409 4418
4410 4419 Returns 0 on success, 1 if any warnings encountered.
4411 4420 """
4412 4421
4413 4422 ret = 0
4414 4423 after, force = opts.get('after'), opts.get('force')
4415 4424 if not pats and not after:
4416 4425 raise util.Abort(_('no files specified'))
4417 4426
4418 4427 m = scmutil.match(repo[None], pats, opts)
4419 4428 s = repo.status(match=m, clean=True)
4420 4429 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4421 4430
4422 4431 for f in m.files():
4423 4432 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4424 4433 if os.path.exists(m.rel(f)):
4425 4434 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4426 4435 ret = 1
4427 4436
4428 4437 if force:
4429 4438 list = modified + deleted + clean + added
4430 4439 elif after:
4431 4440 list = deleted
4432 4441 for f in modified + added + clean:
4433 4442 ui.warn(_('not removing %s: file still exists (use -f'
4434 4443 ' to force removal)\n') % m.rel(f))
4435 4444 ret = 1
4436 4445 else:
4437 4446 list = deleted + clean
4438 4447 for f in modified:
4439 4448 ui.warn(_('not removing %s: file is modified (use -f'
4440 4449 ' to force removal)\n') % m.rel(f))
4441 4450 ret = 1
4442 4451 for f in added:
4443 4452 ui.warn(_('not removing %s: file has been marked for add'
4444 4453 ' (use forget to undo)\n') % m.rel(f))
4445 4454 ret = 1
4446 4455
4447 4456 for f in sorted(list):
4448 4457 if ui.verbose or not m.exact(f):
4449 4458 ui.status(_('removing %s\n') % m.rel(f))
4450 4459
4451 4460 wlock = repo.wlock()
4452 4461 try:
4453 4462 if not after:
4454 4463 for f in list:
4455 4464 if f in added:
4456 4465 continue # we never unlink added files on remove
4457 4466 try:
4458 4467 util.unlinkpath(repo.wjoin(f))
4459 4468 except OSError, inst:
4460 4469 if inst.errno != errno.ENOENT:
4461 4470 raise
4462 4471 repo[None].forget(list)
4463 4472 finally:
4464 4473 wlock.release()
4465 4474
4466 4475 return ret
4467 4476
4468 4477 @command('rename|move|mv',
4469 4478 [('A', 'after', None, _('record a rename that has already occurred')),
4470 4479 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4471 4480 ] + walkopts + dryrunopts,
4472 4481 _('[OPTION]... SOURCE... DEST'))
4473 4482 def rename(ui, repo, *pats, **opts):
4474 4483 """rename files; equivalent of copy + remove
4475 4484
4476 4485 Mark dest as copies of sources; mark sources for deletion. If dest
4477 4486 is a directory, copies are put in that directory. If dest is a
4478 4487 file, there can only be one source.
4479 4488
4480 4489 By default, this command copies the contents of files as they
4481 4490 exist in the working directory. If invoked with -A/--after, the
4482 4491 operation is recorded, but no copying is performed.
4483 4492
4484 4493 This command takes effect at the next commit. To undo a rename
4485 4494 before that, see :hg:`revert`.
4486 4495
4487 4496 Returns 0 on success, 1 if errors are encountered.
4488 4497 """
4489 4498 wlock = repo.wlock(False)
4490 4499 try:
4491 4500 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4492 4501 finally:
4493 4502 wlock.release()
4494 4503
4495 4504 @command('resolve',
4496 4505 [('a', 'all', None, _('select all unresolved files')),
4497 4506 ('l', 'list', None, _('list state of files needing merge')),
4498 4507 ('m', 'mark', None, _('mark files as resolved')),
4499 4508 ('u', 'unmark', None, _('mark files as unresolved')),
4500 4509 ('n', 'no-status', None, _('hide status prefix'))]
4501 4510 + mergetoolopts + walkopts,
4502 4511 _('[OPTION]... [FILE]...'))
4503 4512 def resolve(ui, repo, *pats, **opts):
4504 4513 """redo merges or set/view the merge status of files
4505 4514
4506 4515 Merges with unresolved conflicts are often the result of
4507 4516 non-interactive merging using the ``internal:merge`` configuration
4508 4517 setting, or a command-line merge tool like ``diff3``. The resolve
4509 4518 command is used to manage the files involved in a merge, after
4510 4519 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4511 4520 working directory must have two parents).
4512 4521
4513 4522 The resolve command can be used in the following ways:
4514 4523
4515 4524 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4516 4525 files, discarding any previous merge attempts. Re-merging is not
4517 4526 performed for files already marked as resolved. Use ``--all/-a``
4518 4527 to select all unresolved files. ``--tool`` can be used to specify
4519 4528 the merge tool used for the given files. It overrides the HGMERGE
4520 4529 environment variable and your configuration files. Previous file
4521 4530 contents are saved with a ``.orig`` suffix.
4522 4531
4523 4532 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4524 4533 (e.g. after having manually fixed-up the files). The default is
4525 4534 to mark all unresolved files.
4526 4535
4527 4536 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4528 4537 default is to mark all resolved files.
4529 4538
4530 4539 - :hg:`resolve -l`: list files which had or still have conflicts.
4531 4540 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4532 4541
4533 4542 Note that Mercurial will not let you commit files with unresolved
4534 4543 merge conflicts. You must use :hg:`resolve -m ...` before you can
4535 4544 commit after a conflicting merge.
4536 4545
4537 4546 Returns 0 on success, 1 if any files fail a resolve attempt.
4538 4547 """
4539 4548
4540 4549 all, mark, unmark, show, nostatus = \
4541 4550 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4542 4551
4543 4552 if (show and (mark or unmark)) or (mark and unmark):
4544 4553 raise util.Abort(_("too many options specified"))
4545 4554 if pats and all:
4546 4555 raise util.Abort(_("can't specify --all and patterns"))
4547 4556 if not (all or pats or show or mark or unmark):
4548 4557 raise util.Abort(_('no files or directories specified; '
4549 4558 'use --all to remerge all files'))
4550 4559
4551 4560 ms = mergemod.mergestate(repo)
4552 4561 m = scmutil.match(repo[None], pats, opts)
4553 4562 ret = 0
4554 4563
4555 4564 for f in ms:
4556 4565 if m(f):
4557 4566 if show:
4558 4567 if nostatus:
4559 4568 ui.write("%s\n" % f)
4560 4569 else:
4561 4570 ui.write("%s %s\n" % (ms[f].upper(), f),
4562 4571 label='resolve.' +
4563 4572 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4564 4573 elif mark:
4565 4574 ms.mark(f, "r")
4566 4575 elif unmark:
4567 4576 ms.mark(f, "u")
4568 4577 else:
4569 4578 wctx = repo[None]
4570 4579 mctx = wctx.parents()[-1]
4571 4580
4572 4581 # backup pre-resolve (merge uses .orig for its own purposes)
4573 4582 a = repo.wjoin(f)
4574 4583 util.copyfile(a, a + ".resolve")
4575 4584
4576 4585 try:
4577 4586 # resolve file
4578 4587 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4579 4588 if ms.resolve(f, wctx, mctx):
4580 4589 ret = 1
4581 4590 finally:
4582 4591 ui.setconfig('ui', 'forcemerge', '')
4583 4592
4584 4593 # replace filemerge's .orig file with our resolve file
4585 4594 util.rename(a + ".resolve", a + ".orig")
4586 4595
4587 4596 ms.commit()
4588 4597 return ret
4589 4598
4590 4599 @command('revert',
4591 4600 [('a', 'all', None, _('revert all changes when no arguments given')),
4592 4601 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4593 4602 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4594 4603 ('C', 'no-backup', None, _('do not save backup copies of files')),
4595 4604 ] + walkopts + dryrunopts,
4596 4605 _('[OPTION]... [-r REV] [NAME]...'))
4597 4606 def revert(ui, repo, *pats, **opts):
4598 4607 """restore files to their checkout state
4599 4608
4600 4609 .. note::
4601 4610 To check out earlier revisions, you should use :hg:`update REV`.
4602 4611 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4603 4612
4604 4613 With no revision specified, revert the specified files or directories
4605 4614 to the contents they had in the parent of the working directory.
4606 4615 This restores the contents of files to an unmodified
4607 4616 state and unschedules adds, removes, copies, and renames. If the
4608 4617 working directory has two parents, you must explicitly specify a
4609 4618 revision.
4610 4619
4611 4620 Using the -r/--rev or -d/--date options, revert the given files or
4612 4621 directories to their states as of a specific revision. Because
4613 4622 revert does not change the working directory parents, this will
4614 4623 cause these files to appear modified. This can be helpful to "back
4615 4624 out" some or all of an earlier change. See :hg:`backout` for a
4616 4625 related method.
4617 4626
4618 4627 Modified files are saved with a .orig suffix before reverting.
4619 4628 To disable these backups, use --no-backup.
4620 4629
4621 4630 See :hg:`help dates` for a list of formats valid for -d/--date.
4622 4631
4623 4632 Returns 0 on success.
4624 4633 """
4625 4634
4626 4635 if opts.get("date"):
4627 4636 if opts.get("rev"):
4628 4637 raise util.Abort(_("you can't specify a revision and a date"))
4629 4638 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4630 4639
4631 4640 parent, p2 = repo.dirstate.parents()
4632 4641 if not opts.get('rev') and p2 != nullid:
4633 4642 # revert after merge is a trap for new users (issue2915)
4634 4643 raise util.Abort(_('uncommitted merge with no revision specified'),
4635 4644 hint=_('use "hg update" or see "hg help revert"'))
4636 4645
4637 4646 ctx = scmutil.revsingle(repo, opts.get('rev'))
4638 4647 node = ctx.node()
4639 4648
4640 4649 if not pats and not opts.get('all'):
4641 4650 msg = _("no files or directories specified")
4642 4651 if p2 != nullid:
4643 4652 hint = _("uncommitted merge, use --all to discard all changes,"
4644 4653 " or 'hg update -C .' to abort the merge")
4645 4654 raise util.Abort(msg, hint=hint)
4646 4655 dirty = util.any(repo.status())
4647 4656 if node != parent:
4648 4657 if dirty:
4649 4658 hint = _("uncommitted changes, use --all to discard all"
4650 4659 " changes, or 'hg update %s' to update") % ctx.rev()
4651 4660 else:
4652 4661 hint = _("use --all to revert all files,"
4653 4662 " or 'hg update %s' to update") % ctx.rev()
4654 4663 elif dirty:
4655 4664 hint = _("uncommitted changes, use --all to discard all changes")
4656 4665 else:
4657 4666 hint = _("use --all to revert all files")
4658 4667 raise util.Abort(msg, hint=hint)
4659 4668
4660 4669 mf = ctx.manifest()
4661 4670 if node == parent:
4662 4671 pmf = mf
4663 4672 else:
4664 4673 pmf = None
4665 4674
4666 4675 # need all matching names in dirstate and manifest of target rev,
4667 4676 # so have to walk both. do not print errors if files exist in one
4668 4677 # but not other.
4669 4678
4670 4679 names = {}
4671 4680
4672 4681 wlock = repo.wlock()
4673 4682 try:
4674 4683 # walk dirstate.
4675 4684
4676 4685 m = scmutil.match(repo[None], pats, opts)
4677 4686 m.bad = lambda x, y: False
4678 4687 for abs in repo.walk(m):
4679 4688 names[abs] = m.rel(abs), m.exact(abs)
4680 4689
4681 4690 # walk target manifest.
4682 4691
4683 4692 def badfn(path, msg):
4684 4693 if path in names:
4685 4694 return
4686 4695 if path in repo[node].substate:
4687 4696 ui.warn("%s: %s\n" % (m.rel(path),
4688 4697 'reverting subrepos is unsupported'))
4689 4698 return
4690 4699 path_ = path + '/'
4691 4700 for f in names:
4692 4701 if f.startswith(path_):
4693 4702 return
4694 4703 ui.warn("%s: %s\n" % (m.rel(path), msg))
4695 4704
4696 4705 m = scmutil.match(repo[node], pats, opts)
4697 4706 m.bad = badfn
4698 4707 for abs in repo[node].walk(m):
4699 4708 if abs not in names:
4700 4709 names[abs] = m.rel(abs), m.exact(abs)
4701 4710
4702 4711 m = scmutil.matchfiles(repo, names)
4703 4712 changes = repo.status(match=m)[:4]
4704 4713 modified, added, removed, deleted = map(set, changes)
4705 4714
4706 4715 # if f is a rename, also revert the source
4707 4716 cwd = repo.getcwd()
4708 4717 for f in added:
4709 4718 src = repo.dirstate.copied(f)
4710 4719 if src and src not in names and repo.dirstate[src] == 'r':
4711 4720 removed.add(src)
4712 4721 names[src] = (repo.pathto(src, cwd), True)
4713 4722
4714 4723 def removeforget(abs):
4715 4724 if repo.dirstate[abs] == 'a':
4716 4725 return _('forgetting %s\n')
4717 4726 return _('removing %s\n')
4718 4727
4719 4728 revert = ([], _('reverting %s\n'))
4720 4729 add = ([], _('adding %s\n'))
4721 4730 remove = ([], removeforget)
4722 4731 undelete = ([], _('undeleting %s\n'))
4723 4732
4724 4733 disptable = (
4725 4734 # dispatch table:
4726 4735 # file state
4727 4736 # action if in target manifest
4728 4737 # action if not in target manifest
4729 4738 # make backup if in target manifest
4730 4739 # make backup if not in target manifest
4731 4740 (modified, revert, remove, True, True),
4732 4741 (added, revert, remove, True, False),
4733 4742 (removed, undelete, None, False, False),
4734 4743 (deleted, revert, remove, False, False),
4735 4744 )
4736 4745
4737 4746 for abs, (rel, exact) in sorted(names.items()):
4738 4747 mfentry = mf.get(abs)
4739 4748 target = repo.wjoin(abs)
4740 4749 def handle(xlist, dobackup):
4741 4750 xlist[0].append(abs)
4742 4751 if (dobackup and not opts.get('no_backup') and
4743 4752 os.path.lexists(target)):
4744 4753 bakname = "%s.orig" % rel
4745 4754 ui.note(_('saving current version of %s as %s\n') %
4746 4755 (rel, bakname))
4747 4756 if not opts.get('dry_run'):
4748 4757 util.rename(target, bakname)
4749 4758 if ui.verbose or not exact:
4750 4759 msg = xlist[1]
4751 4760 if not isinstance(msg, basestring):
4752 4761 msg = msg(abs)
4753 4762 ui.status(msg % rel)
4754 4763 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4755 4764 if abs not in table:
4756 4765 continue
4757 4766 # file has changed in dirstate
4758 4767 if mfentry:
4759 4768 handle(hitlist, backuphit)
4760 4769 elif misslist is not None:
4761 4770 handle(misslist, backupmiss)
4762 4771 break
4763 4772 else:
4764 4773 if abs not in repo.dirstate:
4765 4774 if mfentry:
4766 4775 handle(add, True)
4767 4776 elif exact:
4768 4777 ui.warn(_('file not managed: %s\n') % rel)
4769 4778 continue
4770 4779 # file has not changed in dirstate
4771 4780 if node == parent:
4772 4781 if exact:
4773 4782 ui.warn(_('no changes needed to %s\n') % rel)
4774 4783 continue
4775 4784 if pmf is None:
4776 4785 # only need parent manifest in this unlikely case,
4777 4786 # so do not read by default
4778 4787 pmf = repo[parent].manifest()
4779 4788 if abs in pmf and mfentry:
4780 4789 # if version of file is same in parent and target
4781 4790 # manifests, do nothing
4782 4791 if (pmf[abs] != mfentry or
4783 4792 pmf.flags(abs) != mf.flags(abs)):
4784 4793 handle(revert, False)
4785 4794 else:
4786 4795 handle(remove, False)
4787 4796
4788 4797 if not opts.get('dry_run'):
4789 4798 def checkout(f):
4790 4799 fc = ctx[f]
4791 4800 repo.wwrite(f, fc.data(), fc.flags())
4792 4801
4793 4802 audit_path = scmutil.pathauditor(repo.root)
4794 4803 for f in remove[0]:
4795 4804 if repo.dirstate[f] == 'a':
4796 4805 repo.dirstate.drop(f)
4797 4806 continue
4798 4807 audit_path(f)
4799 4808 try:
4800 4809 util.unlinkpath(repo.wjoin(f))
4801 4810 except OSError:
4802 4811 pass
4803 4812 repo.dirstate.remove(f)
4804 4813
4805 4814 normal = None
4806 4815 if node == parent:
4807 4816 # We're reverting to our parent. If possible, we'd like status
4808 4817 # to report the file as clean. We have to use normallookup for
4809 4818 # merges to avoid losing information about merged/dirty files.
4810 4819 if p2 != nullid:
4811 4820 normal = repo.dirstate.normallookup
4812 4821 else:
4813 4822 normal = repo.dirstate.normal
4814 4823 for f in revert[0]:
4815 4824 checkout(f)
4816 4825 if normal:
4817 4826 normal(f)
4818 4827
4819 4828 for f in add[0]:
4820 4829 checkout(f)
4821 4830 repo.dirstate.add(f)
4822 4831
4823 4832 normal = repo.dirstate.normallookup
4824 4833 if node == parent and p2 == nullid:
4825 4834 normal = repo.dirstate.normal
4826 4835 for f in undelete[0]:
4827 4836 checkout(f)
4828 4837 normal(f)
4829 4838
4830 4839 finally:
4831 4840 wlock.release()
4832 4841
4833 4842 @command('rollback', dryrunopts +
4834 4843 [('f', 'force', False, _('ignore safety measures'))])
4835 4844 def rollback(ui, repo, **opts):
4836 4845 """roll back the last transaction (dangerous)
4837 4846
4838 4847 This command should be used with care. There is only one level of
4839 4848 rollback, and there is no way to undo a rollback. It will also
4840 4849 restore the dirstate at the time of the last transaction, losing
4841 4850 any dirstate changes since that time. This command does not alter
4842 4851 the working directory.
4843 4852
4844 4853 Transactions are used to encapsulate the effects of all commands
4845 4854 that create new changesets or propagate existing changesets into a
4846 4855 repository. For example, the following commands are transactional,
4847 4856 and their effects can be rolled back:
4848 4857
4849 4858 - commit
4850 4859 - import
4851 4860 - pull
4852 4861 - push (with this repository as the destination)
4853 4862 - unbundle
4854 4863
4855 4864 It's possible to lose data with rollback: commit, update back to
4856 4865 an older changeset, and then rollback. The update removes the
4857 4866 changes you committed from the working directory, and rollback
4858 4867 removes them from history. To avoid data loss, you must pass
4859 4868 --force in this case.
4860 4869
4861 4870 This command is not intended for use on public repositories. Once
4862 4871 changes are visible for pull by other users, rolling a transaction
4863 4872 back locally is ineffective (someone else may already have pulled
4864 4873 the changes). Furthermore, a race is possible with readers of the
4865 4874 repository; for example an in-progress pull from the repository
4866 4875 may fail if a rollback is performed.
4867 4876
4868 4877 Returns 0 on success, 1 if no rollback data is available.
4869 4878 """
4870 4879 return repo.rollback(dryrun=opts.get('dry_run'),
4871 4880 force=opts.get('force'))
4872 4881
4873 4882 @command('root', [])
4874 4883 def root(ui, repo):
4875 4884 """print the root (top) of the current working directory
4876 4885
4877 4886 Print the root directory of the current repository.
4878 4887
4879 4888 Returns 0 on success.
4880 4889 """
4881 4890 ui.write(repo.root + "\n")
4882 4891
4883 4892 @command('^serve',
4884 4893 [('A', 'accesslog', '', _('name of access log file to write to'),
4885 4894 _('FILE')),
4886 4895 ('d', 'daemon', None, _('run server in background')),
4887 4896 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4888 4897 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4889 4898 # use string type, then we can check if something was passed
4890 4899 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4891 4900 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4892 4901 _('ADDR')),
4893 4902 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4894 4903 _('PREFIX')),
4895 4904 ('n', 'name', '',
4896 4905 _('name to show in web pages (default: working directory)'), _('NAME')),
4897 4906 ('', 'web-conf', '',
4898 4907 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4899 4908 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4900 4909 _('FILE')),
4901 4910 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4902 4911 ('', 'stdio', None, _('for remote clients')),
4903 4912 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4904 4913 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4905 4914 ('', 'style', '', _('template style to use'), _('STYLE')),
4906 4915 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4907 4916 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4908 4917 _('[OPTION]...'))
4909 4918 def serve(ui, repo, **opts):
4910 4919 """start stand-alone webserver
4911 4920
4912 4921 Start a local HTTP repository browser and pull server. You can use
4913 4922 this for ad-hoc sharing and browsing of repositories. It is
4914 4923 recommended to use a real web server to serve a repository for
4915 4924 longer periods of time.
4916 4925
4917 4926 Please note that the server does not implement access control.
4918 4927 This means that, by default, anybody can read from the server and
4919 4928 nobody can write to it by default. Set the ``web.allow_push``
4920 4929 option to ``*`` to allow everybody to push to the server. You
4921 4930 should use a real web server if you need to authenticate users.
4922 4931
4923 4932 By default, the server logs accesses to stdout and errors to
4924 4933 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4925 4934 files.
4926 4935
4927 4936 To have the server choose a free port number to listen on, specify
4928 4937 a port number of 0; in this case, the server will print the port
4929 4938 number it uses.
4930 4939
4931 4940 Returns 0 on success.
4932 4941 """
4933 4942
4934 4943 if opts["stdio"] and opts["cmdserver"]:
4935 4944 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4936 4945
4937 4946 def checkrepo():
4938 4947 if repo is None:
4939 4948 raise error.RepoError(_("There is no Mercurial repository here"
4940 4949 " (.hg not found)"))
4941 4950
4942 4951 if opts["stdio"]:
4943 4952 checkrepo()
4944 4953 s = sshserver.sshserver(ui, repo)
4945 4954 s.serve_forever()
4946 4955
4947 4956 if opts["cmdserver"]:
4948 4957 checkrepo()
4949 4958 s = commandserver.server(ui, repo, opts["cmdserver"])
4950 4959 return s.serve()
4951 4960
4952 4961 # this way we can check if something was given in the command-line
4953 4962 if opts.get('port'):
4954 4963 opts['port'] = util.getport(opts.get('port'))
4955 4964
4956 4965 baseui = repo and repo.baseui or ui
4957 4966 optlist = ("name templates style address port prefix ipv6"
4958 4967 " accesslog errorlog certificate encoding")
4959 4968 for o in optlist.split():
4960 4969 val = opts.get(o, '')
4961 4970 if val in (None, ''): # should check against default options instead
4962 4971 continue
4963 4972 baseui.setconfig("web", o, val)
4964 4973 if repo and repo.ui != baseui:
4965 4974 repo.ui.setconfig("web", o, val)
4966 4975
4967 4976 o = opts.get('web_conf') or opts.get('webdir_conf')
4968 4977 if not o:
4969 4978 if not repo:
4970 4979 raise error.RepoError(_("There is no Mercurial repository"
4971 4980 " here (.hg not found)"))
4972 4981 o = repo.root
4973 4982
4974 4983 app = hgweb.hgweb(o, baseui=ui)
4975 4984
4976 4985 class service(object):
4977 4986 def init(self):
4978 4987 util.setsignalhandler()
4979 4988 self.httpd = hgweb.server.create_server(ui, app)
4980 4989
4981 4990 if opts['port'] and not ui.verbose:
4982 4991 return
4983 4992
4984 4993 if self.httpd.prefix:
4985 4994 prefix = self.httpd.prefix.strip('/') + '/'
4986 4995 else:
4987 4996 prefix = ''
4988 4997
4989 4998 port = ':%d' % self.httpd.port
4990 4999 if port == ':80':
4991 5000 port = ''
4992 5001
4993 5002 bindaddr = self.httpd.addr
4994 5003 if bindaddr == '0.0.0.0':
4995 5004 bindaddr = '*'
4996 5005 elif ':' in bindaddr: # IPv6
4997 5006 bindaddr = '[%s]' % bindaddr
4998 5007
4999 5008 fqaddr = self.httpd.fqaddr
5000 5009 if ':' in fqaddr:
5001 5010 fqaddr = '[%s]' % fqaddr
5002 5011 if opts['port']:
5003 5012 write = ui.status
5004 5013 else:
5005 5014 write = ui.write
5006 5015 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5007 5016 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5008 5017
5009 5018 def run(self):
5010 5019 self.httpd.serve_forever()
5011 5020
5012 5021 service = service()
5013 5022
5014 5023 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5015 5024
5016 5025 @command('showconfig|debugconfig',
5017 5026 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5018 5027 _('[-u] [NAME]...'))
5019 5028 def showconfig(ui, repo, *values, **opts):
5020 5029 """show combined config settings from all hgrc files
5021 5030
5022 5031 With no arguments, print names and values of all config items.
5023 5032
5024 5033 With one argument of the form section.name, print just the value
5025 5034 of that config item.
5026 5035
5027 5036 With multiple arguments, print names and values of all config
5028 5037 items with matching section names.
5029 5038
5030 5039 With --debug, the source (filename and line number) is printed
5031 5040 for each config item.
5032 5041
5033 5042 Returns 0 on success.
5034 5043 """
5035 5044
5036 5045 for f in scmutil.rcpath():
5037 5046 ui.debug('read config from: %s\n' % f)
5038 5047 untrusted = bool(opts.get('untrusted'))
5039 5048 if values:
5040 5049 sections = [v for v in values if '.' not in v]
5041 5050 items = [v for v in values if '.' in v]
5042 5051 if len(items) > 1 or items and sections:
5043 5052 raise util.Abort(_('only one config item permitted'))
5044 5053 for section, name, value in ui.walkconfig(untrusted=untrusted):
5045 5054 value = str(value).replace('\n', '\\n')
5046 5055 sectname = section + '.' + name
5047 5056 if values:
5048 5057 for v in values:
5049 5058 if v == section:
5050 5059 ui.debug('%s: ' %
5051 5060 ui.configsource(section, name, untrusted))
5052 5061 ui.write('%s=%s\n' % (sectname, value))
5053 5062 elif v == sectname:
5054 5063 ui.debug('%s: ' %
5055 5064 ui.configsource(section, name, untrusted))
5056 5065 ui.write(value, '\n')
5057 5066 else:
5058 5067 ui.debug('%s: ' %
5059 5068 ui.configsource(section, name, untrusted))
5060 5069 ui.write('%s=%s\n' % (sectname, value))
5061 5070
5062 5071 @command('^status|st',
5063 5072 [('A', 'all', None, _('show status of all files')),
5064 5073 ('m', 'modified', None, _('show only modified files')),
5065 5074 ('a', 'added', None, _('show only added files')),
5066 5075 ('r', 'removed', None, _('show only removed files')),
5067 5076 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5068 5077 ('c', 'clean', None, _('show only files without changes')),
5069 5078 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5070 5079 ('i', 'ignored', None, _('show only ignored files')),
5071 5080 ('n', 'no-status', None, _('hide status prefix')),
5072 5081 ('C', 'copies', None, _('show source of copied files')),
5073 5082 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5074 5083 ('', 'rev', [], _('show difference from revision'), _('REV')),
5075 5084 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5076 5085 ] + walkopts + subrepoopts,
5077 5086 _('[OPTION]... [FILE]...'))
5078 5087 def status(ui, repo, *pats, **opts):
5079 5088 """show changed files in the working directory
5080 5089
5081 5090 Show status of files in the repository. If names are given, only
5082 5091 files that match are shown. Files that are clean or ignored or
5083 5092 the source of a copy/move operation, are not listed unless
5084 5093 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5085 5094 Unless options described with "show only ..." are given, the
5086 5095 options -mardu are used.
5087 5096
5088 5097 Option -q/--quiet hides untracked (unknown and ignored) files
5089 5098 unless explicitly requested with -u/--unknown or -i/--ignored.
5090 5099
5091 5100 .. note::
5092 5101 status may appear to disagree with diff if permissions have
5093 5102 changed or a merge has occurred. The standard diff format does
5094 5103 not report permission changes and diff only reports changes
5095 5104 relative to one merge parent.
5096 5105
5097 5106 If one revision is given, it is used as the base revision.
5098 5107 If two revisions are given, the differences between them are
5099 5108 shown. The --change option can also be used as a shortcut to list
5100 5109 the changed files of a revision from its first parent.
5101 5110
5102 5111 The codes used to show the status of files are::
5103 5112
5104 5113 M = modified
5105 5114 A = added
5106 5115 R = removed
5107 5116 C = clean
5108 5117 ! = missing (deleted by non-hg command, but still tracked)
5109 5118 ? = not tracked
5110 5119 I = ignored
5111 5120 = origin of the previous file listed as A (added)
5112 5121
5113 5122 .. container:: verbose
5114 5123
5115 5124 Examples:
5116 5125
5117 5126 - show changes in the working directory relative to a changeset:
5118 5127
5119 5128 hg status --rev 9353
5120 5129
5121 5130 - show all changes including copies in an existing changeset::
5122 5131
5123 5132 hg status --copies --change 9353
5124 5133
5125 5134 - get a NUL separated list of added files, suitable for xargs::
5126 5135
5127 5136 hg status -an0
5128 5137
5129 5138 Returns 0 on success.
5130 5139 """
5131 5140
5132 5141 revs = opts.get('rev')
5133 5142 change = opts.get('change')
5134 5143
5135 5144 if revs and change:
5136 5145 msg = _('cannot specify --rev and --change at the same time')
5137 5146 raise util.Abort(msg)
5138 5147 elif change:
5139 5148 node2 = repo.lookup(change)
5140 5149 node1 = repo[node2].p1().node()
5141 5150 else:
5142 5151 node1, node2 = scmutil.revpair(repo, revs)
5143 5152
5144 5153 cwd = (pats and repo.getcwd()) or ''
5145 5154 end = opts.get('print0') and '\0' or '\n'
5146 5155 copy = {}
5147 5156 states = 'modified added removed deleted unknown ignored clean'.split()
5148 5157 show = [k for k in states if opts.get(k)]
5149 5158 if opts.get('all'):
5150 5159 show += ui.quiet and (states[:4] + ['clean']) or states
5151 5160 if not show:
5152 5161 show = ui.quiet and states[:4] or states[:5]
5153 5162
5154 5163 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5155 5164 'ignored' in show, 'clean' in show, 'unknown' in show,
5156 5165 opts.get('subrepos'))
5157 5166 changestates = zip(states, 'MAR!?IC', stat)
5158 5167
5159 5168 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5160 5169 ctxn = repo[nullid]
5161 5170 ctx1 = repo[node1]
5162 5171 ctx2 = repo[node2]
5163 5172 added = stat[1]
5164 5173 if node2 is None:
5165 5174 added = stat[0] + stat[1] # merged?
5166 5175
5167 5176 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5168 5177 if k in added:
5169 5178 copy[k] = v
5170 5179 elif v in added:
5171 5180 copy[v] = k
5172 5181
5173 5182 for state, char, files in changestates:
5174 5183 if state in show:
5175 5184 format = "%s %%s%s" % (char, end)
5176 5185 if opts.get('no_status'):
5177 5186 format = "%%s%s" % end
5178 5187
5179 5188 for f in files:
5180 5189 ui.write(format % repo.pathto(f, cwd),
5181 5190 label='status.' + state)
5182 5191 if f in copy:
5183 5192 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5184 5193 label='status.copied')
5185 5194
5186 5195 @command('^summary|sum',
5187 5196 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5188 5197 def summary(ui, repo, **opts):
5189 5198 """summarize working directory state
5190 5199
5191 5200 This generates a brief summary of the working directory state,
5192 5201 including parents, branch, commit status, and available updates.
5193 5202
5194 5203 With the --remote option, this will check the default paths for
5195 5204 incoming and outgoing changes. This can be time-consuming.
5196 5205
5197 5206 Returns 0 on success.
5198 5207 """
5199 5208
5200 5209 ctx = repo[None]
5201 5210 parents = ctx.parents()
5202 5211 pnode = parents[0].node()
5203 5212 marks = []
5204 5213
5205 5214 for p in parents:
5206 5215 # label with log.changeset (instead of log.parent) since this
5207 5216 # shows a working directory parent *changeset*:
5208 5217 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5209 5218 label='log.changeset')
5210 5219 ui.write(' '.join(p.tags()), label='log.tag')
5211 5220 if p.bookmarks():
5212 5221 marks.extend(p.bookmarks())
5213 5222 if p.rev() == -1:
5214 5223 if not len(repo):
5215 5224 ui.write(_(' (empty repository)'))
5216 5225 else:
5217 5226 ui.write(_(' (no revision checked out)'))
5218 5227 ui.write('\n')
5219 5228 if p.description():
5220 5229 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5221 5230 label='log.summary')
5222 5231
5223 5232 branch = ctx.branch()
5224 5233 bheads = repo.branchheads(branch)
5225 5234 m = _('branch: %s\n') % branch
5226 5235 if branch != 'default':
5227 5236 ui.write(m, label='log.branch')
5228 5237 else:
5229 5238 ui.status(m, label='log.branch')
5230 5239
5231 5240 if marks:
5232 5241 current = repo._bookmarkcurrent
5233 5242 ui.write(_('bookmarks:'), label='log.bookmark')
5234 5243 if current is not None:
5235 5244 try:
5236 5245 marks.remove(current)
5237 5246 ui.write(' *' + current, label='bookmarks.current')
5238 5247 except ValueError:
5239 5248 # current bookmark not in parent ctx marks
5240 5249 pass
5241 5250 for m in marks:
5242 5251 ui.write(' ' + m, label='log.bookmark')
5243 5252 ui.write('\n', label='log.bookmark')
5244 5253
5245 5254 st = list(repo.status(unknown=True))[:6]
5246 5255
5247 5256 c = repo.dirstate.copies()
5248 5257 copied, renamed = [], []
5249 5258 for d, s in c.iteritems():
5250 5259 if s in st[2]:
5251 5260 st[2].remove(s)
5252 5261 renamed.append(d)
5253 5262 else:
5254 5263 copied.append(d)
5255 5264 if d in st[1]:
5256 5265 st[1].remove(d)
5257 5266 st.insert(3, renamed)
5258 5267 st.insert(4, copied)
5259 5268
5260 5269 ms = mergemod.mergestate(repo)
5261 5270 st.append([f for f in ms if ms[f] == 'u'])
5262 5271
5263 5272 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5264 5273 st.append(subs)
5265 5274
5266 5275 labels = [ui.label(_('%d modified'), 'status.modified'),
5267 5276 ui.label(_('%d added'), 'status.added'),
5268 5277 ui.label(_('%d removed'), 'status.removed'),
5269 5278 ui.label(_('%d renamed'), 'status.copied'),
5270 5279 ui.label(_('%d copied'), 'status.copied'),
5271 5280 ui.label(_('%d deleted'), 'status.deleted'),
5272 5281 ui.label(_('%d unknown'), 'status.unknown'),
5273 5282 ui.label(_('%d ignored'), 'status.ignored'),
5274 5283 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5275 5284 ui.label(_('%d subrepos'), 'status.modified')]
5276 5285 t = []
5277 5286 for s, l in zip(st, labels):
5278 5287 if s:
5279 5288 t.append(l % len(s))
5280 5289
5281 5290 t = ', '.join(t)
5282 5291 cleanworkdir = False
5283 5292
5284 5293 if len(parents) > 1:
5285 5294 t += _(' (merge)')
5286 5295 elif branch != parents[0].branch():
5287 5296 t += _(' (new branch)')
5288 5297 elif (parents[0].extra().get('close') and
5289 5298 pnode in repo.branchheads(branch, closed=True)):
5290 5299 t += _(' (head closed)')
5291 5300 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5292 5301 t += _(' (clean)')
5293 5302 cleanworkdir = True
5294 5303 elif pnode not in bheads:
5295 5304 t += _(' (new branch head)')
5296 5305
5297 5306 if cleanworkdir:
5298 5307 ui.status(_('commit: %s\n') % t.strip())
5299 5308 else:
5300 5309 ui.write(_('commit: %s\n') % t.strip())
5301 5310
5302 5311 # all ancestors of branch heads - all ancestors of parent = new csets
5303 5312 new = [0] * len(repo)
5304 5313 cl = repo.changelog
5305 5314 for a in [cl.rev(n) for n in bheads]:
5306 5315 new[a] = 1
5307 5316 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5308 5317 new[a] = 1
5309 5318 for a in [p.rev() for p in parents]:
5310 5319 if a >= 0:
5311 5320 new[a] = 0
5312 5321 for a in cl.ancestors(*[p.rev() for p in parents]):
5313 5322 new[a] = 0
5314 5323 new = sum(new)
5315 5324
5316 5325 if new == 0:
5317 5326 ui.status(_('update: (current)\n'))
5318 5327 elif pnode not in bheads:
5319 5328 ui.write(_('update: %d new changesets (update)\n') % new)
5320 5329 else:
5321 5330 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5322 5331 (new, len(bheads)))
5323 5332
5324 5333 if opts.get('remote'):
5325 5334 t = []
5326 5335 source, branches = hg.parseurl(ui.expandpath('default'))
5327 5336 other = hg.peer(repo, {}, source)
5328 5337 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5329 5338 ui.debug('comparing with %s\n' % util.hidepassword(source))
5330 5339 repo.ui.pushbuffer()
5331 5340 commoninc = discovery.findcommonincoming(repo, other)
5332 5341 _common, incoming, _rheads = commoninc
5333 5342 repo.ui.popbuffer()
5334 5343 if incoming:
5335 5344 t.append(_('1 or more incoming'))
5336 5345
5337 5346 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5338 5347 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5339 5348 if source != dest:
5340 5349 other = hg.peer(repo, {}, dest)
5341 5350 commoninc = None
5342 5351 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5343 5352 repo.ui.pushbuffer()
5344 5353 common, outheads = discovery.findcommonoutgoing(repo, other,
5345 5354 commoninc=commoninc)
5346 5355 repo.ui.popbuffer()
5347 5356 o = repo.changelog.findmissing(common=common, heads=outheads)
5348 5357 if o:
5349 5358 t.append(_('%d outgoing') % len(o))
5350 5359 if 'bookmarks' in other.listkeys('namespaces'):
5351 5360 lmarks = repo.listkeys('bookmarks')
5352 5361 rmarks = other.listkeys('bookmarks')
5353 5362 diff = set(rmarks) - set(lmarks)
5354 5363 if len(diff) > 0:
5355 5364 t.append(_('%d incoming bookmarks') % len(diff))
5356 5365 diff = set(lmarks) - set(rmarks)
5357 5366 if len(diff) > 0:
5358 5367 t.append(_('%d outgoing bookmarks') % len(diff))
5359 5368
5360 5369 if t:
5361 5370 ui.write(_('remote: %s\n') % (', '.join(t)))
5362 5371 else:
5363 5372 ui.status(_('remote: (synced)\n'))
5364 5373
5365 5374 @command('tag',
5366 5375 [('f', 'force', None, _('force tag')),
5367 5376 ('l', 'local', None, _('make the tag local')),
5368 5377 ('r', 'rev', '', _('revision to tag'), _('REV')),
5369 5378 ('', 'remove', None, _('remove a tag')),
5370 5379 # -l/--local is already there, commitopts cannot be used
5371 5380 ('e', 'edit', None, _('edit commit message')),
5372 5381 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5373 5382 ] + commitopts2,
5374 5383 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5375 5384 def tag(ui, repo, name1, *names, **opts):
5376 5385 """add one or more tags for the current or given revision
5377 5386
5378 5387 Name a particular revision using <name>.
5379 5388
5380 5389 Tags are used to name particular revisions of the repository and are
5381 5390 very useful to compare different revisions, to go back to significant
5382 5391 earlier versions or to mark branch points as releases, etc. Changing
5383 5392 an existing tag is normally disallowed; use -f/--force to override.
5384 5393
5385 5394 If no revision is given, the parent of the working directory is
5386 5395 used, or tip if no revision is checked out.
5387 5396
5388 5397 To facilitate version control, distribution, and merging of tags,
5389 5398 they are stored as a file named ".hgtags" which is managed similarly
5390 5399 to other project files and can be hand-edited if necessary. This
5391 5400 also means that tagging creates a new commit. The file
5392 5401 ".hg/localtags" is used for local tags (not shared among
5393 5402 repositories).
5394 5403
5395 5404 Tag commits are usually made at the head of a branch. If the parent
5396 5405 of the working directory is not a branch head, :hg:`tag` aborts; use
5397 5406 -f/--force to force the tag commit to be based on a non-head
5398 5407 changeset.
5399 5408
5400 5409 See :hg:`help dates` for a list of formats valid for -d/--date.
5401 5410
5402 5411 Since tag names have priority over branch names during revision
5403 5412 lookup, using an existing branch name as a tag name is discouraged.
5404 5413
5405 5414 Returns 0 on success.
5406 5415 """
5407 5416
5408 5417 rev_ = "."
5409 5418 names = [t.strip() for t in (name1,) + names]
5410 5419 if len(names) != len(set(names)):
5411 5420 raise util.Abort(_('tag names must be unique'))
5412 5421 for n in names:
5413 5422 if n in ['tip', '.', 'null']:
5414 5423 raise util.Abort(_("the name '%s' is reserved") % n)
5415 5424 if not n:
5416 5425 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5417 5426 if opts.get('rev') and opts.get('remove'):
5418 5427 raise util.Abort(_("--rev and --remove are incompatible"))
5419 5428 if opts.get('rev'):
5420 5429 rev_ = opts['rev']
5421 5430 message = opts.get('message')
5422 5431 if opts.get('remove'):
5423 5432 expectedtype = opts.get('local') and 'local' or 'global'
5424 5433 for n in names:
5425 5434 if not repo.tagtype(n):
5426 5435 raise util.Abort(_("tag '%s' does not exist") % n)
5427 5436 if repo.tagtype(n) != expectedtype:
5428 5437 if expectedtype == 'global':
5429 5438 raise util.Abort(_("tag '%s' is not a global tag") % n)
5430 5439 else:
5431 5440 raise util.Abort(_("tag '%s' is not a local tag") % n)
5432 5441 rev_ = nullid
5433 5442 if not message:
5434 5443 # we don't translate commit messages
5435 5444 message = 'Removed tag %s' % ', '.join(names)
5436 5445 elif not opts.get('force'):
5437 5446 for n in names:
5438 5447 if n in repo.tags():
5439 5448 raise util.Abort(_("tag '%s' already exists "
5440 5449 "(use -f to force)") % n)
5441 5450 if not opts.get('local'):
5442 5451 p1, p2 = repo.dirstate.parents()
5443 5452 if p2 != nullid:
5444 5453 raise util.Abort(_('uncommitted merge'))
5445 5454 bheads = repo.branchheads()
5446 5455 if not opts.get('force') and bheads and p1 not in bheads:
5447 5456 raise util.Abort(_('not at a branch head (use -f to force)'))
5448 5457 r = scmutil.revsingle(repo, rev_).node()
5449 5458
5450 5459 if not message:
5451 5460 # we don't translate commit messages
5452 5461 message = ('Added tag %s for changeset %s' %
5453 5462 (', '.join(names), short(r)))
5454 5463
5455 5464 date = opts.get('date')
5456 5465 if date:
5457 5466 date = util.parsedate(date)
5458 5467
5459 5468 if opts.get('edit'):
5460 5469 message = ui.edit(message, ui.username())
5461 5470
5462 5471 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5463 5472
5464 5473 @command('tags', [], '')
5465 5474 def tags(ui, repo):
5466 5475 """list repository tags
5467 5476
5468 5477 This lists both regular and local tags. When the -v/--verbose
5469 5478 switch is used, a third column "local" is printed for local tags.
5470 5479
5471 5480 Returns 0 on success.
5472 5481 """
5473 5482
5474 5483 hexfunc = ui.debugflag and hex or short
5475 5484 tagtype = ""
5476 5485
5477 5486 for t, n in reversed(repo.tagslist()):
5478 5487 if ui.quiet:
5479 5488 ui.write("%s\n" % t, label='tags.normal')
5480 5489 continue
5481 5490
5482 5491 hn = hexfunc(n)
5483 5492 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5484 5493 rev = ui.label(r, 'log.changeset')
5485 5494 spaces = " " * (30 - encoding.colwidth(t))
5486 5495
5487 5496 tag = ui.label(t, 'tags.normal')
5488 5497 if ui.verbose:
5489 5498 if repo.tagtype(t) == 'local':
5490 5499 tagtype = " local"
5491 5500 tag = ui.label(t, 'tags.local')
5492 5501 else:
5493 5502 tagtype = ""
5494 5503 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5495 5504
5496 5505 @command('tip',
5497 5506 [('p', 'patch', None, _('show patch')),
5498 5507 ('g', 'git', None, _('use git extended diff format')),
5499 5508 ] + templateopts,
5500 5509 _('[-p] [-g]'))
5501 5510 def tip(ui, repo, **opts):
5502 5511 """show the tip revision
5503 5512
5504 5513 The tip revision (usually just called the tip) is the changeset
5505 5514 most recently added to the repository (and therefore the most
5506 5515 recently changed head).
5507 5516
5508 5517 If you have just made a commit, that commit will be the tip. If
5509 5518 you have just pulled changes from another repository, the tip of
5510 5519 that repository becomes the current tip. The "tip" tag is special
5511 5520 and cannot be renamed or assigned to a different changeset.
5512 5521
5513 5522 Returns 0 on success.
5514 5523 """
5515 5524 displayer = cmdutil.show_changeset(ui, repo, opts)
5516 5525 displayer.show(repo[len(repo) - 1])
5517 5526 displayer.close()
5518 5527
5519 5528 @command('unbundle',
5520 5529 [('u', 'update', None,
5521 5530 _('update to new branch head if changesets were unbundled'))],
5522 5531 _('[-u] FILE...'))
5523 5532 def unbundle(ui, repo, fname1, *fnames, **opts):
5524 5533 """apply one or more changegroup files
5525 5534
5526 5535 Apply one or more compressed changegroup files generated by the
5527 5536 bundle command.
5528 5537
5529 5538 Returns 0 on success, 1 if an update has unresolved files.
5530 5539 """
5531 5540 fnames = (fname1,) + fnames
5532 5541
5533 5542 lock = repo.lock()
5534 5543 wc = repo['.']
5535 5544 try:
5536 5545 for fname in fnames:
5537 5546 f = url.open(ui, fname)
5538 5547 gen = changegroup.readbundle(f, fname)
5539 5548 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5540 5549 lock=lock)
5541 5550 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5542 5551 finally:
5543 5552 lock.release()
5544 5553 return postincoming(ui, repo, modheads, opts.get('update'), None)
5545 5554
5546 5555 @command('^update|up|checkout|co',
5547 5556 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5548 5557 ('c', 'check', None,
5549 5558 _('update across branches if no uncommitted changes')),
5550 5559 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5551 5560 ('r', 'rev', '', _('revision'), _('REV'))],
5552 5561 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5553 5562 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5554 5563 """update working directory (or switch revisions)
5555 5564
5556 5565 Update the repository's working directory to the specified
5557 5566 changeset. If no changeset is specified, update to the tip of the
5558 5567 current named branch.
5559 5568
5560 5569 If the changeset is not a descendant of the working directory's
5561 5570 parent, the update is aborted. With the -c/--check option, the
5562 5571 working directory is checked for uncommitted changes; if none are
5563 5572 found, the working directory is updated to the specified
5564 5573 changeset.
5565 5574
5566 5575 Update sets the working directory's parent revison to the specified
5567 5576 changeset (see :hg:`help parents`).
5568 5577
5569 5578 The following rules apply when the working directory contains
5570 5579 uncommitted changes:
5571 5580
5572 5581 1. If neither -c/--check nor -C/--clean is specified, and if
5573 5582 the requested changeset is an ancestor or descendant of
5574 5583 the working directory's parent, the uncommitted changes
5575 5584 are merged into the requested changeset and the merged
5576 5585 result is left uncommitted. If the requested changeset is
5577 5586 not an ancestor or descendant (that is, it is on another
5578 5587 branch), the update is aborted and the uncommitted changes
5579 5588 are preserved.
5580 5589
5581 5590 2. With the -c/--check option, the update is aborted and the
5582 5591 uncommitted changes are preserved.
5583 5592
5584 5593 3. With the -C/--clean option, uncommitted changes are discarded and
5585 5594 the working directory is updated to the requested changeset.
5586 5595
5587 5596 Use null as the changeset to remove the working directory (like
5588 5597 :hg:`clone -U`).
5589 5598
5590 5599 If you want to revert just one file to an older revision, use
5591 5600 :hg:`revert [-r REV] NAME`.
5592 5601
5593 5602 See :hg:`help dates` for a list of formats valid for -d/--date.
5594 5603
5595 5604 Returns 0 on success, 1 if there are unresolved files.
5596 5605 """
5597 5606 if rev and node:
5598 5607 raise util.Abort(_("please specify just one revision"))
5599 5608
5600 5609 if rev is None or rev == '':
5601 5610 rev = node
5602 5611
5603 5612 # if we defined a bookmark, we have to remember the original bookmark name
5604 5613 brev = rev
5605 5614 rev = scmutil.revsingle(repo, rev, rev).rev()
5606 5615
5607 5616 if check and clean:
5608 5617 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5609 5618
5610 5619 if check:
5611 5620 # we could use dirty() but we can ignore merge and branch trivia
5612 5621 c = repo[None]
5613 5622 if c.modified() or c.added() or c.removed():
5614 5623 raise util.Abort(_("uncommitted local changes"))
5615 5624
5616 5625 if date:
5617 5626 if rev is not None:
5618 5627 raise util.Abort(_("you can't specify a revision and a date"))
5619 5628 rev = cmdutil.finddate(ui, repo, date)
5620 5629
5621 5630 if clean or check:
5622 5631 ret = hg.clean(repo, rev)
5623 5632 else:
5624 5633 ret = hg.update(repo, rev)
5625 5634
5626 5635 if brev in repo._bookmarks:
5627 5636 bookmarks.setcurrent(repo, brev)
5628 5637
5629 5638 return ret
5630 5639
5631 5640 @command('verify', [])
5632 5641 def verify(ui, repo):
5633 5642 """verify the integrity of the repository
5634 5643
5635 5644 Verify the integrity of the current repository.
5636 5645
5637 5646 This will perform an extensive check of the repository's
5638 5647 integrity, validating the hashes and checksums of each entry in
5639 5648 the changelog, manifest, and tracked files, as well as the
5640 5649 integrity of their crosslinks and indices.
5641 5650
5642 5651 Returns 0 on success, 1 if errors are encountered.
5643 5652 """
5644 5653 return hg.verify(repo)
5645 5654
5646 5655 @command('version', [])
5647 5656 def version_(ui):
5648 5657 """output version and copyright information"""
5649 5658 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5650 5659 % util.version())
5651 5660 ui.status(_(
5652 5661 "(see http://mercurial.selenic.com for more information)\n"
5653 5662 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5654 5663 "This is free software; see the source for copying conditions. "
5655 5664 "There is NO\nwarranty; "
5656 5665 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5657 5666 ))
5658 5667
5659 5668 norepo = ("clone init version help debugcommands debugcomplete"
5660 5669 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5661 5670 " debugknown debuggetbundle debugbundle")
5662 5671 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5663 5672 " debugdata debugindex debugindexdot debugrevlog")
General Comments 0
You need to be logged in to leave comments. Login now