##// END OF EJS Templates
make all commands be repo-wide by default...
Benoit Boissinot -
r1568:1d7d0c07 default
parent child Browse files
Show More
@@ -1,2715 +1,2700 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from demandload import demandload
9 9 from node import *
10 10 from i18n import gettext as _
11 11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 12 demandload(globals(), "fancyopts ui hg util lock revlog")
13 13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
14 14 demandload(globals(), "errno socket version struct atexit sets bz2")
15 15
16 16 class UnknownCommand(Exception):
17 17 """Exception raised if command is not in the command table."""
18 18 class AmbiguousCommand(Exception):
19 19 """Exception raised if command shortcut matches more than one command."""
20 20
21 21 def filterfiles(filters, files):
22 22 l = [x for x in files if x in filters]
23 23
24 24 for t in filters:
25 25 if t and t[-1] != "/":
26 26 t += "/"
27 27 l += [x for x in files if x.startswith(t)]
28 28 return l
29 29
30 30 def relpath(repo, args):
31 31 cwd = repo.getcwd()
32 32 if cwd:
33 33 return [util.normpath(os.path.join(cwd, x)) for x in args]
34 34 return args
35 35
36 def matchpats(repo, cwd, pats=[], opts={}, head=''):
36 def matchpats(repo, pats=[], opts={}, head=''):
37 cwd = repo.getcwd()
38 if not pats and cwd:
39 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
40 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
41 cwd = ''
37 42 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
38 opts.get('exclude'), head)
43 opts.get('exclude'), head) + (cwd,)
39 44
40 45 def makewalk(repo, pats, opts, head=''):
41 cwd = repo.getcwd()
42 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
46 files, matchfn, anypats, cwd = matchpats(repo, pats, opts, head)
43 47 exact = dict(zip(files, files))
44 48 def walk():
45 49 for src, fn in repo.walk(files=files, match=matchfn):
46 50 yield src, fn, util.pathto(cwd, fn), fn in exact
47 51 return files, matchfn, walk()
48 52
49 53 def walk(repo, pats, opts, head=''):
50 54 files, matchfn, results = makewalk(repo, pats, opts, head)
51 55 for r in results:
52 56 yield r
53 57
54 def walkchangerevs(ui, repo, cwd, pats, opts):
58 def walkchangerevs(ui, repo, pats, opts):
55 59 '''Iterate over files and the revs they changed in.
56 60
57 61 Callers most commonly need to iterate backwards over the history
58 62 it is interested in. Doing so has awful (quadratic-looking)
59 63 performance, so we use iterators in a "windowed" way.
60 64
61 65 We walk a window of revisions in the desired order. Within the
62 66 window, we first walk forwards to gather data, then in the desired
63 67 order (usually backwards) to display it.
64 68
65 69 This function returns an (iterator, getchange) pair. The
66 70 getchange function returns the changelog entry for a numeric
67 71 revision. The iterator yields 3-tuples. They will be of one of
68 72 the following forms:
69 73
70 74 "window", incrementing, lastrev: stepping through a window,
71 75 positive if walking forwards through revs, last rev in the
72 76 sequence iterated over - use to reset state for the current window
73 77
74 78 "add", rev, fns: out-of-order traversal of the given file names
75 79 fns, which changed during revision rev - use to gather data for
76 80 possible display
77 81
78 82 "iter", rev, None: in-order traversal of the revs earlier iterated
79 83 over with "add" - use to display data'''
80 84
81 85 if repo.changelog.count() == 0:
82 86 return [], False
83 87
84 cwd = repo.getcwd()
85 if not pats and cwd:
86 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
87 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
88 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
89 pats, opts)
88 files, matchfn, anypats, cwd = matchpats(repo, pats, opts)
90 89 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
91 90 wanted = {}
92 91 slowpath = anypats
93 92 window = 300
94 93 fncache = {}
95 94
96 95 chcache = {}
97 96 def getchange(rev):
98 97 ch = chcache.get(rev)
99 98 if ch is None:
100 99 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
101 100 return ch
102 101
103 102 if not slowpath and not files:
104 103 # No files, no patterns. Display all revs.
105 104 wanted = dict(zip(revs, revs))
106 105 if not slowpath:
107 106 # Only files, no patterns. Check the history of each file.
108 107 def filerevgen(filelog):
109 108 for i in xrange(filelog.count() - 1, -1, -window):
110 109 revs = []
111 110 for j in xrange(max(0, i - window), i + 1):
112 111 revs.append(filelog.linkrev(filelog.node(j)))
113 112 revs.reverse()
114 113 for rev in revs:
115 114 yield rev
116 115
117 116 minrev, maxrev = min(revs), max(revs)
118 117 for file in files:
119 118 filelog = repo.file(file)
120 119 # A zero count may be a directory or deleted file, so
121 120 # try to find matching entries on the slow path.
122 121 if filelog.count() == 0:
123 122 slowpath = True
124 123 break
125 124 for rev in filerevgen(filelog):
126 125 if rev <= maxrev:
127 126 if rev < minrev:
128 127 break
129 128 fncache.setdefault(rev, [])
130 129 fncache[rev].append(file)
131 130 wanted[rev] = 1
132 131 if slowpath:
133 132 # The slow path checks files modified in every changeset.
134 133 def changerevgen():
135 134 for i in xrange(repo.changelog.count() - 1, -1, -window):
136 135 for j in xrange(max(0, i - window), i + 1):
137 136 yield j, getchange(j)[3]
138 137
139 138 for rev, changefiles in changerevgen():
140 139 matches = filter(matchfn, changefiles)
141 140 if matches:
142 141 fncache[rev] = matches
143 142 wanted[rev] = 1
144 143
145 144 def iterate():
146 145 for i in xrange(0, len(revs), window):
147 146 yield 'window', revs[0] < revs[-1], revs[-1]
148 147 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
149 148 if rev in wanted]
150 149 srevs = list(nrevs)
151 150 srevs.sort()
152 151 for rev in srevs:
153 152 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
154 153 yield 'add', rev, fns
155 154 for rev in nrevs:
156 155 yield 'iter', rev, None
157 156 return iterate(), getchange
158 157
159 158 revrangesep = ':'
160 159
161 160 def revrange(ui, repo, revs, revlog=None):
162 161 """Yield revision as strings from a list of revision specifications."""
163 162 if revlog is None:
164 163 revlog = repo.changelog
165 164 revcount = revlog.count()
166 165 def fix(val, defval):
167 166 if not val:
168 167 return defval
169 168 try:
170 169 num = int(val)
171 170 if str(num) != val:
172 171 raise ValueError
173 172 if num < 0: num += revcount
174 173 if num < 0: num = 0
175 174 elif num >= revcount:
176 175 raise ValueError
177 176 except ValueError:
178 177 try:
179 178 num = repo.changelog.rev(repo.lookup(val))
180 179 except KeyError:
181 180 try:
182 181 num = revlog.rev(revlog.lookup(val))
183 182 except KeyError:
184 183 raise util.Abort(_('invalid revision identifier %s'), val)
185 184 return num
186 185 seen = {}
187 186 for spec in revs:
188 187 if spec.find(revrangesep) >= 0:
189 188 start, end = spec.split(revrangesep, 1)
190 189 start = fix(start, 0)
191 190 end = fix(end, revcount - 1)
192 191 step = start > end and -1 or 1
193 192 for rev in xrange(start, end+step, step):
194 193 if rev in seen: continue
195 194 seen[rev] = 1
196 195 yield str(rev)
197 196 else:
198 197 rev = fix(spec, None)
199 198 if rev in seen: continue
200 199 seen[rev] = 1
201 200 yield str(rev)
202 201
203 202 def make_filename(repo, r, pat, node=None,
204 203 total=None, seqno=None, revwidth=None, pathname=None):
205 204 node_expander = {
206 205 'H': lambda: hex(node),
207 206 'R': lambda: str(r.rev(node)),
208 207 'h': lambda: short(node),
209 208 }
210 209 expander = {
211 210 '%': lambda: '%',
212 211 'b': lambda: os.path.basename(repo.root),
213 212 }
214 213
215 214 try:
216 215 if node:
217 216 expander.update(node_expander)
218 217 if node and revwidth is not None:
219 218 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
220 219 if total is not None:
221 220 expander['N'] = lambda: str(total)
222 221 if seqno is not None:
223 222 expander['n'] = lambda: str(seqno)
224 223 if total is not None and seqno is not None:
225 224 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
226 225 if pathname is not None:
227 226 expander['s'] = lambda: os.path.basename(pathname)
228 227 expander['d'] = lambda: os.path.dirname(pathname) or '.'
229 228 expander['p'] = lambda: pathname
230 229
231 230 newname = []
232 231 patlen = len(pat)
233 232 i = 0
234 233 while i < patlen:
235 234 c = pat[i]
236 235 if c == '%':
237 236 i += 1
238 237 c = pat[i]
239 238 c = expander[c]()
240 239 newname.append(c)
241 240 i += 1
242 241 return ''.join(newname)
243 242 except KeyError, inst:
244 243 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
245 244 inst.args[0])
246 245
247 246 def make_file(repo, r, pat, node=None,
248 247 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
249 248 if not pat or pat == '-':
250 249 return 'w' in mode and sys.stdout or sys.stdin
251 250 if hasattr(pat, 'write') and 'w' in mode:
252 251 return pat
253 252 if hasattr(pat, 'read') and 'r' in mode:
254 253 return pat
255 254 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
256 255 pathname),
257 256 mode)
258 257
259 258 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
260 259 changes=None, text=False):
261 260 if not changes:
262 261 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
263 262 else:
264 263 (c, a, d, u) = changes
265 264 if files:
266 265 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
267 266
268 267 if not c and not a and not d:
269 268 return
270 269
271 270 if node2:
272 271 change = repo.changelog.read(node2)
273 272 mmap2 = repo.manifest.read(change[0])
274 273 date2 = util.datestr(change[2])
275 274 def read(f):
276 275 return repo.file(f).read(mmap2[f])
277 276 else:
278 277 date2 = util.datestr()
279 278 if not node1:
280 279 node1 = repo.dirstate.parents()[0]
281 280 def read(f):
282 281 return repo.wfile(f).read()
283 282
284 283 if ui.quiet:
285 284 r = None
286 285 else:
287 286 hexfunc = ui.verbose and hex or short
288 287 r = [hexfunc(node) for node in [node1, node2] if node]
289 288
290 289 change = repo.changelog.read(node1)
291 290 mmap = repo.manifest.read(change[0])
292 291 date1 = util.datestr(change[2])
293 292
294 293 for f in c:
295 294 to = None
296 295 if f in mmap:
297 296 to = repo.file(f).read(mmap[f])
298 297 tn = read(f)
299 298 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
300 299 for f in a:
301 300 to = None
302 301 tn = read(f)
303 302 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
304 303 for f in d:
305 304 to = repo.file(f).read(mmap[f])
306 305 tn = None
307 306 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
308 307
309 308 def trimuser(ui, name, rev, revcache):
310 309 """trim the name of the user who committed a change"""
311 310 user = revcache.get(rev)
312 311 if user is None:
313 312 user = revcache[rev] = ui.shortuser(name)
314 313 return user
315 314
316 315 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
317 316 """show a single changeset or file revision"""
318 317 log = repo.changelog
319 318 if changenode is None:
320 319 changenode = log.node(rev)
321 320 elif not rev:
322 321 rev = log.rev(changenode)
323 322
324 323 if ui.quiet:
325 324 ui.write("%d:%s\n" % (rev, short(changenode)))
326 325 return
327 326
328 327 changes = log.read(changenode)
329 328 date = util.datestr(changes[2])
330 329
331 330 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
332 331 for p in log.parents(changenode)
333 332 if ui.debugflag or p != nullid]
334 333 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
335 334 parents = []
336 335
337 336 if ui.verbose:
338 337 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
339 338 else:
340 339 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
341 340
342 341 for tag in repo.nodetags(changenode):
343 342 ui.status(_("tag: %s\n") % tag)
344 343 for parent in parents:
345 344 ui.write(_("parent: %d:%s\n") % parent)
346 345
347 346 if brinfo and changenode in brinfo:
348 347 br = brinfo[changenode]
349 348 ui.write(_("branch: %s\n") % " ".join(br))
350 349
351 350 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
352 351 hex(changes[0])))
353 352 ui.status(_("user: %s\n") % changes[1])
354 353 ui.status(_("date: %s\n") % date)
355 354
356 355 if ui.debugflag:
357 356 files = repo.changes(log.parents(changenode)[0], changenode)
358 357 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
359 358 if value:
360 359 ui.note("%-12s %s\n" % (key, " ".join(value)))
361 360 else:
362 361 ui.note(_("files: %s\n") % " ".join(changes[3]))
363 362
364 363 description = changes[4].strip()
365 364 if description:
366 365 if ui.verbose:
367 366 ui.status(_("description:\n"))
368 367 ui.status(description)
369 368 ui.status("\n\n")
370 369 else:
371 370 ui.status(_("summary: %s\n") % description.splitlines()[0])
372 371 ui.status("\n")
373 372
374 373 def show_version(ui):
375 374 """output version and copyright information"""
376 375 ui.write(_("Mercurial Distributed SCM (version %s)\n")
377 376 % version.get_version())
378 377 ui.status(_(
379 378 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
380 379 "This is free software; see the source for copying conditions. "
381 380 "There is NO\nwarranty; "
382 381 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
383 382 ))
384 383
385 384 def help_(ui, cmd=None, with_version=False):
386 385 """show help for a given command or all commands"""
387 386 option_lists = []
388 387 if cmd and cmd != 'shortlist':
389 388 if with_version:
390 389 show_version(ui)
391 390 ui.write('\n')
392 391 aliases, i = find(cmd)
393 392 # synopsis
394 393 ui.write("%s\n\n" % i[2])
395 394
396 395 # description
397 396 doc = i[0].__doc__
398 397 if ui.quiet:
399 398 doc = doc.splitlines(0)[0]
400 399 ui.write("%s\n" % doc.rstrip())
401 400
402 401 if not ui.quiet:
403 402 # aliases
404 403 if len(aliases) > 1:
405 404 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
406 405
407 406 # options
408 407 if i[1]:
409 408 option_lists.append(("options", i[1]))
410 409
411 410 else:
412 411 # program name
413 412 if ui.verbose or with_version:
414 413 show_version(ui)
415 414 else:
416 415 ui.status(_("Mercurial Distributed SCM\n"))
417 416 ui.status('\n')
418 417
419 418 # list of commands
420 419 if cmd == "shortlist":
421 420 ui.status(_('basic commands (use "hg help" '
422 421 'for the full list or option "-v" for details):\n\n'))
423 422 elif ui.verbose:
424 423 ui.status(_('list of commands:\n\n'))
425 424 else:
426 425 ui.status(_('list of commands (use "hg help -v" '
427 426 'to show aliases and global options):\n\n'))
428 427
429 428 h = {}
430 429 cmds = {}
431 430 for c, e in table.items():
432 431 f = c.split("|")[0]
433 432 if cmd == "shortlist" and not f.startswith("^"):
434 433 continue
435 434 f = f.lstrip("^")
436 435 if not ui.debugflag and f.startswith("debug"):
437 436 continue
438 437 d = ""
439 438 if e[0].__doc__:
440 439 d = e[0].__doc__.splitlines(0)[0].rstrip()
441 440 h[f] = d
442 441 cmds[f]=c.lstrip("^")
443 442
444 443 fns = h.keys()
445 444 fns.sort()
446 445 m = max(map(len, fns))
447 446 for f in fns:
448 447 if ui.verbose:
449 448 commands = cmds[f].replace("|",", ")
450 449 ui.write(" %s:\n %s\n"%(commands,h[f]))
451 450 else:
452 451 ui.write(' %-*s %s\n' % (m, f, h[f]))
453 452
454 453 # global options
455 454 if ui.verbose:
456 455 option_lists.append(("global options", globalopts))
457 456
458 457 # list all option lists
459 458 opt_output = []
460 459 for title, options in option_lists:
461 460 opt_output.append(("\n%s:\n" % title, None))
462 461 for shortopt, longopt, default, desc in options:
463 462 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
464 463 longopt and " --%s" % longopt),
465 464 "%s%s" % (desc,
466 465 default and _(" (default: %s)") % default
467 466 or "")))
468 467
469 468 if opt_output:
470 469 opts_len = max([len(line[0]) for line in opt_output if line[1]])
471 470 for first, second in opt_output:
472 471 if second:
473 472 ui.write(" %-*s %s\n" % (opts_len, first, second))
474 473 else:
475 474 ui.write("%s\n" % first)
476 475
477 476 # Commands start here, listed alphabetically
478 477
479 478 def add(ui, repo, *pats, **opts):
480 479 """add the specified files on the next commit
481 480
482 481 Schedule files to be version controlled and added to the repository.
483 482
484 483 The files will be added to the repository at the next commit.
485 484
486 If no names are given, add all files in the current directory and
487 its subdirectories.
485 If no names are given, add all files in the repository.
488 486 """
489 487
490 488 names = []
491 489 for src, abs, rel, exact in walk(repo, pats, opts):
492 490 if exact:
493 491 if ui.verbose: ui.status(_('adding %s\n') % rel)
494 492 names.append(abs)
495 493 elif repo.dirstate.state(abs) == '?':
496 494 ui.status(_('adding %s\n') % rel)
497 495 names.append(abs)
498 496 repo.add(names)
499 497
500 498 def addremove(ui, repo, *pats, **opts):
501 499 """add all new files, delete all missing files
502 500
503 501 Add all new files and remove all missing files from the repository.
504 502
505 503 New files are ignored if they match any of the patterns in .hgignore. As
506 504 with add, these changes take effect at the next commit.
507 505 """
508 506 add, remove = [], []
509 507 for src, abs, rel, exact in walk(repo, pats, opts):
510 508 if src == 'f' and repo.dirstate.state(abs) == '?':
511 509 add.append(abs)
512 510 if ui.verbose or not exact:
513 511 ui.status(_('adding %s\n') % rel)
514 512 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
515 513 remove.append(abs)
516 514 if ui.verbose or not exact:
517 515 ui.status(_('removing %s\n') % rel)
518 516 repo.add(add)
519 517 repo.remove(remove)
520 518
521 519 def annotate(ui, repo, *pats, **opts):
522 520 """show changeset information per file line
523 521
524 522 List changes in files, showing the revision id responsible for each line
525 523
526 524 This command is useful to discover who did a change or when a change took
527 525 place.
528 526
529 527 Without the -a option, annotate will avoid processing files it
530 528 detects as binary. With -a, annotate will generate an annotation
531 529 anyway, probably with undesirable results.
532 530 """
533 531 def getnode(rev):
534 532 return short(repo.changelog.node(rev))
535 533
536 534 ucache = {}
537 535 def getname(rev):
538 536 cl = repo.changelog.read(repo.changelog.node(rev))
539 537 return trimuser(ui, cl[1], rev, ucache)
540 538
541 539 dcache = {}
542 540 def getdate(rev):
543 541 datestr = dcache.get(rev)
544 542 if datestr is None:
545 543 cl = repo.changelog.read(repo.changelog.node(rev))
546 544 datestr = dcache[rev] = util.datestr(cl[2])
547 545 return datestr
548 546
549 547 if not pats:
550 548 raise util.Abort(_('at least one file name or pattern required'))
551 549
552 550 opmap = [['user', getname], ['number', str], ['changeset', getnode],
553 551 ['date', getdate]]
554 552 if not opts['user'] and not opts['changeset'] and not opts['date']:
555 553 opts['number'] = 1
556 554
557 555 if opts['rev']:
558 556 node = repo.changelog.lookup(opts['rev'])
559 557 else:
560 558 node = repo.dirstate.parents()[0]
561 559 change = repo.changelog.read(node)
562 560 mmap = repo.manifest.read(change[0])
563 561
564 562 for src, abs, rel, exact in walk(repo, pats, opts):
565 563 if abs not in mmap:
566 564 ui.warn(_("warning: %s is not in the repository!\n") % rel)
567 565 continue
568 566
569 567 f = repo.file(abs)
570 568 if not opts['text'] and util.binary(f.read(mmap[abs])):
571 569 ui.write(_("%s: binary file\n") % rel)
572 570 continue
573 571
574 572 lines = f.annotate(mmap[abs])
575 573 pieces = []
576 574
577 575 for o, f in opmap:
578 576 if opts[o]:
579 577 l = [f(n) for n, dummy in lines]
580 578 if l:
581 579 m = max(map(len, l))
582 580 pieces.append(["%*s" % (m, x) for x in l])
583 581
584 582 if pieces:
585 583 for p, l in zip(zip(*pieces), lines):
586 584 ui.write("%s: %s" % (" ".join(p), l[1]))
587 585
588 586 def bundle(ui, repo, fname, dest="default-push", **opts):
589 587 """create a changegroup file
590 588
591 589 Generate a compressed changegroup file collecting all changesets
592 590 not found in the other repository.
593 591
594 592 This file can then be transferred using conventional means and
595 593 applied to another repository with the unbundle command. This is
596 594 useful when native push and pull are not available or when
597 595 exporting an entire repository is undesirable. The standard file
598 596 extension is ".hg".
599 597
600 598 Unlike import/export, this exactly preserves all changeset
601 599 contents including permissions, rename data, and revision history.
602 600 """
603 601 f = open(fname, "wb")
604 602 dest = ui.expandpath(dest, repo.root)
605 603 other = hg.repository(ui, dest)
606 604 o = repo.findoutgoing(other)
607 605 cg = repo.changegroup(o)
608 606
609 607 try:
610 608 f.write("HG10")
611 609 z = bz2.BZ2Compressor(9)
612 610 while 1:
613 611 chunk = cg.read(4096)
614 612 if not chunk:
615 613 break
616 614 f.write(z.compress(chunk))
617 615 f.write(z.flush())
618 616 except:
619 617 os.unlink(fname)
620 618 raise
621 619
622 620 def cat(ui, repo, file1, *pats, **opts):
623 621 """output the latest or given revisions of files
624 622
625 623 Print the specified files as they were at the given revision.
626 624 If no revision is given then the tip is used.
627 625
628 626 Output may be to a file, in which case the name of the file is
629 627 given using a format string. The formatting rules are the same as
630 628 for the export command, with the following additions:
631 629
632 630 %s basename of file being printed
633 631 %d dirname of file being printed, or '.' if in repo root
634 632 %p root-relative path name of file being printed
635 633 """
636 634 mf = {}
637 635 rev = opts['rev']
638 636 if rev:
639 637 change = repo.changelog.read(repo.lookup(rev))
640 638 mf = repo.manifest.read(change[0])
641 639 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
642 640 r = repo.file(abs)
643 641 if rev:
644 642 try:
645 643 n = mf[abs]
646 644 except (hg.RepoError, KeyError):
647 645 try:
648 646 n = r.lookup(rev)
649 647 except KeyError, inst:
650 648 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
651 649 else:
652 650 n = r.tip()
653 651 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
654 652 fp.write(r.read(n))
655 653
656 654 def clone(ui, source, dest=None, **opts):
657 655 """make a copy of an existing repository
658 656
659 657 Create a copy of an existing repository in a new directory.
660 658
661 659 If no destination directory name is specified, it defaults to the
662 660 basename of the source.
663 661
664 662 The location of the source is added to the new repository's
665 663 .hg/hgrc file, as the default to be used for future pulls.
666 664
667 665 For efficiency, hardlinks are used for cloning whenever the source
668 666 and destination are on the same filesystem. Some filesystems,
669 667 such as AFS, implement hardlinking incorrectly, but do not report
670 668 errors. In these cases, use the --pull option to avoid
671 669 hardlinking.
672 670 """
673 671 if dest is None:
674 672 dest = os.path.basename(os.path.normpath(source))
675 673
676 674 if os.path.exists(dest):
677 675 raise util.Abort(_("destination '%s' already exists"), dest)
678 676
679 677 dest = os.path.realpath(dest)
680 678
681 679 class Dircleanup(object):
682 680 def __init__(self, dir_):
683 681 self.rmtree = shutil.rmtree
684 682 self.dir_ = dir_
685 683 os.mkdir(dir_)
686 684 def close(self):
687 685 self.dir_ = None
688 686 def __del__(self):
689 687 if self.dir_:
690 688 self.rmtree(self.dir_, True)
691 689
692 690 if opts['ssh']:
693 691 ui.setconfig("ui", "ssh", opts['ssh'])
694 692 if opts['remotecmd']:
695 693 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
696 694
697 695 if not os.path.exists(source):
698 696 source = ui.expandpath(source)
699 697
700 698 d = Dircleanup(dest)
701 699 abspath = source
702 700 other = hg.repository(ui, source)
703 701
704 702 copy = False
705 703 if other.dev() != -1:
706 704 abspath = os.path.abspath(source)
707 705 if not opts['pull'] and not opts['rev']:
708 706 copy = True
709 707
710 708 if copy:
711 709 try:
712 710 # we use a lock here because if we race with commit, we
713 711 # can end up with extra data in the cloned revlogs that's
714 712 # not pointed to by changesets, thus causing verify to
715 713 # fail
716 714 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
717 715 except OSError:
718 716 copy = False
719 717
720 718 if copy:
721 719 # we lock here to avoid premature writing to the target
722 720 os.mkdir(os.path.join(dest, ".hg"))
723 721 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
724 722
725 723 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
726 724 for f in files.split():
727 725 src = os.path.join(source, ".hg", f)
728 726 dst = os.path.join(dest, ".hg", f)
729 727 try:
730 728 util.copyfiles(src, dst)
731 729 except OSError, inst:
732 730 if inst.errno != errno.ENOENT: raise
733 731
734 732 repo = hg.repository(ui, dest)
735 733
736 734 else:
737 735 revs = None
738 736 if opts['rev']:
739 737 if not other.local():
740 738 raise util.Abort("clone -r not supported yet for remote repositories.")
741 739 else:
742 740 revs = [other.lookup(rev) for rev in opts['rev']]
743 741 repo = hg.repository(ui, dest, create=1)
744 742 repo.pull(other, heads = revs)
745 743
746 744 f = repo.opener("hgrc", "w", text=True)
747 745 f.write("[paths]\n")
748 746 f.write("default = %s\n" % abspath)
749 747 f.close()
750 748
751 749 if not opts['noupdate']:
752 750 update(ui, repo)
753 751
754 752 d.close()
755 753
756 754 def commit(ui, repo, *pats, **opts):
757 755 """commit the specified files or all outstanding changes
758 756
759 757 Commit changes to the given files into the repository.
760 758
761 759 If a list of files is omitted, all changes reported by "hg status"
762 from the root of the repository will be commited.
760 will be commited.
763 761
764 762 The HGEDITOR or EDITOR environment variables are used to start an
765 763 editor to add a commit comment.
766 764 """
767 765 message = opts['message']
768 766 logfile = opts['logfile']
769 767
770 768 if message and logfile:
771 769 raise util.Abort(_('options --message and --logfile are mutually '
772 770 'exclusive'))
773 771 if not message and logfile:
774 772 try:
775 773 if logfile == '-':
776 774 message = sys.stdin.read()
777 775 else:
778 776 message = open(logfile).read()
779 777 except IOError, inst:
780 778 raise util.Abort(_("can't read commit message '%s': %s") %
781 779 (logfile, inst.strerror))
782 780
783 781 if opts['addremove']:
784 782 addremove(ui, repo, *pats, **opts)
785 cwd = repo.getcwd()
786 if not pats and cwd:
787 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
788 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
789 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
790 pats, opts)
783 fns, match, anypats, cwd = matchpats(repo, pats, opts)
791 784 if pats:
792 785 c, a, d, u = repo.changes(files=fns, match=match)
793 786 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
794 787 else:
795 788 files = []
796 789 try:
797 790 repo.commit(files, message, opts['user'], opts['date'], match)
798 791 except ValueError, inst:
799 792 raise util.Abort(str(inst))
800 793
801 794 def docopy(ui, repo, pats, opts):
802 795 cwd = repo.getcwd()
803 796 errors = 0
804 797 copied = []
805 798 targets = {}
806 799
807 800 def okaytocopy(abs, rel, exact):
808 801 reasons = {'?': _('is not managed'),
809 802 'a': _('has been marked for add')}
810 803 reason = reasons.get(repo.dirstate.state(abs))
811 804 if reason:
812 805 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
813 806 else:
814 807 return True
815 808
816 809 def copy(abssrc, relsrc, target, exact):
817 810 abstarget = util.canonpath(repo.root, cwd, target)
818 811 reltarget = util.pathto(cwd, abstarget)
819 812 prevsrc = targets.get(abstarget)
820 813 if prevsrc is not None:
821 814 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
822 815 (reltarget, abssrc, prevsrc))
823 816 return
824 817 if (not opts['after'] and os.path.exists(reltarget) or
825 818 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
826 819 if not opts['force']:
827 820 ui.warn(_('%s: not overwriting - file exists\n') %
828 821 reltarget)
829 822 return
830 823 if not opts['after']:
831 824 os.unlink(reltarget)
832 825 if opts['after']:
833 826 if not os.path.exists(reltarget):
834 827 return
835 828 else:
836 829 targetdir = os.path.dirname(reltarget) or '.'
837 830 if not os.path.isdir(targetdir):
838 831 os.makedirs(targetdir)
839 832 try:
840 833 shutil.copyfile(relsrc, reltarget)
841 834 shutil.copymode(relsrc, reltarget)
842 835 except shutil.Error, inst:
843 836 raise util.Abort(str(inst))
844 837 except IOError, inst:
845 838 if inst.errno == errno.ENOENT:
846 839 ui.warn(_('%s: deleted in working copy\n') % relsrc)
847 840 else:
848 841 ui.warn(_('%s: cannot copy - %s\n') %
849 842 (relsrc, inst.strerror))
850 843 errors += 1
851 844 return
852 845 if ui.verbose or not exact:
853 846 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
854 847 targets[abstarget] = abssrc
855 848 repo.copy(abssrc, abstarget)
856 849 copied.append((abssrc, relsrc, exact))
857 850
858 851 def targetpathfn(pat, dest, srcs):
859 852 if os.path.isdir(pat):
860 853 if pat.endswith(os.sep):
861 854 pat = pat[:-len(os.sep)]
862 855 if destdirexists:
863 856 striplen = len(os.path.split(pat)[0])
864 857 else:
865 858 striplen = len(pat)
866 859 if striplen:
867 860 striplen += len(os.sep)
868 861 res = lambda p: os.path.join(dest, p[striplen:])
869 862 elif destdirexists:
870 863 res = lambda p: os.path.join(dest, os.path.basename(p))
871 864 else:
872 865 res = lambda p: dest
873 866 return res
874 867
875 868 def targetpathafterfn(pat, dest, srcs):
876 869 if util.patkind(pat, None)[0]:
877 870 # a mercurial pattern
878 871 res = lambda p: os.path.join(dest, os.path.basename(p))
879 872 elif len(util.canonpath(repo.root, cwd, pat)) < len(srcs[0][0]):
880 873 # A directory. Either the target path contains the last
881 874 # component of the source path or it does not.
882 875 def evalpath(striplen):
883 876 score = 0
884 877 for s in srcs:
885 878 t = os.path.join(dest, s[1][striplen:])
886 879 if os.path.exists(t):
887 880 score += 1
888 881 return score
889 882
890 883 if pat.endswith(os.sep):
891 884 pat = pat[:-len(os.sep)]
892 885 striplen = len(pat) + len(os.sep)
893 886 if os.path.isdir(os.path.join(dest, os.path.split(pat)[1])):
894 887 score = evalpath(striplen)
895 888 striplen1 = len(os.path.split(pat)[0])
896 889 if striplen1:
897 890 striplen1 += len(os.sep)
898 891 if evalpath(striplen1) > score:
899 892 striplen = striplen1
900 893 res = lambda p: os.path.join(dest, p[striplen:])
901 894 else:
902 895 # a file
903 896 if destdirexists:
904 897 res = lambda p: os.path.join(dest, os.path.basename(p))
905 898 else:
906 899 res = lambda p: dest
907 900 return res
908 901
909 902
910 903 pats = list(pats)
911 904 if not pats:
912 905 raise util.Abort(_('no source or destination specified'))
913 906 if len(pats) == 1:
914 907 raise util.Abort(_('no destination specified'))
915 908 dest = pats.pop()
916 909 destdirexists = os.path.isdir(dest)
917 910 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
918 911 raise util.Abort(_('with multiple sources, destination must be an '
919 912 'existing directory'))
920 913 if opts['after']:
921 914 tfn = targetpathafterfn
922 915 else:
923 916 tfn = targetpathfn
924 917 copylist = []
925 918 for pat in pats:
926 919 srcs = []
927 920 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
928 921 if okaytocopy(abssrc, relsrc, exact):
929 922 srcs.append((abssrc, relsrc, exact))
930 923 if not srcs:
931 924 continue
932 925 copylist.append((tfn(pat, dest, srcs), srcs))
933 926 if not copylist:
934 927 raise util.Abort(_('no files to copy'))
935 928
936 929 for targetpath, srcs in copylist:
937 930 for abssrc, relsrc, exact in srcs:
938 931 copy(abssrc, relsrc, targetpath(relsrc), exact)
939 932
940 933 if errors:
941 934 ui.warn(_('(consider using --after)\n'))
942 935 return errors, copied
943 936
944 937 def copy(ui, repo, *pats, **opts):
945 938 """mark files as copied for the next commit
946 939
947 940 Mark dest as having copies of source files. If dest is a
948 941 directory, copies are put in that directory. If dest is a file,
949 942 there can only be one source.
950 943
951 944 By default, this command copies the contents of files as they
952 945 stand in the working directory. If invoked with --after, the
953 946 operation is recorded, but no copying is performed.
954 947
955 948 This command takes effect in the next commit.
956 949
957 950 NOTE: This command should be treated as experimental. While it
958 951 should properly record copied files, this information is not yet
959 952 fully used by merge, nor fully reported by log.
960 953 """
961 954 errs, copied = docopy(ui, repo, pats, opts)
962 955 return errs
963 956
964 957 def debugancestor(ui, index, rev1, rev2):
965 958 """find the ancestor revision of two revisions in a given index"""
966 959 r = revlog.revlog(util.opener(os.getcwd()), index, "")
967 960 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
968 961 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
969 962
970 963 def debugcheckstate(ui, repo):
971 964 """validate the correctness of the current dirstate"""
972 965 parent1, parent2 = repo.dirstate.parents()
973 966 repo.dirstate.read()
974 967 dc = repo.dirstate.map
975 968 keys = dc.keys()
976 969 keys.sort()
977 970 m1n = repo.changelog.read(parent1)[0]
978 971 m2n = repo.changelog.read(parent2)[0]
979 972 m1 = repo.manifest.read(m1n)
980 973 m2 = repo.manifest.read(m2n)
981 974 errors = 0
982 975 for f in dc:
983 976 state = repo.dirstate.state(f)
984 977 if state in "nr" and f not in m1:
985 978 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
986 979 errors += 1
987 980 if state in "a" and f in m1:
988 981 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
989 982 errors += 1
990 983 if state in "m" and f not in m1 and f not in m2:
991 984 ui.warn(_("%s in state %s, but not in either manifest\n") %
992 985 (f, state))
993 986 errors += 1
994 987 for f in m1:
995 988 state = repo.dirstate.state(f)
996 989 if state not in "nrm":
997 990 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
998 991 errors += 1
999 992 if errors:
1000 993 raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
1001 994
1002 995 def debugconfig(ui):
1003 996 """show combined config settings from all hgrc files"""
1004 997 try:
1005 998 repo = hg.repository(ui)
1006 999 except hg.RepoError:
1007 1000 pass
1008 1001 for section, name, value in ui.walkconfig():
1009 1002 ui.write('%s.%s=%s\n' % (section, name, value))
1010 1003
1011 1004 def debugsetparents(ui, repo, rev1, rev2=None):
1012 1005 """manually set the parents of the current working directory
1013 1006
1014 1007 This is useful for writing repository conversion tools, but should
1015 1008 be used with care.
1016 1009 """
1017 1010
1018 1011 if not rev2:
1019 1012 rev2 = hex(nullid)
1020 1013
1021 1014 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1022 1015
1023 1016 def debugstate(ui, repo):
1024 1017 """show the contents of the current dirstate"""
1025 1018 repo.dirstate.read()
1026 1019 dc = repo.dirstate.map
1027 1020 keys = dc.keys()
1028 1021 keys.sort()
1029 1022 for file_ in keys:
1030 1023 ui.write("%c %3o %10d %s %s\n"
1031 1024 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1032 1025 time.strftime("%x %X",
1033 1026 time.localtime(dc[file_][3])), file_))
1034 1027 for f in repo.dirstate.copies:
1035 1028 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1036 1029
1037 1030 def debugdata(ui, file_, rev):
1038 1031 """dump the contents of an data file revision"""
1039 1032 r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
1040 1033 try:
1041 1034 ui.write(r.revision(r.lookup(rev)))
1042 1035 except KeyError:
1043 1036 raise util.Abort(_('invalid revision identifier %s'), rev)
1044 1037
1045 1038 def debugindex(ui, file_):
1046 1039 """dump the contents of an index file"""
1047 1040 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1048 1041 ui.write(" rev offset length base linkrev" +
1049 1042 " nodeid p1 p2\n")
1050 1043 for i in range(r.count()):
1051 1044 e = r.index[i]
1052 1045 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1053 1046 i, e[0], e[1], e[2], e[3],
1054 1047 short(e[6]), short(e[4]), short(e[5])))
1055 1048
1056 1049 def debugindexdot(ui, file_):
1057 1050 """dump an index DAG as a .dot file"""
1058 1051 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1059 1052 ui.write("digraph G {\n")
1060 1053 for i in range(r.count()):
1061 1054 e = r.index[i]
1062 1055 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1063 1056 if e[5] != nullid:
1064 1057 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1065 1058 ui.write("}\n")
1066 1059
1067 1060 def debugrename(ui, repo, file, rev=None):
1068 1061 """dump rename information"""
1069 1062 r = repo.file(relpath(repo, [file])[0])
1070 1063 if rev:
1071 1064 try:
1072 1065 # assume all revision numbers are for changesets
1073 1066 n = repo.lookup(rev)
1074 1067 change = repo.changelog.read(n)
1075 1068 m = repo.manifest.read(change[0])
1076 1069 n = m[relpath(repo, [file])[0]]
1077 1070 except (hg.RepoError, KeyError):
1078 1071 n = r.lookup(rev)
1079 1072 else:
1080 1073 n = r.tip()
1081 1074 m = r.renamed(n)
1082 1075 if m:
1083 1076 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1084 1077 else:
1085 1078 ui.write(_("not renamed\n"))
1086 1079
1087 1080 def debugwalk(ui, repo, *pats, **opts):
1088 1081 """show how files match on given patterns"""
1089 1082 items = list(walk(repo, pats, opts))
1090 1083 if not items:
1091 1084 return
1092 1085 fmt = '%%s %%-%ds %%-%ds %%s' % (
1093 1086 max([len(abs) for (src, abs, rel, exact) in items]),
1094 1087 max([len(rel) for (src, abs, rel, exact) in items]))
1095 1088 for src, abs, rel, exact in items:
1096 1089 line = fmt % (src, abs, rel, exact and 'exact' or '')
1097 1090 ui.write("%s\n" % line.rstrip())
1098 1091
1099 1092 def diff(ui, repo, *pats, **opts):
1100 """diff working directory (or selected files)
1093 """diff repository (or selected files)
1101 1094
1102 1095 Show differences between revisions for the specified files.
1103 1096
1104 1097 Differences between files are shown using the unified diff format.
1105 1098
1106 1099 When two revision arguments are given, then changes are shown
1107 1100 between those revisions. If only one revision is specified then
1108 1101 that revision is compared to the working directory, and, when no
1109 1102 revisions are specified, the working directory files are compared
1110 1103 to its parent.
1111 1104
1112 1105 Without the -a option, diff will avoid generating diffs of files
1113 1106 it detects as binary. With -a, diff will generate a diff anyway,
1114 1107 probably with undesirable results.
1115 1108 """
1116 1109 node1, node2 = None, None
1117 1110 revs = [repo.lookup(x) for x in opts['rev']]
1118 1111
1119 1112 if len(revs) > 0:
1120 1113 node1 = revs[0]
1121 1114 if len(revs) > 1:
1122 1115 node2 = revs[1]
1123 1116 if len(revs) > 2:
1124 1117 raise util.Abort(_("too many revisions to diff"))
1125 1118
1126 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1119 fns, matchfn, anypats, cwd = matchpats(repo, pats, opts)
1127 1120
1128 1121 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1129 1122 text=opts['text'])
1130 1123
1131 1124 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1132 1125 node = repo.lookup(changeset)
1133 1126 prev, other = repo.changelog.parents(node)
1134 1127 change = repo.changelog.read(node)
1135 1128
1136 1129 fp = make_file(repo, repo.changelog, opts['output'],
1137 1130 node=node, total=total, seqno=seqno,
1138 1131 revwidth=revwidth)
1139 1132 if fp != sys.stdout:
1140 1133 ui.note("%s\n" % fp.name)
1141 1134
1142 1135 fp.write("# HG changeset patch\n")
1143 1136 fp.write("# User %s\n" % change[1])
1144 1137 fp.write("# Node ID %s\n" % hex(node))
1145 1138 fp.write("# Parent %s\n" % hex(prev))
1146 1139 if other != nullid:
1147 1140 fp.write("# Parent %s\n" % hex(other))
1148 1141 fp.write(change[4].rstrip())
1149 1142 fp.write("\n\n")
1150 1143
1151 1144 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1152 1145 if fp != sys.stdout:
1153 1146 fp.close()
1154 1147
1155 1148 def export(ui, repo, *changesets, **opts):
1156 1149 """dump the header and diffs for one or more changesets
1157 1150
1158 1151 Print the changeset header and diffs for one or more revisions.
1159 1152
1160 1153 The information shown in the changeset header is: author,
1161 1154 changeset hash, parent and commit comment.
1162 1155
1163 1156 Output may be to a file, in which case the name of the file is
1164 1157 given using a format string. The formatting rules are as follows:
1165 1158
1166 1159 %% literal "%" character
1167 1160 %H changeset hash (40 bytes of hexadecimal)
1168 1161 %N number of patches being generated
1169 1162 %R changeset revision number
1170 1163 %b basename of the exporting repository
1171 1164 %h short-form changeset hash (12 bytes of hexadecimal)
1172 1165 %n zero-padded sequence number, starting at 1
1173 1166 %r zero-padded changeset revision number
1174 1167
1175 1168 Without the -a option, export will avoid generating diffs of files
1176 1169 it detects as binary. With -a, export will generate a diff anyway,
1177 1170 probably with undesirable results.
1178 1171 """
1179 1172 if not changesets:
1180 1173 raise util.Abort(_("export requires at least one changeset"))
1181 1174 seqno = 0
1182 1175 revs = list(revrange(ui, repo, changesets))
1183 1176 total = len(revs)
1184 1177 revwidth = max(map(len, revs))
1185 1178 ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
1186 1179 for cset in revs:
1187 1180 seqno += 1
1188 1181 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1189 1182
1190 1183 def forget(ui, repo, *pats, **opts):
1191 1184 """don't add the specified files on the next commit
1192 1185
1193 1186 Undo an 'hg add' scheduled for the next commit.
1194 1187 """
1195 1188 forget = []
1196 1189 for src, abs, rel, exact in walk(repo, pats, opts):
1197 1190 if repo.dirstate.state(abs) == 'a':
1198 1191 forget.append(abs)
1199 1192 if ui.verbose or not exact:
1200 1193 ui.status(_('forgetting %s\n') % rel)
1201 1194 repo.forget(forget)
1202 1195
1203 1196 def grep(ui, repo, pattern, *pats, **opts):
1204 1197 """search for a pattern in specified files and revisions
1205 1198
1206 1199 Search revisions of files for a regular expression.
1207 1200
1208 1201 This command behaves differently than Unix grep. It only accepts
1209 1202 Python/Perl regexps. It searches repository history, not the
1210 1203 working directory. It always prints the revision number in which
1211 1204 a match appears.
1212 1205
1213 1206 By default, grep only prints output for the first revision of a
1214 1207 file in which it finds a match. To get it to print every revision
1215 1208 that contains a change in match status ("-" for a match that
1216 1209 becomes a non-match, or "+" for a non-match that becomes a match),
1217 1210 use the --all flag.
1218 1211 """
1219 1212 reflags = 0
1220 1213 if opts['ignore_case']:
1221 1214 reflags |= re.I
1222 1215 regexp = re.compile(pattern, reflags)
1223 1216 sep, eol = ':', '\n'
1224 1217 if opts['print0']:
1225 1218 sep = eol = '\0'
1226 1219
1227 1220 fcache = {}
1228 1221 def getfile(fn):
1229 1222 if fn not in fcache:
1230 1223 fcache[fn] = repo.file(fn)
1231 1224 return fcache[fn]
1232 1225
1233 1226 def matchlines(body):
1234 1227 begin = 0
1235 1228 linenum = 0
1236 1229 while True:
1237 1230 match = regexp.search(body, begin)
1238 1231 if not match:
1239 1232 break
1240 1233 mstart, mend = match.span()
1241 1234 linenum += body.count('\n', begin, mstart) + 1
1242 1235 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1243 1236 lend = body.find('\n', mend)
1244 1237 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1245 1238 begin = lend + 1
1246 1239
1247 1240 class linestate(object):
1248 1241 def __init__(self, line, linenum, colstart, colend):
1249 1242 self.line = line
1250 1243 self.linenum = linenum
1251 1244 self.colstart = colstart
1252 1245 self.colend = colend
1253 1246 def __eq__(self, other):
1254 1247 return self.line == other.line
1255 1248 def __hash__(self):
1256 1249 return hash(self.line)
1257 1250
1258 1251 matches = {}
1259 1252 def grepbody(fn, rev, body):
1260 1253 matches[rev].setdefault(fn, {})
1261 1254 m = matches[rev][fn]
1262 1255 for lnum, cstart, cend, line in matchlines(body):
1263 1256 s = linestate(line, lnum, cstart, cend)
1264 1257 m[s] = s
1265 1258
1266 1259 prev = {}
1267 1260 ucache = {}
1268 1261 def display(fn, rev, states, prevstates):
1269 1262 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1270 1263 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1271 1264 counts = {'-': 0, '+': 0}
1272 1265 filerevmatches = {}
1273 1266 for l in diff:
1274 1267 if incrementing or not opts['all']:
1275 1268 change = ((l in prevstates) and '-') or '+'
1276 1269 r = rev
1277 1270 else:
1278 1271 change = ((l in states) and '-') or '+'
1279 1272 r = prev[fn]
1280 1273 cols = [fn, str(rev)]
1281 1274 if opts['line_number']: cols.append(str(l.linenum))
1282 1275 if opts['all']: cols.append(change)
1283 1276 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1284 1277 ucache))
1285 1278 if opts['files_with_matches']:
1286 1279 c = (fn, rev)
1287 1280 if c in filerevmatches: continue
1288 1281 filerevmatches[c] = 1
1289 1282 else:
1290 1283 cols.append(l.line)
1291 1284 ui.write(sep.join(cols), eol)
1292 1285 counts[change] += 1
1293 1286 return counts['+'], counts['-']
1294 1287
1295 1288 fstate = {}
1296 1289 skip = {}
1297 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1290 changeiter, getchange = walkchangerevs(ui, repo, pats, opts)
1298 1291 count = 0
1299 1292 incrementing = False
1300 1293 for st, rev, fns in changeiter:
1301 1294 if st == 'window':
1302 1295 incrementing = rev
1303 1296 matches.clear()
1304 1297 elif st == 'add':
1305 1298 change = repo.changelog.read(repo.lookup(str(rev)))
1306 1299 mf = repo.manifest.read(change[0])
1307 1300 matches[rev] = {}
1308 1301 for fn in fns:
1309 1302 if fn in skip: continue
1310 1303 fstate.setdefault(fn, {})
1311 1304 try:
1312 1305 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1313 1306 except KeyError:
1314 1307 pass
1315 1308 elif st == 'iter':
1316 1309 states = matches[rev].items()
1317 1310 states.sort()
1318 1311 for fn, m in states:
1319 1312 if fn in skip: continue
1320 1313 if incrementing or not opts['all'] or fstate[fn]:
1321 1314 pos, neg = display(fn, rev, m, fstate[fn])
1322 1315 count += pos + neg
1323 1316 if pos and not opts['all']:
1324 1317 skip[fn] = True
1325 1318 fstate[fn] = m
1326 1319 prev[fn] = rev
1327 1320
1328 1321 if not incrementing:
1329 1322 fstate = fstate.items()
1330 1323 fstate.sort()
1331 1324 for fn, state in fstate:
1332 1325 if fn in skip: continue
1333 1326 display(fn, rev, {}, state)
1334 1327 return (count == 0 and 1) or 0
1335 1328
1336 1329 def heads(ui, repo, **opts):
1337 1330 """show current repository heads
1338 1331
1339 1332 Show all repository head changesets.
1340 1333
1341 1334 Repository "heads" are changesets that don't have children
1342 1335 changesets. They are where development generally takes place and
1343 1336 are the usual targets for update and merge operations.
1344 1337 """
1345 1338 if opts['rev']:
1346 1339 heads = repo.heads(repo.lookup(opts['rev']))
1347 1340 else:
1348 1341 heads = repo.heads()
1349 1342 br = None
1350 1343 if opts['branches']:
1351 1344 br = repo.branchlookup(heads)
1352 1345 for n in heads:
1353 1346 show_changeset(ui, repo, changenode=n, brinfo=br)
1354 1347
1355 1348 def identify(ui, repo):
1356 1349 """print information about the working copy
1357 1350
1358 1351 Print a short summary of the current state of the repo.
1359 1352
1360 1353 This summary identifies the repository state using one or two parent
1361 1354 hash identifiers, followed by a "+" if there are uncommitted changes
1362 1355 in the working directory, followed by a list of tags for this revision.
1363 1356 """
1364 1357 parents = [p for p in repo.dirstate.parents() if p != nullid]
1365 1358 if not parents:
1366 1359 ui.write(_("unknown\n"))
1367 1360 return
1368 1361
1369 1362 hexfunc = ui.verbose and hex or short
1370 1363 (c, a, d, u) = repo.changes()
1371 1364 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1372 1365 (c or a or d) and "+" or "")]
1373 1366
1374 1367 if not ui.quiet:
1375 1368 # multiple tags for a single parent separated by '/'
1376 1369 parenttags = ['/'.join(tags)
1377 1370 for tags in map(repo.nodetags, parents) if tags]
1378 1371 # tags for multiple parents separated by ' + '
1379 1372 if parenttags:
1380 1373 output.append(' + '.join(parenttags))
1381 1374
1382 1375 ui.write("%s\n" % ' '.join(output))
1383 1376
1384 1377 def import_(ui, repo, patch1, *patches, **opts):
1385 1378 """import an ordered set of patches
1386 1379
1387 1380 Import a list of patches and commit them individually.
1388 1381
1389 1382 If there are outstanding changes in the working directory, import
1390 1383 will abort unless given the -f flag.
1391 1384
1392 1385 If a patch looks like a mail message (its first line starts with
1393 1386 "From " or looks like an RFC822 header), it will not be applied
1394 1387 unless the -f option is used. The importer neither parses nor
1395 1388 discards mail headers, so use -f only to override the "mailness"
1396 1389 safety check, not to import a real mail message.
1397 1390 """
1398 1391 patches = (patch1,) + patches
1399 1392
1400 1393 if not opts['force']:
1401 1394 (c, a, d, u) = repo.changes()
1402 1395 if c or a or d:
1403 1396 raise util.Abort(_("outstanding uncommitted changes"))
1404 1397
1405 1398 d = opts["base"]
1406 1399 strip = opts["strip"]
1407 1400
1408 1401 mailre = re.compile(r'(?:From |[\w-]+:)')
1409 1402
1410 1403 # attempt to detect the start of a patch
1411 1404 # (this heuristic is borrowed from quilt)
1412 1405 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1413 1406 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1414 1407 '(---|\*\*\*)[ \t])')
1415 1408
1416 1409 for patch in patches:
1417 1410 ui.status(_("applying %s\n") % patch)
1418 1411 pf = os.path.join(d, patch)
1419 1412
1420 1413 message = []
1421 1414 user = None
1422 1415 hgpatch = False
1423 1416 for line in file(pf):
1424 1417 line = line.rstrip()
1425 1418 if (not message and not hgpatch and
1426 1419 mailre.match(line) and not opts['force']):
1427 1420 if len(line) > 35: line = line[:32] + '...'
1428 1421 raise util.Abort(_('first line looks like a '
1429 1422 'mail header: ') + line)
1430 1423 if diffre.match(line):
1431 1424 break
1432 1425 elif hgpatch:
1433 1426 # parse values when importing the result of an hg export
1434 1427 if line.startswith("# User "):
1435 1428 user = line[7:]
1436 1429 ui.debug(_('User: %s\n') % user)
1437 1430 elif not line.startswith("# ") and line:
1438 1431 message.append(line)
1439 1432 hgpatch = False
1440 1433 elif line == '# HG changeset patch':
1441 1434 hgpatch = True
1442 1435 message = [] # We may have collected garbage
1443 1436 else:
1444 1437 message.append(line)
1445 1438
1446 1439 # make sure message isn't empty
1447 1440 if not message:
1448 1441 message = _("imported patch %s\n") % patch
1449 1442 else:
1450 1443 message = "%s\n" % '\n'.join(message)
1451 1444 ui.debug(_('message:\n%s\n') % message)
1452 1445
1453 1446 files = util.patch(strip, pf, ui)
1454 1447
1455 1448 if len(files) > 0:
1456 1449 addremove(ui, repo, *files)
1457 1450 repo.commit(files, message, user)
1458 1451
1459 1452 def incoming(ui, repo, source="default", **opts):
1460 1453 """show new changesets found in source
1461 1454
1462 1455 Show new changesets found in the specified repo or the default
1463 1456 pull repo. These are the changesets that would be pulled if a pull
1464 1457 was requested.
1465 1458
1466 1459 Currently only local repositories are supported.
1467 1460 """
1468 1461 source = ui.expandpath(source, repo.root)
1469 1462 other = hg.repository(ui, source)
1470 1463 if not other.local():
1471 1464 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1472 1465 o = repo.findincoming(other)
1473 1466 if not o:
1474 1467 return
1475 1468 o = other.changelog.nodesbetween(o)[0]
1476 1469 if opts['newest_first']:
1477 1470 o.reverse()
1478 1471 for n in o:
1479 1472 parents = [p for p in other.changelog.parents(n) if p != nullid]
1480 1473 if opts['no_merges'] and len(parents) == 2:
1481 1474 continue
1482 1475 show_changeset(ui, other, changenode=n)
1483 1476 if opts['patch']:
1484 1477 prev = (parents and parents[0]) or nullid
1485 1478 dodiff(ui, ui, other, prev, n)
1486 1479 ui.write("\n")
1487 1480
1488 1481 def init(ui, dest="."):
1489 1482 """create a new repository in the given directory
1490 1483
1491 1484 Initialize a new repository in the given directory. If the given
1492 1485 directory does not exist, it is created.
1493 1486
1494 1487 If no directory is given, the current directory is used.
1495 1488 """
1496 1489 if not os.path.exists(dest):
1497 1490 os.mkdir(dest)
1498 1491 hg.repository(ui, dest, create=1)
1499 1492
1500 1493 def locate(ui, repo, *pats, **opts):
1501 1494 """locate files matching specific patterns
1502 1495
1503 1496 Print all files under Mercurial control whose names match the
1504 1497 given patterns.
1505 1498
1506 1499 This command searches the current directory and its
1507 1500 subdirectories. To search an entire repository, move to the root
1508 1501 of the repository.
1509 1502
1510 1503 If no patterns are given to match, this command prints all file
1511 1504 names.
1512 1505
1513 1506 If you want to feed the output of this command into the "xargs"
1514 1507 command, use the "-0" option to both this command and "xargs".
1515 1508 This will avoid the problem of "xargs" treating single filenames
1516 1509 that contain white space as multiple filenames.
1517 1510 """
1518 1511 end = opts['print0'] and '\0' or '\n'
1519 1512
1520 1513 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1521 1514 if repo.dirstate.state(abs) == '?':
1522 1515 continue
1523 1516 if opts['fullpath']:
1524 1517 ui.write(os.path.join(repo.root, abs), end)
1525 1518 else:
1526 1519 ui.write(rel, end)
1527 1520
1528 1521 def log(ui, repo, *pats, **opts):
1529 1522 """show revision history of entire repository or files
1530 1523
1531 1524 Print the revision history of the specified files or the entire project.
1532 1525
1533 1526 By default this command outputs: changeset id and hash, tags,
1534 1527 non-trivial parents, user, date and time, and a summary for each
1535 1528 commit. When the -v/--verbose switch is used, the list of changed
1536 1529 files and full commit message is shown.
1537 1530 """
1538 1531 class dui(object):
1539 1532 # Implement and delegate some ui protocol. Save hunks of
1540 1533 # output for later display in the desired order.
1541 1534 def __init__(self, ui):
1542 1535 self.ui = ui
1543 1536 self.hunk = {}
1544 1537 def bump(self, rev):
1545 1538 self.rev = rev
1546 1539 self.hunk[rev] = []
1547 1540 def note(self, *args):
1548 1541 if self.verbose:
1549 1542 self.write(*args)
1550 1543 def status(self, *args):
1551 1544 if not self.quiet:
1552 1545 self.write(*args)
1553 1546 def write(self, *args):
1554 1547 self.hunk[self.rev].append(args)
1555 1548 def debug(self, *args):
1556 1549 if self.debugflag:
1557 1550 self.write(*args)
1558 1551 def __getattr__(self, key):
1559 1552 return getattr(self.ui, key)
1560 cwd = repo.getcwd()
1561 if not pats and cwd:
1562 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1563 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1564 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1565 pats, opts)
1553 changeiter, getchange = walkchangerevs(ui, repo, pats, opts)
1566 1554 for st, rev, fns in changeiter:
1567 1555 if st == 'window':
1568 1556 du = dui(ui)
1569 1557 elif st == 'add':
1570 1558 du.bump(rev)
1571 1559 changenode = repo.changelog.node(rev)
1572 1560 parents = [p for p in repo.changelog.parents(changenode)
1573 1561 if p != nullid]
1574 1562 if opts['no_merges'] and len(parents) == 2:
1575 1563 continue
1576 1564 if opts['only_merges'] and len(parents) != 2:
1577 1565 continue
1578 1566
1579 1567 br = None
1580 1568 if opts['keyword']:
1581 1569 changes = repo.changelog.read(repo.changelog.node(rev))
1582 1570 miss = 0
1583 1571 for k in [kw.lower() for kw in opts['keyword']]:
1584 1572 if not (k in changes[1].lower() or
1585 1573 k in changes[4].lower() or
1586 1574 k in " ".join(changes[3][:20]).lower()):
1587 1575 miss = 1
1588 1576 break
1589 1577 if miss:
1590 1578 continue
1591 1579
1592 1580 if opts['branch']:
1593 1581 br = repo.branchlookup([repo.changelog.node(rev)])
1594 1582
1595 1583 show_changeset(du, repo, rev, brinfo=br)
1596 1584 if opts['patch']:
1597 1585 prev = (parents and parents[0]) or nullid
1598 1586 dodiff(du, du, repo, prev, changenode, fns)
1599 1587 du.write("\n\n")
1600 1588 elif st == 'iter':
1601 1589 for args in du.hunk[rev]:
1602 1590 ui.write(*args)
1603 1591
1604 1592 def manifest(ui, repo, rev=None):
1605 1593 """output the latest or given revision of the project manifest
1606 1594
1607 1595 Print a list of version controlled files for the given revision.
1608 1596
1609 1597 The manifest is the list of files being version controlled. If no revision
1610 1598 is given then the tip is used.
1611 1599 """
1612 1600 if rev:
1613 1601 try:
1614 1602 # assume all revision numbers are for changesets
1615 1603 n = repo.lookup(rev)
1616 1604 change = repo.changelog.read(n)
1617 1605 n = change[0]
1618 1606 except hg.RepoError:
1619 1607 n = repo.manifest.lookup(rev)
1620 1608 else:
1621 1609 n = repo.manifest.tip()
1622 1610 m = repo.manifest.read(n)
1623 1611 mf = repo.manifest.readflags(n)
1624 1612 files = m.keys()
1625 1613 files.sort()
1626 1614
1627 1615 for f in files:
1628 1616 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1629 1617
1630 1618 def outgoing(ui, repo, dest="default-push", **opts):
1631 1619 """show changesets not found in destination
1632 1620
1633 1621 Show changesets not found in the specified destination repo or the
1634 1622 default push repo. These are the changesets that would be pushed
1635 1623 if a push was requested.
1636 1624 """
1637 1625 dest = ui.expandpath(dest, repo.root)
1638 1626 other = hg.repository(ui, dest)
1639 1627 o = repo.findoutgoing(other)
1640 1628 o = repo.changelog.nodesbetween(o)[0]
1641 1629 if opts['newest_first']:
1642 1630 o.reverse()
1643 1631 for n in o:
1644 1632 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1645 1633 if opts['no_merges'] and len(parents) == 2:
1646 1634 continue
1647 1635 show_changeset(ui, repo, changenode=n)
1648 1636 if opts['patch']:
1649 1637 prev = (parents and parents[0]) or nullid
1650 1638 dodiff(ui, ui, repo, prev, n)
1651 1639 ui.write("\n")
1652 1640
1653 1641 def parents(ui, repo, rev=None):
1654 1642 """show the parents of the working dir or revision
1655 1643
1656 1644 Print the working directory's parent revisions.
1657 1645 """
1658 1646 if rev:
1659 1647 p = repo.changelog.parents(repo.lookup(rev))
1660 1648 else:
1661 1649 p = repo.dirstate.parents()
1662 1650
1663 1651 for n in p:
1664 1652 if n != nullid:
1665 1653 show_changeset(ui, repo, changenode=n)
1666 1654
1667 1655 def paths(ui, search=None):
1668 1656 """show definition of symbolic path names
1669 1657
1670 1658 Show definition of symbolic path name NAME. If no name is given, show
1671 1659 definition of available names.
1672 1660
1673 1661 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1674 1662 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1675 1663 """
1676 1664 try:
1677 1665 repo = hg.repository(ui=ui)
1678 1666 except hg.RepoError:
1679 1667 pass
1680 1668
1681 1669 if search:
1682 1670 for name, path in ui.configitems("paths"):
1683 1671 if name == search:
1684 1672 ui.write("%s\n" % path)
1685 1673 return
1686 1674 ui.warn(_("not found!\n"))
1687 1675 return 1
1688 1676 else:
1689 1677 for name, path in ui.configitems("paths"):
1690 1678 ui.write("%s = %s\n" % (name, path))
1691 1679
1692 1680 def pull(ui, repo, source="default", **opts):
1693 1681 """pull changes from the specified source
1694 1682
1695 1683 Pull changes from a remote repository to a local one.
1696 1684
1697 1685 This finds all changes from the repository at the specified path
1698 1686 or URL and adds them to the local repository. By default, this
1699 1687 does not update the copy of the project in the working directory.
1700 1688
1701 1689 Valid URLs are of the form:
1702 1690
1703 1691 local/filesystem/path
1704 1692 http://[user@]host[:port][/path]
1705 1693 https://[user@]host[:port][/path]
1706 1694 ssh://[user@]host[:port][/path]
1707 1695
1708 1696 SSH requires an accessible shell account on the destination machine
1709 1697 and a copy of hg in the remote path. With SSH, paths are relative
1710 1698 to the remote user's home directory by default; use two slashes at
1711 1699 the start of a path to specify it as relative to the filesystem root.
1712 1700 """
1713 1701 source = ui.expandpath(source, repo.root)
1714 1702 ui.status(_('pulling from %s\n') % (source))
1715 1703
1716 1704 if opts['ssh']:
1717 1705 ui.setconfig("ui", "ssh", opts['ssh'])
1718 1706 if opts['remotecmd']:
1719 1707 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1720 1708
1721 1709 other = hg.repository(ui, source)
1722 1710 revs = None
1723 1711 if opts['rev'] and not other.local():
1724 1712 raise util.Abort("pull -r doesn't work for remote repositories yet")
1725 1713 elif opts['rev']:
1726 1714 revs = [other.lookup(rev) for rev in opts['rev']]
1727 1715 r = repo.pull(other, heads=revs)
1728 1716 if not r:
1729 1717 if opts['update']:
1730 1718 return update(ui, repo)
1731 1719 else:
1732 1720 ui.status(_("(run 'hg update' to get a working copy)\n"))
1733 1721
1734 1722 return r
1735 1723
1736 1724 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1737 1725 """push changes to the specified destination
1738 1726
1739 1727 Push changes from the local repository to the given destination.
1740 1728
1741 1729 This is the symmetrical operation for pull. It helps to move
1742 1730 changes from the current repository to a different one. If the
1743 1731 destination is local this is identical to a pull in that directory
1744 1732 from the current one.
1745 1733
1746 1734 By default, push will refuse to run if it detects the result would
1747 1735 increase the number of remote heads. This generally indicates the
1748 1736 the client has forgotten to sync and merge before pushing.
1749 1737
1750 1738 Valid URLs are of the form:
1751 1739
1752 1740 local/filesystem/path
1753 1741 ssh://[user@]host[:port][/path]
1754 1742
1755 1743 SSH requires an accessible shell account on the destination
1756 1744 machine and a copy of hg in the remote path.
1757 1745 """
1758 1746 dest = ui.expandpath(dest, repo.root)
1759 1747 ui.status('pushing to %s\n' % (dest))
1760 1748
1761 1749 if ssh:
1762 1750 ui.setconfig("ui", "ssh", ssh)
1763 1751 if remotecmd:
1764 1752 ui.setconfig("ui", "remotecmd", remotecmd)
1765 1753
1766 1754 other = hg.repository(ui, dest)
1767 1755 r = repo.push(other, force)
1768 1756 return r
1769 1757
1770 1758 def rawcommit(ui, repo, *flist, **rc):
1771 1759 """raw commit interface
1772 1760
1773 1761 Lowlevel commit, for use in helper scripts.
1774 1762
1775 1763 This command is not intended to be used by normal users, as it is
1776 1764 primarily useful for importing from other SCMs.
1777 1765 """
1778 1766 message = rc['message']
1779 1767 if not message and rc['logfile']:
1780 1768 try:
1781 1769 message = open(rc['logfile']).read()
1782 1770 except IOError:
1783 1771 pass
1784 1772 if not message and not rc['logfile']:
1785 1773 raise util.Abort(_("missing commit message"))
1786 1774
1787 1775 files = relpath(repo, list(flist))
1788 1776 if rc['files']:
1789 1777 files += open(rc['files']).read().splitlines()
1790 1778
1791 1779 rc['parent'] = map(repo.lookup, rc['parent'])
1792 1780
1793 1781 try:
1794 1782 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1795 1783 except ValueError, inst:
1796 1784 raise util.Abort(str(inst))
1797 1785
1798 1786 def recover(ui, repo):
1799 1787 """roll back an interrupted transaction
1800 1788
1801 1789 Recover from an interrupted commit or pull.
1802 1790
1803 1791 This command tries to fix the repository status after an interrupted
1804 1792 operation. It should only be necessary when Mercurial suggests it.
1805 1793 """
1806 1794 if repo.recover():
1807 1795 return repo.verify()
1808 1796 return False
1809 1797
1810 1798 def remove(ui, repo, pat, *pats, **opts):
1811 1799 """remove the specified files on the next commit
1812 1800
1813 1801 Schedule the indicated files for removal from the repository.
1814 1802
1815 1803 This command schedules the files to be removed at the next commit.
1816 1804 This only removes files from the current branch, not from the
1817 1805 entire project history. If the files still exist in the working
1818 1806 directory, they will be deleted from it.
1819 1807 """
1820 1808 names = []
1821 1809 def okaytoremove(abs, rel, exact):
1822 1810 c, a, d, u = repo.changes(files = [abs])
1823 1811 reason = None
1824 1812 if c: reason = _('is modified')
1825 1813 elif a: reason = _('has been marked for add')
1826 1814 elif u: reason = _('is not managed')
1827 1815 if reason:
1828 1816 if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1829 1817 else:
1830 1818 return True
1831 1819 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1832 1820 if okaytoremove(abs, rel, exact):
1833 1821 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1834 1822 names.append(abs)
1835 1823 repo.remove(names, unlink=True)
1836 1824
1837 1825 def rename(ui, repo, *pats, **opts):
1838 1826 """rename files; equivalent of copy + remove
1839 1827
1840 1828 Mark dest as copies of sources; mark sources for deletion. If
1841 1829 dest is a directory, copies are put in that directory. If dest is
1842 1830 a file, there can only be one source.
1843 1831
1844 1832 By default, this command copies the contents of files as they
1845 1833 stand in the working directory. If invoked with --after, the
1846 1834 operation is recorded, but no copying is performed.
1847 1835
1848 1836 This command takes effect in the next commit.
1849 1837
1850 1838 NOTE: This command should be treated as experimental. While it
1851 1839 should properly record rename files, this information is not yet
1852 1840 fully used by merge, nor fully reported by log.
1853 1841 """
1854 1842 errs, copied = docopy(ui, repo, pats, opts)
1855 1843 names = []
1856 1844 for abs, rel, exact in copied:
1857 1845 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1858 1846 names.append(abs)
1859 1847 repo.remove(names, unlink=True)
1860 1848 return errs
1861 1849
1862 1850 def revert(ui, repo, *pats, **opts):
1863 1851 """revert modified files or dirs back to their unmodified states
1864 1852
1865 1853 Revert any uncommitted modifications made to the named files or
1866 1854 directories. This restores the contents of the affected files to
1867 1855 an unmodified state.
1868 1856
1869 1857 If a file has been deleted, it is recreated. If the executable
1870 1858 mode of a file was changed, it is reset.
1871 1859
1872 1860 If names are given, all files matching the names are reverted.
1873 1861
1874 If no names are given, all files in the current directory and
1875 its subdirectories are reverted.
1862 If no arguments are given, all files in the repository are reverted.
1876 1863 """
1877 1864 node = opts['rev'] and repo.lookup(opts['rev']) or \
1878 1865 repo.dirstate.parents()[0]
1879 1866
1880 files, choose, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1867 files, choose, anypats, cwd = matchpats(repo, pats, opts)
1881 1868 (c, a, d, u) = repo.changes(match=choose)
1882 1869 repo.forget(a)
1883 1870 repo.undelete(d)
1884 1871
1885 1872 return repo.update(node, False, True, choose, False)
1886 1873
1887 1874 def root(ui, repo):
1888 1875 """print the root (top) of the current working dir
1889 1876
1890 1877 Print the root directory of the current repository.
1891 1878 """
1892 1879 ui.write(repo.root + "\n")
1893 1880
1894 1881 def serve(ui, repo, **opts):
1895 1882 """export the repository via HTTP
1896 1883
1897 1884 Start a local HTTP repository browser and pull server.
1898 1885
1899 1886 By default, the server logs accesses to stdout and errors to
1900 1887 stderr. Use the "-A" and "-E" options to log to files.
1901 1888 """
1902 1889
1903 1890 if opts["stdio"]:
1904 1891 fin, fout = sys.stdin, sys.stdout
1905 1892 sys.stdout = sys.stderr
1906 1893
1907 1894 # Prevent insertion/deletion of CRs
1908 1895 util.set_binary(fin)
1909 1896 util.set_binary(fout)
1910 1897
1911 1898 def getarg():
1912 1899 argline = fin.readline()[:-1]
1913 1900 arg, l = argline.split()
1914 1901 val = fin.read(int(l))
1915 1902 return arg, val
1916 1903 def respond(v):
1917 1904 fout.write("%d\n" % len(v))
1918 1905 fout.write(v)
1919 1906 fout.flush()
1920 1907
1921 1908 lock = None
1922 1909
1923 1910 while 1:
1924 1911 cmd = fin.readline()[:-1]
1925 1912 if cmd == '':
1926 1913 return
1927 1914 if cmd == "heads":
1928 1915 h = repo.heads()
1929 1916 respond(" ".join(map(hex, h)) + "\n")
1930 1917 if cmd == "lock":
1931 1918 lock = repo.lock()
1932 1919 respond("")
1933 1920 if cmd == "unlock":
1934 1921 if lock:
1935 1922 lock.release()
1936 1923 lock = None
1937 1924 respond("")
1938 1925 elif cmd == "branches":
1939 1926 arg, nodes = getarg()
1940 1927 nodes = map(bin, nodes.split(" "))
1941 1928 r = []
1942 1929 for b in repo.branches(nodes):
1943 1930 r.append(" ".join(map(hex, b)) + "\n")
1944 1931 respond("".join(r))
1945 1932 elif cmd == "between":
1946 1933 arg, pairs = getarg()
1947 1934 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1948 1935 r = []
1949 1936 for b in repo.between(pairs):
1950 1937 r.append(" ".join(map(hex, b)) + "\n")
1951 1938 respond("".join(r))
1952 1939 elif cmd == "changegroup":
1953 1940 nodes = []
1954 1941 arg, roots = getarg()
1955 1942 nodes = map(bin, roots.split(" "))
1956 1943
1957 1944 cg = repo.changegroup(nodes)
1958 1945 while 1:
1959 1946 d = cg.read(4096)
1960 1947 if not d:
1961 1948 break
1962 1949 fout.write(d)
1963 1950
1964 1951 fout.flush()
1965 1952
1966 1953 elif cmd == "addchangegroup":
1967 1954 if not lock:
1968 1955 respond("not locked")
1969 1956 continue
1970 1957 respond("")
1971 1958
1972 1959 r = repo.addchangegroup(fin)
1973 1960 respond("")
1974 1961
1975 1962 optlist = "name templates style address port ipv6 accesslog errorlog"
1976 1963 for o in optlist.split():
1977 1964 if opts[o]:
1978 1965 ui.setconfig("web", o, opts[o])
1979 1966
1980 1967 try:
1981 1968 httpd = hgweb.create_server(repo)
1982 1969 except socket.error, inst:
1983 1970 raise util.Abort('cannot start server: ' + inst.args[1])
1984 1971
1985 1972 if ui.verbose:
1986 1973 addr, port = httpd.socket.getsockname()
1987 1974 if addr == '0.0.0.0':
1988 1975 addr = socket.gethostname()
1989 1976 else:
1990 1977 try:
1991 1978 addr = socket.gethostbyaddr(addr)[0]
1992 1979 except socket.error:
1993 1980 pass
1994 1981 if port != 80:
1995 1982 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
1996 1983 else:
1997 1984 ui.status(_('listening at http://%s/\n') % addr)
1998 1985 httpd.serve_forever()
1999 1986
2000 1987 def status(ui, repo, *pats, **opts):
2001 1988 """show changed files in the working directory
2002 1989
2003 Show changed files in the working directory. If no names are
2004 given, all files are shown. Otherwise, only files matching the
2005 given names are shown.
1990 Show changed files in the repository. If names are
1991 given, only files that match are shown.
2006 1992
2007 1993 The codes used to show the status of files are:
2008 1994 M = modified
2009 1995 A = added
2010 1996 R = removed
2011 1997 ? = not tracked
2012 1998 """
2013 1999
2014 cwd = repo.getcwd()
2015 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
2000 files, matchfn, anypats, cwd = matchpats(repo, pats, opts)
2016 2001 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
2017 2002 for n in repo.changes(files=files, match=matchfn)]
2018 2003
2019 2004 changetypes = [(_('modified'), 'M', c),
2020 2005 (_('added'), 'A', a),
2021 2006 (_('removed'), 'R', d),
2022 2007 (_('unknown'), '?', u)]
2023 2008
2024 2009 end = opts['print0'] and '\0' or '\n'
2025 2010
2026 2011 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2027 2012 or changetypes):
2028 2013 if opts['no_status']:
2029 2014 format = "%%s%s" % end
2030 2015 else:
2031 2016 format = "%s %%s%s" % (char, end);
2032 2017
2033 2018 for f in changes:
2034 2019 ui.write(format % f)
2035 2020
2036 2021 def tag(ui, repo, name, rev=None, **opts):
2037 2022 """add a tag for the current tip or a given revision
2038 2023
2039 2024 Name a particular revision using <name>.
2040 2025
2041 2026 Tags are used to name particular revisions of the repository and are
2042 2027 very useful to compare different revision, to go back to significant
2043 2028 earlier versions or to mark branch points as releases, etc.
2044 2029
2045 2030 If no revision is given, the tip is used.
2046 2031
2047 2032 To facilitate version control, distribution, and merging of tags,
2048 2033 they are stored as a file named ".hgtags" which is managed
2049 2034 similarly to other project files and can be hand-edited if
2050 2035 necessary.
2051 2036 """
2052 2037 if name == "tip":
2053 2038 raise util.Abort(_("the name 'tip' is reserved"))
2054 2039 if 'rev' in opts:
2055 2040 rev = opts['rev']
2056 2041 if rev:
2057 2042 r = hex(repo.lookup(rev))
2058 2043 else:
2059 2044 r = hex(repo.changelog.tip())
2060 2045
2061 2046 disallowed = (revrangesep, '\r', '\n')
2062 2047 for c in disallowed:
2063 2048 if name.find(c) >= 0:
2064 2049 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2065 2050
2066 2051 if opts['local']:
2067 2052 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2068 2053 return
2069 2054
2070 2055 (c, a, d, u) = repo.changes()
2071 2056 for x in (c, a, d, u):
2072 2057 if ".hgtags" in x:
2073 2058 raise util.Abort(_("working copy of .hgtags is changed "
2074 2059 "(please commit .hgtags manually)"))
2075 2060
2076 2061 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2077 2062 if repo.dirstate.state(".hgtags") == '?':
2078 2063 repo.add([".hgtags"])
2079 2064
2080 2065 message = (opts['message'] or
2081 2066 _("Added tag %s for changeset %s") % (name, r))
2082 2067 try:
2083 2068 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2084 2069 except ValueError, inst:
2085 2070 raise util.Abort(str(inst))
2086 2071
2087 2072 def tags(ui, repo):
2088 2073 """list repository tags
2089 2074
2090 2075 List the repository tags.
2091 2076
2092 2077 This lists both regular and local tags.
2093 2078 """
2094 2079
2095 2080 l = repo.tagslist()
2096 2081 l.reverse()
2097 2082 for t, n in l:
2098 2083 try:
2099 2084 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2100 2085 except KeyError:
2101 2086 r = " ?:?"
2102 2087 ui.write("%-30s %s\n" % (t, r))
2103 2088
2104 2089 def tip(ui, repo):
2105 2090 """show the tip revision
2106 2091
2107 2092 Show the tip revision.
2108 2093 """
2109 2094 n = repo.changelog.tip()
2110 2095 show_changeset(ui, repo, changenode=n)
2111 2096
2112 2097 def unbundle(ui, repo, fname):
2113 2098 """apply a changegroup file
2114 2099
2115 2100 Apply a compressed changegroup file generated by the bundle
2116 2101 command.
2117 2102 """
2118 2103 f = urllib.urlopen(fname)
2119 2104
2120 2105 if f.read(4) != "HG10":
2121 2106 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2122 2107
2123 2108 def bzgenerator(f):
2124 2109 zd = bz2.BZ2Decompressor()
2125 2110 for chunk in f:
2126 2111 yield zd.decompress(chunk)
2127 2112
2128 2113 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2129 2114 repo.addchangegroup(util.chunkbuffer(bzgen))
2130 2115
2131 2116 def undo(ui, repo):
2132 2117 """undo the last commit or pull
2133 2118
2134 2119 Roll back the last pull or commit transaction on the
2135 2120 repository, restoring the project to its earlier state.
2136 2121
2137 2122 This command should be used with care. There is only one level of
2138 2123 undo and there is no redo.
2139 2124
2140 2125 This command is not intended for use on public repositories. Once
2141 2126 a change is visible for pull by other users, undoing it locally is
2142 2127 ineffective.
2143 2128 """
2144 2129 repo.undo()
2145 2130
2146 2131 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
2147 2132 """update or merge working directory
2148 2133
2149 2134 Update the working directory to the specified revision.
2150 2135
2151 2136 If there are no outstanding changes in the working directory and
2152 2137 there is a linear relationship between the current version and the
2153 2138 requested version, the result is the requested version.
2154 2139
2155 2140 Otherwise the result is a merge between the contents of the
2156 2141 current working directory and the requested version. Files that
2157 2142 changed between either parent are marked as changed for the next
2158 2143 commit and a commit must be performed before any further updates
2159 2144 are allowed.
2160 2145
2161 2146 By default, update will refuse to run if doing so would require
2162 2147 merging or discarding local changes.
2163 2148 """
2164 2149 if branch:
2165 2150 br = repo.branchlookup(branch=branch)
2166 2151 found = []
2167 2152 for x in br:
2168 2153 if branch in br[x]:
2169 2154 found.append(x)
2170 2155 if len(found) > 1:
2171 2156 ui.warn(_("Found multiple heads for %s\n") % branch)
2172 2157 for x in found:
2173 2158 show_changeset(ui, repo, changenode=x, brinfo=br)
2174 2159 return 1
2175 2160 if len(found) == 1:
2176 2161 node = found[0]
2177 2162 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2178 2163 else:
2179 2164 ui.warn(_("branch %s not found\n") % (branch))
2180 2165 return 1
2181 2166 else:
2182 2167 node = node and repo.lookup(node) or repo.changelog.tip()
2183 2168 return repo.update(node, allow=merge, force=clean)
2184 2169
2185 2170 def verify(ui, repo):
2186 2171 """verify the integrity of the repository
2187 2172
2188 2173 Verify the integrity of the current repository.
2189 2174
2190 2175 This will perform an extensive check of the repository's
2191 2176 integrity, validating the hashes and checksums of each entry in
2192 2177 the changelog, manifest, and tracked files, as well as the
2193 2178 integrity of their crosslinks and indices.
2194 2179 """
2195 2180 return repo.verify()
2196 2181
2197 2182 # Command options and aliases are listed here, alphabetically
2198 2183
2199 2184 table = {
2200 2185 "^add":
2201 2186 (add,
2202 2187 [('I', 'include', [], _('include names matching the given patterns')),
2203 2188 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2204 2189 "hg add [OPTION]... [FILE]..."),
2205 2190 "addremove":
2206 2191 (addremove,
2207 2192 [('I', 'include', [], _('include names matching the given patterns')),
2208 2193 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2209 2194 "hg addremove [OPTION]... [FILE]..."),
2210 2195 "^annotate":
2211 2196 (annotate,
2212 2197 [('r', 'rev', '', _('annotate the specified revision')),
2213 2198 ('a', 'text', None, _('treat all files as text')),
2214 2199 ('u', 'user', None, _('list the author')),
2215 2200 ('d', 'date', None, _('list the date')),
2216 2201 ('n', 'number', None, _('list the revision number (default)')),
2217 2202 ('c', 'changeset', None, _('list the changeset')),
2218 2203 ('I', 'include', [], _('include names matching the given patterns')),
2219 2204 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2220 2205 _('hg annotate [OPTION]... FILE...')),
2221 2206 "bundle":
2222 2207 (bundle,
2223 2208 [],
2224 2209 _('hg bundle FILE DEST')),
2225 2210 "cat":
2226 2211 (cat,
2227 2212 [('I', 'include', [], _('include names matching the given patterns')),
2228 2213 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2229 2214 ('o', 'output', "", _('print output to file with formatted name')),
2230 2215 ('r', 'rev', '', _('print the given revision'))],
2231 2216 _('hg cat [OPTION]... FILE...')),
2232 2217 "^clone":
2233 2218 (clone,
2234 2219 [('U', 'noupdate', None, _('do not update the new working directory')),
2235 2220 ('e', 'ssh', "", _('specify ssh command to use')),
2236 2221 ('', 'pull', None, _('use pull protocol to copy metadata')),
2237 2222 ('r', 'rev', [], _('a changeset you would like to have after cloning')),
2238 2223 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2239 2224 _('hg clone [OPTION]... SOURCE [DEST]')),
2240 2225 "^commit|ci":
2241 2226 (commit,
2242 2227 [('A', 'addremove', None, _('run addremove during commit')),
2243 2228 ('I', 'include', [], _('include names matching the given patterns')),
2244 2229 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2245 2230 ('m', 'message', "", _('use <text> as commit message')),
2246 2231 ('l', 'logfile', "", _('read the commit message from <file>')),
2247 2232 ('d', 'date', "", _('record datecode as commit date')),
2248 2233 ('u', 'user', "", _('record user as commiter'))],
2249 2234 _('hg commit [OPTION]... [FILE]...')),
2250 2235 "copy|cp": (copy,
2251 2236 [('I', 'include', [], _('include names matching the given patterns')),
2252 2237 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2253 2238 ('A', 'after', None, _('record a copy that has already occurred')),
2254 2239 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2255 2240 _('hg copy [OPTION]... [SOURCE]... DEST')),
2256 2241 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2257 2242 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2258 2243 "debugconfig": (debugconfig, [], _('debugconfig')),
2259 2244 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2260 2245 "debugstate": (debugstate, [], _('debugstate')),
2261 2246 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2262 2247 "debugindex": (debugindex, [], _('debugindex FILE')),
2263 2248 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2264 2249 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2265 2250 "debugwalk":
2266 2251 (debugwalk,
2267 2252 [('I', 'include', [], _('include names matching the given patterns')),
2268 2253 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2269 2254 _('debugwalk [OPTION]... [FILE]...')),
2270 2255 "^diff":
2271 2256 (diff,
2272 2257 [('r', 'rev', [], _('revision')),
2273 2258 ('a', 'text', None, _('treat all files as text')),
2274 2259 ('I', 'include', [], _('include names matching the given patterns')),
2275 2260 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2276 2261 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2277 2262 "^export":
2278 2263 (export,
2279 2264 [('o', 'output', "", _('print output to file with formatted name')),
2280 2265 ('a', 'text', None, _('treat all files as text'))],
2281 2266 "hg export [-a] [-o OUTFILE] REV..."),
2282 2267 "forget":
2283 2268 (forget,
2284 2269 [('I', 'include', [], _('include names matching the given patterns')),
2285 2270 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2286 2271 "hg forget [OPTION]... FILE..."),
2287 2272 "grep":
2288 2273 (grep,
2289 2274 [('0', 'print0', None, _('end fields with NUL')),
2290 2275 ('I', 'include', [], _('include names matching the given patterns')),
2291 2276 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2292 2277 ('', 'all', None, _('print all revisions that match')),
2293 2278 ('i', 'ignore-case', None, _('ignore case when matching')),
2294 2279 ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
2295 2280 ('n', 'line-number', None, _('print matching line numbers')),
2296 2281 ('r', 'rev', [], _('search in given revision range')),
2297 2282 ('u', 'user', None, _('print user who committed change'))],
2298 2283 "hg grep [OPTION]... PATTERN [FILE]..."),
2299 2284 "heads":
2300 2285 (heads,
2301 2286 [('b', 'branches', None, _('find branch info')),
2302 2287 ('r', 'rev', "", _('show only heads which are descendants of rev'))],
2303 2288 _('hg heads [-b] [-r <rev>]')),
2304 2289 "help": (help_, [], _('hg help [COMMAND]')),
2305 2290 "identify|id": (identify, [], _('hg identify')),
2306 2291 "import|patch":
2307 2292 (import_,
2308 2293 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2309 2294 _('meaning as the corresponding patch option')),
2310 2295 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2311 2296 ('b', 'base', "", _('base path'))],
2312 2297 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
2313 2298 "incoming|in": (incoming,
2314 2299 [('M', 'no-merges', None, _("do not show merges")),
2315 2300 ('p', 'patch', None, _('show patch')),
2316 2301 ('n', 'newest-first', None, _('show newest record first'))],
2317 2302 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2318 2303 "^init": (init, [], _('hg init [DEST]')),
2319 2304 "locate":
2320 2305 (locate,
2321 2306 [('r', 'rev', '', _('search the repository as it stood at rev')),
2322 2307 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2323 2308 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
2324 2309 ('I', 'include', [], _('include names matching the given patterns')),
2325 2310 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2326 2311 _('hg locate [OPTION]... [PATTERN]...')),
2327 2312 "^log|history":
2328 2313 (log,
2329 2314 [('I', 'include', [], _('include names matching the given patterns')),
2330 2315 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2331 2316 ('b', 'branch', None, _('show branches')),
2332 2317 ('k', 'keyword', [], _('search for a keyword')),
2333 2318 ('r', 'rev', [], _('show the specified revision or range')),
2334 2319 ('M', 'no-merges', None, _("do not show merges")),
2335 2320 ('m', 'only-merges', None, _("show only merges")),
2336 2321 ('p', 'patch', None, _('show patch'))],
2337 2322 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2338 2323 "manifest": (manifest, [], _('hg manifest [REV]')),
2339 2324 "outgoing|out": (outgoing,
2340 2325 [('M', 'no-merges', None, _("do not show merges")),
2341 2326 ('p', 'patch', None, _('show patch')),
2342 2327 ('n', 'newest-first', None, _('show newest record first'))],
2343 2328 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2344 2329 "^parents": (parents, [], _('hg parents [REV]')),
2345 2330 "paths": (paths, [], _('hg paths [NAME]')),
2346 2331 "^pull":
2347 2332 (pull,
2348 2333 [('u', 'update', None, _('update the working directory to tip after pull')),
2349 2334 ('e', 'ssh', "", _('specify ssh command to use')),
2350 2335 ('r', 'rev', [], _('a specific revision you would like to pull')),
2351 2336 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2352 2337 _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
2353 2338 "^push":
2354 2339 (push,
2355 2340 [('f', 'force', None, _('force push')),
2356 2341 ('e', 'ssh', "", _('specify ssh command to use')),
2357 2342 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2358 2343 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2359 2344 "rawcommit":
2360 2345 (rawcommit,
2361 2346 [('p', 'parent', [], _('parent')),
2362 2347 ('d', 'date', "", _('date code')),
2363 2348 ('u', 'user', "", _('user')),
2364 2349 ('F', 'files', "", _('file list')),
2365 2350 ('m', 'message', "", _('commit message')),
2366 2351 ('l', 'logfile', "", _('commit message file'))],
2367 2352 _('hg rawcommit [OPTION]... [FILE]...')),
2368 2353 "recover": (recover, [], _("hg recover")),
2369 2354 "^remove|rm": (remove,
2370 2355 [('I', 'include', [], _('include names matching the given patterns')),
2371 2356 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2372 2357 _("hg remove [OPTION]... FILE...")),
2373 2358 "rename|mv": (rename,
2374 2359 [('I', 'include', [], _('include names matching the given patterns')),
2375 2360 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2376 2361 ('A', 'after', None, _('record a rename that has already occurred')),
2377 2362 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2378 2363 _('hg rename [OPTION]... [SOURCE]... DEST')),
2379 2364 "^revert":
2380 2365 (revert,
2381 2366 [('I', 'include', [], _('include names matching the given patterns')),
2382 2367 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2383 2368 ("r", "rev", "", _("revision to revert to"))],
2384 2369 _("hg revert [-n] [-r REV] [NAME]...")),
2385 2370 "root": (root, [], _("hg root")),
2386 2371 "^serve":
2387 2372 (serve,
2388 2373 [('A', 'accesslog', '', _('name of access log file to write to')),
2389 2374 ('E', 'errorlog', '', _('name of error log file to write to')),
2390 2375 ('p', 'port', 0, _('port to use (default: 8000)')),
2391 2376 ('a', 'address', '', _('address to use')),
2392 2377 ('n', 'name', "", _('name to show in web pages (default: working dir)')),
2393 2378 ('', 'stdio', None, _('for remote clients')),
2394 2379 ('t', 'templates', "", _('web templates to use')),
2395 2380 ('', 'style', "", _('template style to use')),
2396 2381 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2397 2382 _("hg serve [OPTION]...")),
2398 2383 "^status|st":
2399 2384 (status,
2400 2385 [('m', 'modified', None, _('show only modified files')),
2401 2386 ('a', 'added', None, _('show only added files')),
2402 2387 ('r', 'removed', None, _('show only removed files')),
2403 2388 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2404 2389 ('n', 'no-status', None, _('hide status prefix')),
2405 2390 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2406 2391 ('I', 'include', [], _('include names matching the given patterns')),
2407 2392 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2408 2393 _("hg status [OPTION]... [FILE]...")),
2409 2394 "tag":
2410 2395 (tag,
2411 2396 [('l', 'local', None, _('make the tag local')),
2412 2397 ('m', 'message', "", _('message for tag commit log entry')),
2413 2398 ('d', 'date', "", _('record datecode as commit date')),
2414 2399 ('u', 'user', "", _('record user as commiter')),
2415 2400 ('r', 'rev', "", _('revision to tag'))],
2416 2401 _('hg tag [OPTION]... NAME [REV]')),
2417 2402 "tags": (tags, [], _('hg tags')),
2418 2403 "tip": (tip, [], _('hg tip')),
2419 2404 "unbundle":
2420 2405 (unbundle,
2421 2406 [],
2422 2407 _('hg unbundle FILE')),
2423 2408 "undo": (undo, [], _('hg undo')),
2424 2409 "^update|up|checkout|co":
2425 2410 (update,
2426 2411 [('b', 'branch', "", _('checkout the head of a specific branch')),
2427 2412 ('m', 'merge', None, _('allow merging of branches')),
2428 2413 ('C', 'clean', None, _('overwrite locally modified files'))],
2429 2414 _('hg update [-b TAG] [-m] [-C] [REV]')),
2430 2415 "verify": (verify, [], _('hg verify')),
2431 2416 "version": (show_version, [], _('hg version')),
2432 2417 }
2433 2418
2434 2419 globalopts = [
2435 2420 ('R', 'repository', "", _("repository root directory")),
2436 2421 ('', 'cwd', '', _("change working directory")),
2437 2422 ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
2438 2423 ('q', 'quiet', None, _("suppress output")),
2439 2424 ('v', 'verbose', None, _("enable additional output")),
2440 2425 ('', 'debug', None, _("enable debugging output")),
2441 2426 ('', 'debugger', None, _("start debugger")),
2442 2427 ('', 'traceback', None, _("print traceback on exception")),
2443 2428 ('', 'time', None, _("time how long the command takes")),
2444 2429 ('', 'profile', None, _("print command execution profile")),
2445 2430 ('', 'version', None, _("output version information and exit")),
2446 2431 ('h', 'help', None, _("display help and exit")),
2447 2432 ]
2448 2433
2449 2434 norepo = ("clone init version help debugancestor debugconfig debugdata"
2450 2435 " debugindex debugindexdot paths")
2451 2436
2452 2437 def find(cmd):
2453 2438 """Return (aliases, command table entry) for command string."""
2454 2439 choice = None
2455 2440 for e in table.keys():
2456 2441 aliases = e.lstrip("^").split("|")
2457 2442 if cmd in aliases:
2458 2443 return aliases, table[e]
2459 2444 for a in aliases:
2460 2445 if a.startswith(cmd):
2461 2446 if choice:
2462 2447 raise AmbiguousCommand(cmd)
2463 2448 else:
2464 2449 choice = aliases, table[e]
2465 2450 break
2466 2451 if choice:
2467 2452 return choice
2468 2453
2469 2454 raise UnknownCommand(cmd)
2470 2455
2471 2456 class SignalInterrupt(Exception):
2472 2457 """Exception raised on SIGTERM and SIGHUP."""
2473 2458
2474 2459 def catchterm(*args):
2475 2460 raise SignalInterrupt
2476 2461
2477 2462 def run():
2478 2463 sys.exit(dispatch(sys.argv[1:]))
2479 2464
2480 2465 class ParseError(Exception):
2481 2466 """Exception raised on errors in parsing the command line."""
2482 2467
2483 2468 def parse(ui, args):
2484 2469 options = {}
2485 2470 cmdoptions = {}
2486 2471
2487 2472 try:
2488 2473 args = fancyopts.fancyopts(args, globalopts, options)
2489 2474 except fancyopts.getopt.GetoptError, inst:
2490 2475 raise ParseError(None, inst)
2491 2476
2492 2477 if args:
2493 2478 cmd, args = args[0], args[1:]
2494 2479 aliases, i = find(cmd)
2495 2480 cmd = aliases[0]
2496 2481 defaults = ui.config("defaults", cmd)
2497 2482 if defaults:
2498 2483 args = defaults.split() + args
2499 2484 c = list(i[1])
2500 2485 else:
2501 2486 cmd = None
2502 2487 c = []
2503 2488
2504 2489 # combine global options into local
2505 2490 for o in globalopts:
2506 2491 c.append((o[0], o[1], options[o[1]], o[3]))
2507 2492
2508 2493 try:
2509 2494 args = fancyopts.fancyopts(args, c, cmdoptions)
2510 2495 except fancyopts.getopt.GetoptError, inst:
2511 2496 raise ParseError(cmd, inst)
2512 2497
2513 2498 # separate global options back out
2514 2499 for o in globalopts:
2515 2500 n = o[1]
2516 2501 options[n] = cmdoptions[n]
2517 2502 del cmdoptions[n]
2518 2503
2519 2504 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2520 2505
2521 2506 def dispatch(args):
2522 2507 signal.signal(signal.SIGTERM, catchterm)
2523 2508 try:
2524 2509 signal.signal(signal.SIGHUP, catchterm)
2525 2510 except AttributeError:
2526 2511 pass
2527 2512
2528 2513 try:
2529 2514 u = ui.ui()
2530 2515 except util.Abort, inst:
2531 2516 sys.stderr.write(_("abort: %s\n") % inst)
2532 2517 sys.exit(1)
2533 2518
2534 2519 external = []
2535 2520 for x in u.extensions():
2536 2521 def on_exception(exc, inst):
2537 2522 u.warn(_("*** failed to import extension %s\n") % x[1])
2538 2523 u.warn("%s\n" % inst)
2539 2524 if "--traceback" in sys.argv[1:]:
2540 2525 traceback.print_exc()
2541 2526 if x[1]:
2542 2527 try:
2543 2528 mod = imp.load_source(x[0], x[1])
2544 2529 except Exception, inst:
2545 2530 on_exception(Exception, inst)
2546 2531 continue
2547 2532 else:
2548 2533 def importh(name):
2549 2534 mod = __import__(name)
2550 2535 components = name.split('.')
2551 2536 for comp in components[1:]:
2552 2537 mod = getattr(mod, comp)
2553 2538 return mod
2554 2539 try:
2555 2540 mod = importh(x[0])
2556 2541 except Exception, inst:
2557 2542 on_exception(Exception, inst)
2558 2543 continue
2559 2544
2560 2545 external.append(mod)
2561 2546 for x in external:
2562 2547 cmdtable = getattr(x, 'cmdtable', {})
2563 2548 for t in cmdtable:
2564 2549 if t in table:
2565 2550 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2566 2551 table.update(cmdtable)
2567 2552
2568 2553 try:
2569 2554 cmd, func, args, options, cmdoptions = parse(u, args)
2570 2555 except ParseError, inst:
2571 2556 if inst.args[0]:
2572 2557 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2573 2558 help_(u, inst.args[0])
2574 2559 else:
2575 2560 u.warn(_("hg: %s\n") % inst.args[1])
2576 2561 help_(u, 'shortlist')
2577 2562 sys.exit(-1)
2578 2563 except AmbiguousCommand, inst:
2579 2564 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2580 2565 sys.exit(1)
2581 2566 except UnknownCommand, inst:
2582 2567 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2583 2568 help_(u, 'shortlist')
2584 2569 sys.exit(1)
2585 2570
2586 2571 if options["time"]:
2587 2572 def get_times():
2588 2573 t = os.times()
2589 2574 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2590 2575 t = (t[0], t[1], t[2], t[3], time.clock())
2591 2576 return t
2592 2577 s = get_times()
2593 2578 def print_time():
2594 2579 t = get_times()
2595 2580 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2596 2581 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2597 2582 atexit.register(print_time)
2598 2583
2599 2584 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2600 2585 not options["noninteractive"])
2601 2586
2602 2587 # enter the debugger before command execution
2603 2588 if options['debugger']:
2604 2589 pdb.set_trace()
2605 2590
2606 2591 try:
2607 2592 try:
2608 2593 if options['help']:
2609 2594 help_(u, cmd, options['version'])
2610 2595 sys.exit(0)
2611 2596 elif options['version']:
2612 2597 show_version(u)
2613 2598 sys.exit(0)
2614 2599 elif not cmd:
2615 2600 help_(u, 'shortlist')
2616 2601 sys.exit(0)
2617 2602
2618 2603 if options['cwd']:
2619 2604 try:
2620 2605 os.chdir(options['cwd'])
2621 2606 except OSError, inst:
2622 2607 raise util.Abort('%s: %s' %
2623 2608 (options['cwd'], inst.strerror))
2624 2609
2625 2610 if cmd not in norepo.split():
2626 2611 path = options["repository"] or ""
2627 2612 repo = hg.repository(ui=u, path=path)
2628 2613 for x in external:
2629 2614 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2630 2615 d = lambda: func(u, repo, *args, **cmdoptions)
2631 2616 else:
2632 2617 d = lambda: func(u, *args, **cmdoptions)
2633 2618
2634 2619 if options['profile']:
2635 2620 import hotshot, hotshot.stats
2636 2621 prof = hotshot.Profile("hg.prof")
2637 2622 r = prof.runcall(d)
2638 2623 prof.close()
2639 2624 stats = hotshot.stats.load("hg.prof")
2640 2625 stats.strip_dirs()
2641 2626 stats.sort_stats('time', 'calls')
2642 2627 stats.print_stats(40)
2643 2628 return r
2644 2629 else:
2645 2630 return d()
2646 2631 except:
2647 2632 # enter the debugger when we hit an exception
2648 2633 if options['debugger']:
2649 2634 pdb.post_mortem(sys.exc_info()[2])
2650 2635 if options['traceback']:
2651 2636 traceback.print_exc()
2652 2637 raise
2653 2638 except hg.RepoError, inst:
2654 2639 u.warn(_("abort: "), inst, "!\n")
2655 2640 except revlog.RevlogError, inst:
2656 2641 u.warn(_("abort: "), inst, "!\n")
2657 2642 except SignalInterrupt:
2658 2643 u.warn(_("killed!\n"))
2659 2644 except KeyboardInterrupt:
2660 2645 try:
2661 2646 u.warn(_("interrupted!\n"))
2662 2647 except IOError, inst:
2663 2648 if inst.errno == errno.EPIPE:
2664 2649 if u.debugflag:
2665 2650 u.warn(_("\nbroken pipe\n"))
2666 2651 else:
2667 2652 raise
2668 2653 except IOError, inst:
2669 2654 if hasattr(inst, "code"):
2670 2655 u.warn(_("abort: %s\n") % inst)
2671 2656 elif hasattr(inst, "reason"):
2672 2657 u.warn(_("abort: error: %s\n") % inst.reason[1])
2673 2658 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2674 2659 if u.debugflag:
2675 2660 u.warn(_("broken pipe\n"))
2676 2661 elif getattr(inst, "strerror", None):
2677 2662 if getattr(inst, "filename", None):
2678 2663 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2679 2664 else:
2680 2665 u.warn(_("abort: %s\n") % inst.strerror)
2681 2666 else:
2682 2667 raise
2683 2668 except OSError, inst:
2684 2669 if hasattr(inst, "filename"):
2685 2670 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2686 2671 else:
2687 2672 u.warn(_("abort: %s\n") % inst.strerror)
2688 2673 except util.Abort, inst:
2689 2674 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2690 2675 sys.exit(1)
2691 2676 except TypeError, inst:
2692 2677 # was this an argument error?
2693 2678 tb = traceback.extract_tb(sys.exc_info()[2])
2694 2679 if len(tb) > 2: # no
2695 2680 raise
2696 2681 u.debug(inst, "\n")
2697 2682 u.warn(_("%s: invalid arguments\n") % cmd)
2698 2683 help_(u, cmd)
2699 2684 except AmbiguousCommand, inst:
2700 2685 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2701 2686 help_(u, 'shortlist')
2702 2687 except UnknownCommand, inst:
2703 2688 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2704 2689 help_(u, 'shortlist')
2705 2690 except SystemExit:
2706 2691 # don't catch this in the catch-all below
2707 2692 raise
2708 2693 except:
2709 2694 u.warn(_("** unknown exception encountered, details follow\n"))
2710 2695 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2711 2696 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2712 2697 % version.get_version())
2713 2698 raise
2714 2699
2715 2700 sys.exit(-1)
@@ -1,250 +1,247 b''
1 1 Mercurial Distributed SCM
2 2
3 3 basic commands (use "hg help" for the full list or option "-v" for details):
4 4
5 5 add add the specified files on the next commit
6 6 annotate show changeset information per file line
7 7 clone make a copy of an existing repository
8 8 commit commit the specified files or all outstanding changes
9 diff diff working directory (or selected files)
9 diff diff repository (or selected files)
10 10 export dump the header and diffs for one or more changesets
11 11 init create a new repository in the given directory
12 12 log show revision history of entire repository or files
13 13 parents show the parents of the working dir or revision
14 14 pull pull changes from the specified source
15 15 push push changes to the specified destination
16 16 remove remove the specified files on the next commit
17 17 revert revert modified files or dirs back to their unmodified states
18 18 serve export the repository via HTTP
19 19 status show changed files in the working directory
20 20 update update or merge working directory
21 21 add add the specified files on the next commit
22 22 annotate show changeset information per file line
23 23 clone make a copy of an existing repository
24 24 commit commit the specified files or all outstanding changes
25 diff diff working directory (or selected files)
25 diff diff repository (or selected files)
26 26 export dump the header and diffs for one or more changesets
27 27 init create a new repository in the given directory
28 28 log show revision history of entire repository or files
29 29 parents show the parents of the working dir or revision
30 30 pull pull changes from the specified source
31 31 push push changes to the specified destination
32 32 remove remove the specified files on the next commit
33 33 revert revert modified files or dirs back to their unmodified states
34 34 serve export the repository via HTTP
35 35 status show changed files in the working directory
36 36 update update or merge working directory
37 37 Mercurial Distributed SCM
38 38
39 39 list of commands (use "hg help -v" to show aliases and global options):
40 40
41 41 add add the specified files on the next commit
42 42 addremove add all new files, delete all missing files
43 43 annotate show changeset information per file line
44 44 bundle create a changegroup file
45 45 cat output the latest or given revisions of files
46 46 clone make a copy of an existing repository
47 47 commit commit the specified files or all outstanding changes
48 48 copy mark files as copied for the next commit
49 diff diff working directory (or selected files)
49 diff diff repository (or selected files)
50 50 export dump the header and diffs for one or more changesets
51 51 forget don't add the specified files on the next commit
52 52 grep search for a pattern in specified files and revisions
53 53 heads show current repository heads
54 54 help show help for a given command or all commands
55 55 identify print information about the working copy
56 56 import import an ordered set of patches
57 57 incoming show new changesets found in source
58 58 init create a new repository in the given directory
59 59 locate locate files matching specific patterns
60 60 log show revision history of entire repository or files
61 61 manifest output the latest or given revision of the project manifest
62 62 outgoing show changesets not found in destination
63 63 parents show the parents of the working dir or revision
64 64 paths show definition of symbolic path names
65 65 pull pull changes from the specified source
66 66 push push changes to the specified destination
67 67 rawcommit raw commit interface
68 68 recover roll back an interrupted transaction
69 69 remove remove the specified files on the next commit
70 70 rename rename files; equivalent of copy + remove
71 71 revert revert modified files or dirs back to their unmodified states
72 72 root print the root (top) of the current working dir
73 73 serve export the repository via HTTP
74 74 status show changed files in the working directory
75 75 tag add a tag for the current tip or a given revision
76 76 tags list repository tags
77 77 tip show the tip revision
78 78 unbundle apply a changegroup file
79 79 undo undo the last commit or pull
80 80 update update or merge working directory
81 81 verify verify the integrity of the repository
82 82 version output version and copyright information
83 83 add add the specified files on the next commit
84 84 addremove add all new files, delete all missing files
85 85 annotate show changeset information per file line
86 86 bundle create a changegroup file
87 87 cat output the latest or given revisions of files
88 88 clone make a copy of an existing repository
89 89 commit commit the specified files or all outstanding changes
90 90 copy mark files as copied for the next commit
91 diff diff working directory (or selected files)
91 diff diff repository (or selected files)
92 92 export dump the header and diffs for one or more changesets
93 93 forget don't add the specified files on the next commit
94 94 grep search for a pattern in specified files and revisions
95 95 heads show current repository heads
96 96 help show help for a given command or all commands
97 97 identify print information about the working copy
98 98 import import an ordered set of patches
99 99 incoming show new changesets found in source
100 100 init create a new repository in the given directory
101 101 locate locate files matching specific patterns
102 102 log show revision history of entire repository or files
103 103 manifest output the latest or given revision of the project manifest
104 104 outgoing show changesets not found in destination
105 105 parents show the parents of the working dir or revision
106 106 paths show definition of symbolic path names
107 107 pull pull changes from the specified source
108 108 push push changes to the specified destination
109 109 rawcommit raw commit interface
110 110 recover roll back an interrupted transaction
111 111 remove remove the specified files on the next commit
112 112 rename rename files; equivalent of copy + remove
113 113 revert revert modified files or dirs back to their unmodified states
114 114 root print the root (top) of the current working dir
115 115 serve export the repository via HTTP
116 116 status show changed files in the working directory
117 117 tag add a tag for the current tip or a given revision
118 118 tags list repository tags
119 119 tip show the tip revision
120 120 unbundle apply a changegroup file
121 121 undo undo the last commit or pull
122 122 update update or merge working directory
123 123 verify verify the integrity of the repository
124 124 version output version and copyright information
125 125 hg add [OPTION]... [FILE]...
126 126
127 127 add the specified files on the next commit
128 128
129 129 Schedule files to be version controlled and added to the repository.
130 130
131 131 The files will be added to the repository at the next commit.
132 132
133 If no names are given, add all files in the current directory and
134 its subdirectories.
133 If no names are given, add all files in the repository.
135 134
136 135 options:
137 136
138 137 -I --include include names matching the given patterns
139 138 -X --exclude exclude names matching the given patterns
140 139 hg add: option --skjdfks not recognized
141 140 hg add [OPTION]... [FILE]...
142 141
143 142 add the specified files on the next commit
144 143
145 144 Schedule files to be version controlled and added to the repository.
146 145
147 146 The files will be added to the repository at the next commit.
148 147
149 If no names are given, add all files in the current directory and
150 its subdirectories.
148 If no names are given, add all files in the repository.
151 149
152 150 options:
153 151
154 152 -I --include include names matching the given patterns
155 153 -X --exclude exclude names matching the given patterns
156 154 hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...
157 155
158 diff working directory (or selected files)
156 diff repository (or selected files)
159 157
160 158 Show differences between revisions for the specified files.
161 159
162 160 Differences between files are shown using the unified diff format.
163 161
164 162 When two revision arguments are given, then changes are shown
165 163 between those revisions. If only one revision is specified then
166 164 that revision is compared to the working directory, and, when no
167 165 revisions are specified, the working directory files are compared
168 166 to its parent.
169 167
170 168 Without the -a option, diff will avoid generating diffs of files
171 169 it detects as binary. With -a, diff will generate a diff anyway,
172 170 probably with undesirable results.
173 171
174 172 options:
175 173
176 174 -r --rev revision
177 175 -a --text treat all files as text
178 176 -I --include include names matching the given patterns
179 177 -X --exclude exclude names matching the given patterns
180 178 hg status [OPTION]... [FILE]...
181 179
182 180 show changed files in the working directory
183 181
184 Show changed files in the working directory. If no names are
185 given, all files are shown. Otherwise, only files matching the
186 given names are shown.
182 Show changed files in the repository. If names are
183 given, only files that match are shown.
187 184
188 185 The codes used to show the status of files are:
189 186 M = modified
190 187 A = added
191 188 R = removed
192 189 ? = not tracked
193 190
194 191 aliases: st
195 192
196 193 options:
197 194
198 195 -m --modified show only modified files
199 196 -a --added show only added files
200 197 -r --removed show only removed files
201 198 -u --unknown show only unknown (not tracked) files
202 199 -n --no-status hide status prefix
203 200 -0 --print0 end filenames with NUL, for use with xargs
204 201 -I --include include names matching the given patterns
205 202 -X --exclude exclude names matching the given patterns
206 203 hg status [OPTION]... [FILE]...
207 204
208 205 show changed files in the working directory
209 206 hg: unknown command 'foo'
210 207 Mercurial Distributed SCM
211 208
212 209 basic commands (use "hg help" for the full list or option "-v" for details):
213 210
214 211 add add the specified files on the next commit
215 212 annotate show changeset information per file line
216 213 clone make a copy of an existing repository
217 214 commit commit the specified files or all outstanding changes
218 diff diff working directory (or selected files)
215 diff diff repository (or selected files)
219 216 export dump the header and diffs for one or more changesets
220 217 init create a new repository in the given directory
221 218 log show revision history of entire repository or files
222 219 parents show the parents of the working dir or revision
223 220 pull pull changes from the specified source
224 221 push push changes to the specified destination
225 222 remove remove the specified files on the next commit
226 223 revert revert modified files or dirs back to their unmodified states
227 224 serve export the repository via HTTP
228 225 status show changed files in the working directory
229 226 update update or merge working directory
230 227 hg: unknown command 'skjdfks'
231 228 Mercurial Distributed SCM
232 229
233 230 basic commands (use "hg help" for the full list or option "-v" for details):
234 231
235 232 add add the specified files on the next commit
236 233 annotate show changeset information per file line
237 234 clone make a copy of an existing repository
238 235 commit commit the specified files or all outstanding changes
239 diff diff working directory (or selected files)
236 diff diff repository (or selected files)
240 237 export dump the header and diffs for one or more changesets
241 238 init create a new repository in the given directory
242 239 log show revision history of entire repository or files
243 240 parents show the parents of the working dir or revision
244 241 pull pull changes from the specified source
245 242 push push changes to the specified destination
246 243 remove remove the specified files on the next commit
247 244 revert revert modified files or dirs back to their unmodified states
248 245 serve export the repository via HTTP
249 246 status show changed files in the working directory
250 247 update update or merge working directory
@@ -1,45 +1,45 b''
1 1 #!/bin/sh
2 2
3 3 hg init
4 4 touch a.o
5 5 touch a.c
6 6 touch syntax
7 7 mkdir dir
8 8 touch dir/a.o
9 9 touch dir/b.o
10 10 touch dir/c.o
11 11
12 12 hg add dir/a.o
13 13 hg commit -m 0
14 14 hg add dir/b.o
15 15
16 16 echo "--" ; hg status
17 17
18 18 echo "*.o" > .hgignore
19 19 echo "--" ; hg status
20 20
21 21 echo ".*\.o" > .hgignore
22 22 echo "--" ; hg status
23 23
24 24 # XXX: broken
25 25 #echo "glob:**.o" > .hgignore
26 26 #echo "--" ; hg status
27 27 #
28 28 #echo "glob:*.o" > .hgignore
29 29 #echo "--" ; hg status
30 30
31 31 echo "syntax: invalid" > .hgignore
32 32 echo "--" ; hg status
33 33
34 34 echo "syntax: glob" > .hgignore
35 35 echo "*.o" >> .hgignore
36 36 echo "--" ; hg status
37 37
38 38 echo "relglob:syntax*" > .hgignore
39 39 echo "--" ; hg status
40 40
41 41 echo "relglob:*" > .hgignore
42 42 echo "--" ; hg status
43 43
44 44 cd dir
45 echo "--" ; hg status
45 echo "--" ; hg status .
@@ -1,55 +1,55 b''
1 1 #!/bin/sh
2 2
3 3 mkdir t
4 4 cd t
5 5 hg init
6 6 mkdir -p beans
7 7 for b in kidney navy turtle borlotti black pinto; do
8 8 echo $b > beans/$b
9 9 done
10 10 mkdir -p mammals/Procyonidae
11 11 for m in cacomistle coatimundi raccoon; do
12 12 echo $m > mammals/Procyonidae/$m
13 13 done
14 14 echo skunk > mammals/skunk
15 15 echo fennel > fennel
16 16 echo fenugreek > fenugreek
17 17 echo fiddlehead > fiddlehead
18 18 echo glob:glob > glob:glob
19 19 hg addremove
20 20 hg commit -m "commit #0" -d "0 0"
21 21 hg debugwalk
22 22 cd mammals
23 hg debugwalk
23 hg debugwalk .
24 24 hg debugwalk Procyonidae
25 25 cd Procyonidae
26 hg debugwalk
26 hg debugwalk .
27 27 hg debugwalk ..
28 28 cd ..
29 29 hg debugwalk ../beans
30 hg debugwalk
30 hg debugwalk .
31 31 cd ..
32 32 hg debugwalk -Ibeans
33 33 hg debugwalk 'glob:mammals/../beans/b*'
34 34 hg debugwalk '-X*/Procyonidae' mammals
35 35 hg debugwalk path:mammals
36 36 hg debugwalk ..
37 37 hg debugwalk beans/../..
38 38 # Don't know how to test absolute paths without always getting a false
39 39 # error.
40 40 #hg debugwalk `pwd`/beans
41 41 #hg debugwalk `pwd`/..
42 42 hg debugwalk glob:\*
43 43 hg debugwalk 're:.*[kb]$'
44 44 hg debugwalk path:beans/black
45 45 hg debugwalk beans 'glob:beans/*'
46 46 hg debugwalk 'glob:j*'
47 47 hg debugwalk NOEXIST
48 48 mkfifo fifo
49 49 hg debugwalk fifo
50 50 rm fenugreek
51 51 hg debugwalk fenugreek
52 52 hg rm fenugreek
53 53 hg debugwalk fenugreek
54 54 touch new
55 55 hg debugwalk new
General Comments 0
You need to be logged in to leave comments. Login now