##// END OF EJS Templates
A bunch of parsing/help updates...
mpm@selenic.com -
r596:9a8daeff default
parent child Browse files
Show More
@@ -1,1108 +1,1129 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 import os, re, sys, signal
9 9 import fancyopts, ui, hg, util
10 10 from demandload import *
11 11 demandload(globals(), "mdiff time hgweb traceback random signal errno version")
12 12
13 13 class UnknownCommand(Exception): pass
14 14
15 15 def filterfiles(filters, files):
16 16 l = [ x for x in files if x in filters ]
17 17
18 18 for t in filters:
19 19 if t and t[-1] != "/": t += "/"
20 20 l += [ x for x in files if x.startswith(t) ]
21 21 return l
22 22
23 23 def relfilter(repo, files):
24 24 if os.getcwd() != repo.root:
25 25 p = os.getcwd()[len(repo.root) + 1: ]
26 26 return filterfiles([util.pconvert(p)], files)
27 27 return files
28 28
29 29 def relpath(repo, args):
30 30 if os.getcwd() != repo.root:
31 31 p = os.getcwd()[len(repo.root) + 1: ]
32 32 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
33 33 for x in args ]
34 34 return args
35 35
36 36 revrangesep = ':'
37 37
38 38 def revrange(ui, repo, revs = [], revlog = None):
39 39 if revlog is None:
40 40 revlog = repo.changelog
41 41 revcount = revlog.count()
42 42 def fix(val, defval):
43 43 if not val: return defval
44 44 try:
45 45 num = int(val)
46 46 if str(num) != val: raise ValueError
47 47 if num < 0: num += revcount
48 48 if not (0 <= num < revcount):
49 49 raise ValueError
50 50 except ValueError:
51 51 try:
52 52 num = repo.changelog.rev(repo.lookup(val))
53 53 except KeyError:
54 54 try:
55 55 num = revlog.rev(revlog.lookup(val))
56 56 except KeyError:
57 57 ui.warn('abort: invalid revision identifier %s\n' % val)
58 58 sys.exit(1)
59 59 return num
60 60 for spec in revs:
61 61 if spec.find(revrangesep) >= 0:
62 62 start, end = spec.split(revrangesep, 1)
63 63 start = fix(start, 0)
64 64 end = fix(end, revcount - 1)
65 65 if end > start:
66 66 end += 1
67 67 step = 1
68 68 else:
69 69 end -= 1
70 70 step = -1
71 71 for rev in xrange(start, end, step):
72 72 yield str(rev)
73 73 else:
74 74 yield spec
75 75
76 76 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
77 77 def date(c):
78 78 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
79 79
80 80 (c, a, d, u) = repo.changes(node1, node2, files)
81 81 if files:
82 82 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
83 83
84 84 if not c and not a and not d:
85 85 return
86 86
87 87 if node2:
88 88 change = repo.changelog.read(node2)
89 89 mmap2 = repo.manifest.read(change[0])
90 90 def read(f): return repo.file(f).read(mmap2[f])
91 91 date2 = date(change)
92 92 else:
93 93 date2 = time.asctime()
94 94 if not node1:
95 95 node1 = repo.dirstate.parents()[0]
96 96 def read(f): return repo.wfile(f).read()
97 97
98 98 if ui.quiet:
99 99 r = None
100 100 else:
101 101 hexfunc = ui.verbose and hg.hex or hg.short
102 102 r = [hexfunc(node) for node in [node1, node2] if node]
103 103
104 104 change = repo.changelog.read(node1)
105 105 mmap = repo.manifest.read(change[0])
106 106 date1 = date(change)
107 107
108 108 for f in c:
109 109 to = None
110 110 if f in mmap:
111 111 to = repo.file(f).read(mmap[f])
112 112 tn = read(f)
113 113 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
114 114 for f in a:
115 115 to = None
116 116 tn = read(f)
117 117 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
118 118 for f in d:
119 119 to = repo.file(f).read(mmap[f])
120 120 tn = None
121 121 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
122 122
123 123 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
124 124 """show a single changeset or file revision"""
125 125 changelog = repo.changelog
126 126 if filelog:
127 127 log = filelog
128 128 filerev = rev
129 129 node = filenode = filelog.node(filerev)
130 130 changerev = filelog.linkrev(filenode)
131 131 changenode = changenode or changelog.node(changerev)
132 132 else:
133 133 log = changelog
134 134 changerev = rev
135 135 if changenode is None:
136 136 changenode = changelog.node(changerev)
137 137 elif not changerev:
138 138 rev = changerev = changelog.rev(changenode)
139 139 node = changenode
140 140
141 141 if ui.quiet:
142 142 ui.write("%d:%s\n" % (rev, hg.hex(node)))
143 143 return
144 144
145 145 changes = changelog.read(changenode)
146 146
147 147 parents = [(log.rev(parent), hg.hex(parent))
148 148 for parent in log.parents(node)
149 149 if ui.debugflag or parent != hg.nullid]
150 150 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
151 151 parents = []
152 152
153 153 if filelog:
154 154 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
155 155 for parent in parents:
156 156 ui.write("parent: %d:%s\n" % parent)
157 157 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
158 158 else:
159 159 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
160 160 for tag in repo.nodetags(changenode):
161 161 ui.status("tag: %s\n" % tag)
162 162 for parent in parents:
163 163 ui.write("parent: %d:%s\n" % parent)
164 164 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
165 165 hg.hex(changes[0])))
166 166 ui.status("user: %s\n" % changes[1])
167 167 ui.status("date: %s\n" % time.asctime(
168 168 time.localtime(float(changes[2].split(' ')[0]))))
169 169 if ui.debugflag:
170 170 files = repo.changes(changelog.parents(changenode)[0], changenode)
171 171 for key, value in zip(["files:", "files+:", "files-:"], files):
172 172 if value:
173 173 ui.note("%-12s %s\n" % (key, " ".join(value)))
174 174 else:
175 175 ui.note("files: %s\n" % " ".join(changes[3]))
176 176 description = changes[4].strip()
177 177 if description:
178 178 if ui.verbose:
179 179 ui.status("description:\n")
180 180 ui.status(description)
181 181 ui.status("\n\n")
182 182 else:
183 183 ui.status("summary: %s\n" % description.splitlines()[0])
184 184 ui.status("\n")
185 185
186 186 def show_version(ui):
187 187 """output version and copyright information"""
188 188 ui.write("Mercurial version %s\n" % version.get_version())
189 189 ui.status(
190 190 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
191 191 "This is free software; see the source for copying conditions. "
192 192 "There is NO\nwarranty; "
193 193 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
194 194 )
195 195
196 196 def help(ui, cmd=None):
197 197 '''show help for a given command or all commands'''
198 198 if cmd:
199 199 try:
200 200 i = find(cmd)
201 201 ui.write("%s\n\n" % i[2])
202 202
203 203 if i[1]:
204 204 for s, l, d, c in i[1]:
205 205 opt=' '
206 206 if s: opt = opt + '-' + s + ' '
207 207 if l: opt = opt + '--' + l + ' '
208 208 if d: opt = opt + '(' + str(d) + ')'
209 209 ui.write(opt, "\n")
210 210 if c: ui.write(' %s\n' % c)
211 211 ui.write("\n")
212 212
213 213 ui.write(i[0].__doc__, "\n")
214 214 except UnknownCommand:
215 215 ui.warn("hg: unknown command %s\n" % cmd)
216 216 sys.exit(0)
217 217 else:
218 218 if ui.verbose:
219 219 show_version(ui)
220 220 ui.write('\n')
221 221 if ui.verbose:
222 222 ui.write('hg commands:\n\n')
223 223 else:
224 ui.write('basic hg commands (use -v for long list):\n\n')
224 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
225 225
226 226 h = {}
227 227 for c, e in table.items():
228 228 f = c.split("|")[0]
229 229 if not ui.verbose and not f.startswith("^"):
230 230 continue
231 231 if not ui.debugflag and f.startswith("debug"):
232 232 continue
233 233 f = f.lstrip("^")
234 234 d = ""
235 235 if e[0].__doc__:
236 236 d = e[0].__doc__.splitlines(0)[0].rstrip()
237 237 h[f] = d
238 238
239 239 fns = h.keys()
240 240 fns.sort()
241 241 m = max(map(len, fns))
242 242 for f in fns:
243 243 ui.write(' %-*s %s\n' % (m, f, h[f]))
244 244
245 245 # Commands start here, listed alphabetically
246 246
247 247 def add(ui, repo, file, *files):
248 248 '''add the specified files on the next commit'''
249 249 repo.add(relpath(repo, (file,) + files))
250 250
251 251 def addremove(ui, repo, *files):
252 252 """add all new files, delete all missing files"""
253 253 if files:
254 254 files = relpath(repo, files)
255 255 d = []
256 256 u = []
257 257 for f in files:
258 258 p = repo.wjoin(f)
259 259 s = repo.dirstate.state(f)
260 260 isfile = os.path.isfile(p)
261 261 if s != 'r' and not isfile:
262 262 d.append(f)
263 263 elif s not in 'nmai' and isfile:
264 264 u.append(f)
265 265 else:
266 266 (c, a, d, u) = repo.changes(None, None)
267 267 repo.add(u)
268 268 repo.remove(d)
269 269
270 270 def annotate(u, repo, file, *files, **ops):
271 271 """show changeset information per file line"""
272 272 def getnode(rev):
273 273 return hg.short(repo.changelog.node(rev))
274 274
275 275 def getname(rev):
276 276 try:
277 277 return bcache[rev]
278 278 except KeyError:
279 279 cl = repo.changelog.read(repo.changelog.node(rev))
280 280 name = cl[1]
281 281 f = name.find('@')
282 282 if f >= 0:
283 283 name = name[:f]
284 284 f = name.find('<')
285 285 if f >= 0:
286 286 name = name[f+1:]
287 287 bcache[rev] = name
288 288 return name
289 289
290 290 bcache = {}
291 291 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
292 292 if not ops['user'] and not ops['changeset']:
293 293 ops['number'] = 1
294 294
295 295 node = repo.dirstate.parents()[0]
296 296 if ops['revision']:
297 297 node = repo.changelog.lookup(ops['revision'])
298 298 change = repo.changelog.read(node)
299 299 mmap = repo.manifest.read(change[0])
300 300 for f in relpath(repo, (file,) + files):
301 301 lines = repo.file(f).annotate(mmap[f])
302 302 pieces = []
303 303
304 304 for o, f in opmap:
305 305 if ops[o]:
306 306 l = [ f(n) for n,t in lines ]
307 307 m = max(map(len, l))
308 308 pieces.append([ "%*s" % (m, x) for x in l])
309 309
310 310 for p,l in zip(zip(*pieces), lines):
311 311 u.write(" ".join(p) + ": " + l[1])
312 312
313 313 def cat(ui, repo, file, rev = []):
314 314 """output the latest or given revision of a file"""
315 315 r = repo.file(relpath(repo, [file])[0])
316 316 n = r.tip()
317 317 if rev: n = r.lookup(rev)
318 318 sys.stdout.write(r.read(n))
319 319
320 320 def clone(ui, source, dest = None, **opts):
321 321 """make a copy of an existing repository"""
322 322 source = ui.expandpath(source)
323 323
324 324 if dest is None:
325 325 dest = os.path.basename(os.path.normpath(source))
326 326
327 327 if os.path.exists(dest):
328 328 ui.warn("abort: destination '%s' already exists\n" % dest)
329 329 return 1
330 330
331 331 class dircleanup:
332 332 def __init__(self, dir):
333 333 self.dir = dir
334 334 os.mkdir(dir)
335 335 def close(self):
336 336 self.dir = None
337 337 def __del__(self):
338 338 if self.dir:
339 339 import shutil
340 340 shutil.rmtree(self.dir, True)
341 341
342 342 d = dircleanup(dest)
343 343
344 344 link = 0
345 345 abspath = source
346 346 if not (source.startswith("http://") or
347 347 source.startswith("hg://") or
348 348 source.startswith("old-http://")):
349 349 abspath = os.path.abspath(source)
350 350 d1 = os.stat(dest).st_dev
351 351 d2 = os.stat(source).st_dev
352 352 if d1 == d2: link = 1
353 353
354 354 if link:
355 355 ui.note("copying by hardlink\n")
356 356 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
357 357 try:
358 358 os.remove(os.path.join(dest, ".hg", "dirstate"))
359 359 except: pass
360 360
361 361 repo = hg.repository(ui, dest)
362 362
363 363 else:
364 364 repo = hg.repository(ui, dest, create=1)
365 365 other = hg.repository(ui, source)
366 366 fetch = repo.findincoming(other)
367 367 if fetch:
368 368 cg = other.changegroup(fetch)
369 369 repo.addchangegroup(cg)
370 370
371 371 f = repo.opener("hgrc", "w")
372 372 f.write("[paths]\n")
373 373 f.write("default = %s\n" % abspath)
374 374
375 375 if not opts['noupdate']:
376 376 update(ui, repo)
377 377
378 378 d.close()
379 379
380 380 def commit(ui, repo, *files, **opts):
381 381 """commit the specified files or all outstanding changes"""
382 382 text = opts['text']
383 383 if not text and opts['logfile']:
384 384 try: text = open(opts['logfile']).read()
385 385 except IOError: pass
386 386
387 387 if opts['addremove']:
388 388 addremove(ui, repo, *files)
389 389 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
390 390
391 391 def copy(ui, repo, source, dest):
392 392 """mark a file as copied or renamed for the next commit"""
393 393 return repo.copy(*relpath(repo, (source, dest)))
394 394
395 def debugcheckdirstate(ui, repo):
395 def debugcheckstate(ui, repo):
396 """validate the correctness of the current dirstate"""
396 397 parent1, parent2 = repo.dirstate.parents()
397 398 repo.dirstate.read()
398 399 dc = repo.dirstate.map
399 400 keys = dc.keys()
400 401 keys.sort()
401 402 m1n = repo.changelog.read(parent1)[0]
402 403 m2n = repo.changelog.read(parent2)[0]
403 404 m1 = repo.manifest.read(m1n)
404 405 m2 = repo.manifest.read(m2n)
405 406 errors = 0
406 407 for f in dc:
407 408 state = repo.dirstate.state(f)
408 409 if state in "nr" and f not in m1:
409 410 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
410 411 errors += 1
411 412 if state in "a" and f in m1:
412 413 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
413 414 errors += 1
414 415 if state in "m" and f not in m1 and f not in m2:
415 416 ui.warn("%s in state %s, but not in either manifest\n" %
416 417 (f, state))
417 418 errors += 1
418 419 for f in m1:
419 420 state = repo.dirstate.state(f)
420 421 if state not in "nrm":
421 422 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
422 423 errors += 1
423 424 if errors:
424 425 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
425 426 sys.exit(1)
426 427
427 def debugdumpdirstate(ui, repo):
428 def debugstate(ui, repo):
429 """show the contents of the current dirstate"""
428 430 repo.dirstate.read()
429 431 dc = repo.dirstate.map
430 432 keys = dc.keys()
431 433 keys.sort()
432 434 for file in keys:
433 435 ui.write("%c %s\n" % (dc[file][0], file))
434 436
435 437 def debugindex(ui, file):
438 """dump the contents of an index file"""
436 439 r = hg.revlog(hg.opener(""), file, "")
437 440 ui.write(" rev offset length base linkrev" +
438 441 " p1 p2 nodeid\n")
439 442 for i in range(r.count()):
440 443 e = r.index[i]
441 444 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
442 445 i, e[0], e[1], e[2], e[3],
443 446 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
444 447
445 448 def debugindexdot(ui, file):
449 """dump an index DAG as a .dot file"""
446 450 r = hg.revlog(hg.opener(""), file, "")
447 451 ui.write("digraph G {\n")
448 452 for i in range(r.count()):
449 453 e = r.index[i]
450 454 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
451 455 if e[5] != hg.nullid:
452 456 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
453 457 ui.write("}\n")
454 458
455 459 def diff(ui, repo, *files, **opts):
456 460 """diff working directory (or selected files)"""
457 461 revs = []
458 462 if opts['rev']:
459 463 revs = map(lambda x: repo.lookup(x), opts['rev'])
460 464
461 465 if len(revs) > 2:
462 466 ui.warn("too many revisions to diff\n")
463 467 sys.exit(1)
464 468
465 469 if files:
466 470 files = relpath(repo, files)
467 471 else:
468 472 files = relpath(repo, [""])
469 473
470 474 dodiff(sys.stdout, ui, repo, files, *revs)
471 475
472 476 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
473 477 node = repo.lookup(changeset)
474 478 prev, other = repo.changelog.parents(node)
475 479 change = repo.changelog.read(node)
476 480
477 481 def expand(name):
478 482 expansions = {
479 483 '%': lambda: '%',
480 484 'H': lambda: hg.hex(node),
481 485 'N': lambda: str(total),
482 486 'R': lambda: str(repo.changelog.rev(node)),
483 487 'b': lambda: os.path.basename(repo.root),
484 488 'h': lambda: hg.short(node),
485 489 'n': lambda: str(seqno).zfill(len(str(total))),
486 490 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
487 491 }
488 492 newname = []
489 493 namelen = len(name)
490 494 i = 0
491 495 while i < namelen:
492 496 c = name[i]
493 497 if c == '%':
494 498 i += 1
495 499 c = name[i]
496 500 c = expansions[c]()
497 501 newname.append(c)
498 502 i += 1
499 503 return ''.join(newname)
500 504
501 505 if opts['output'] and opts['output'] != '-':
502 506 try:
503 507 fp = open(expand(opts['output']), 'w')
504 508 except KeyError, inst:
505 509 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
506 510 inst.args[0])
507 511 sys.exit(1)
508 512 else:
509 513 fp = sys.stdout
510 514
511 515 fp.write("# HG changeset patch\n")
512 516 fp.write("# User %s\n" % change[1])
513 517 fp.write("# Node ID %s\n" % hg.hex(node))
514 518 fp.write("# Parent %s\n" % hg.hex(prev))
515 519 if other != hg.nullid:
516 520 fp.write("# Parent %s\n" % hg.hex(other))
517 521 fp.write(change[4].rstrip())
518 522 fp.write("\n\n")
519 523
520 524 dodiff(fp, ui, repo, None, prev, node)
521 525
522 526 def export(ui, repo, *changesets, **opts):
523 527 """dump the header and diffs for one or more changesets"""
524 528 seqno = 0
525 529 revs = list(revrange(ui, repo, changesets))
526 530 total = len(revs)
527 531 revwidth = max(len(revs[0]), len(revs[-1]))
528 532 for cset in revs:
529 533 seqno += 1
530 534 doexport(ui, repo, cset, seqno, total, revwidth, opts)
531 535
532 536 def forget(ui, repo, file, *files):
533 537 """don't add the specified files on the next commit"""
534 538 repo.forget(relpath(repo, (file,) + files))
535 539
536 540 def heads(ui, repo):
537 541 """show current repository heads"""
538 542 for n in repo.changelog.heads():
539 543 show_changeset(ui, repo, changenode=n)
540 544
541 545 def identify(ui, repo):
542 546 """print information about the working copy"""
543 547 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
544 548 if not parents:
545 549 ui.write("unknown\n")
546 550 return
547 551
548 552 hexfunc = ui.verbose and hg.hex or hg.short
549 553 (c, a, d, u) = repo.changes(None, None)
550 554 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
551 555 (c or a or d) and "+" or "")]
552 556
553 557 if not ui.quiet:
554 558 # multiple tags for a single parent separated by '/'
555 559 parenttags = ['/'.join(tags)
556 560 for tags in map(repo.nodetags, parents) if tags]
557 561 # tags for multiple parents separated by ' + '
558 562 output.append(' + '.join(parenttags))
559 563
560 564 ui.write("%s\n" % ' '.join(output))
561 565
562 566 def import_(ui, repo, patch1, *patches, **opts):
563 567 """import an ordered set of patches"""
564 568 try:
565 569 import psyco
566 570 psyco.full()
567 571 except:
568 572 pass
569 573
570 574 patches = (patch1,) + patches
571 575
572 576 d = opts["base"]
573 577 strip = opts["strip"]
574 578
575 579 for patch in patches:
576 580 ui.status("applying %s\n" % patch)
577 581 pf = os.path.join(d, patch)
578 582
579 583 text = ""
580 584 for l in file(pf):
581 585 if l[:4] == "--- ": break
582 586 text += l
583 587
584 588 # make sure text isn't empty
585 589 if not text: text = "imported patch %s\n" % patch
586 590
587 591 f = os.popen("patch -p%d < %s" % (strip, pf))
588 592 files = []
589 593 for l in f.read().splitlines():
590 594 l.rstrip('\r\n');
591 595 ui.status("%s\n" % l)
592 596 if l[:14] == 'patching file ':
593 597 pf = l[14:]
594 598 if pf not in files:
595 599 files.append(pf)
596 600 patcherr = f.close()
597 601 if patcherr:
598 602 sys.stderr.write("patch failed")
599 603 sys.exit(1)
600 604
601 605 if len(files) > 0:
602 606 addremove(ui, repo, *files)
603 607 repo.commit(files, text)
604 608
605 609 def init(ui, source=None):
606 610 """create a new repository in the current directory"""
607 611
608 612 if source:
609 613 ui.warn("no longer supported: use \"hg clone\" instead\n")
610 614 sys.exit(1)
611 615 repo = hg.repository(ui, ".", create=1)
612 616
613 617 def log(ui, repo, f=None, **opts):
614 618 """show the revision history of the repository or a single file"""
615 619 if f:
616 620 filelog = repo.file(relpath(repo, [f])[0])
617 621 log = filelog
618 622 lookup = filelog.lookup
619 623 else:
620 624 filelog = None
621 625 log = repo.changelog
622 626 lookup = repo.lookup
623 627 revlist = []
624 628 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
625 629 while revs:
626 630 if len(revs) == 1:
627 631 revlist.append(revs.pop(0))
628 632 else:
629 633 a = revs.pop(0)
630 634 b = revs.pop(0)
631 635 off = a > b and -1 or 1
632 636 revlist.extend(range(a, b + off, off))
633 637 for i in revlist or range(log.count() - 1, -1, -1):
634 638 show_changeset(ui, repo, filelog=filelog, rev=i)
635 639
636 640 def manifest(ui, repo, rev = []):
637 641 """output the latest or given revision of the project manifest"""
638 642 n = repo.manifest.tip()
639 643 if rev:
640 644 n = repo.manifest.lookup(rev)
641 645 m = repo.manifest.read(n)
642 646 mf = repo.manifest.readflags(n)
643 647 files = m.keys()
644 648 files.sort()
645 649
646 650 for f in files:
647 651 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
648 652
649 653 def parents(ui, repo, node = None):
650 654 '''show the parents of the current working dir'''
651 655 if node:
652 656 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
653 657 else:
654 658 p = repo.dirstate.parents()
655 659
656 660 for n in p:
657 661 if n != hg.nullid:
658 662 show_changeset(ui, repo, changenode=n)
659 663
660 664 def pull(ui, repo, source="default", **opts):
661 665 """pull changes from the specified source"""
662 666 source = ui.expandpath(source)
663 667
664 668 ui.status('pulling from %s\n' % (source))
665 669
666 670 other = hg.repository(ui, source)
667 671 fetch = repo.findincoming(other)
668 672 if not fetch:
669 673 ui.status("no changes found\n")
670 674 return
671 675
672 676 cg = other.changegroup(fetch)
673 677 r = repo.addchangegroup(cg)
674 678 if cg and not r:
675 679 if opts['update']:
676 680 return update(ui, repo)
677 681 else:
678 682 ui.status("(run 'hg update' to get a working copy)\n")
679 683
680 684 return r
681 685
682 686 def push(ui, repo, dest="default-push"):
683 687 """push changes to the specified destination"""
684 688 dest = ui.expandpath(dest)
685 689
686 690 if not dest.startswith("ssh://"):
687 691 ui.warn("abort: can only push to ssh:// destinations currently\n")
688 692 return 1
689 693
690 694 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
691 695 if not m:
692 696 ui.warn("abort: couldn't parse destination %s\n" % dest)
693 697 return 1
694 698
695 699 user, host, port, path = map(m.group, (2, 3, 5, 7))
696 700 uhost = user and ("%s@%s" % (user, host)) or host
697 701 port = port and (" -p %s") % port or ""
698 702 path = path or ""
699 703
700 704 sport = random.randrange(30000, 60000)
701 705 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
702 706 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
703 707
704 708 child = os.fork()
705 709 if not child:
706 710 sys.stdout = file("/dev/null", "w")
707 711 sys.stderr = sys.stdout
708 712 hgweb.server(repo.root, "pull", "", "localhost", sport)
709 713 else:
710 714 ui.status("connecting to %s\n" % host)
711 715 r = os.system(cmd)
712 716 os.kill(child, signal.SIGTERM)
713 717 return r
714 718
715 719 def rawcommit(ui, repo, *flist, **rc):
716 720 "raw commit interface"
717 721
718 722 text = rc['text']
719 723 if not text and rc['logfile']:
720 724 try: text = open(rc['logfile']).read()
721 725 except IOError: pass
722 726 if not text and not rc['logfile']:
723 727 ui.warn("abort: missing commit text\n")
724 728 return 1
725 729
726 730 files = relpath(repo, list(flist))
727 731 if rc['files']:
728 732 files += open(rc['files']).read().splitlines()
729 733
730 734 rc['parent'] = map(repo.lookup, rc['parent'])
731 735
732 736 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
733 737
734 738 def recover(ui, repo):
735 739 """roll back an interrupted transaction"""
736 740 repo.recover()
737 741
738 742 def remove(ui, repo, file, *files):
739 743 """remove the specified files on the next commit"""
740 744 repo.remove(relpath(repo, (file,) + files))
741 745
742 746 def revert(ui, repo, *names, **opts):
743 747 """revert modified files or dirs back to their unmodified states"""
744 748 node = opts['rev'] and repo.lookup(opts['rev']) or \
745 749 repo.dirstate.parents()[0]
746 750 root = os.path.realpath(repo.root)
747 751
748 752 def trimpath(p):
749 753 p = os.path.realpath(p)
750 754 if p.startswith(root):
751 755 rest = p[len(root):]
752 756 if not rest:
753 757 return rest
754 758 if p.startswith(os.sep):
755 759 return rest[1:]
756 760 return p
757 761
758 762 relnames = map(trimpath, names or [os.getcwd()])
759 763 chosen = {}
760 764
761 765 def choose(name):
762 766 def body(name):
763 767 for r in relnames:
764 768 if not name.startswith(r): continue
765 769 rest = name[len(r):]
766 770 if not rest: return r, True
767 771 depth = rest.count(os.sep)
768 772 if not r:
769 773 if depth == 0 or not opts['nonrecursive']: return r, True
770 774 elif rest[0] == os.sep:
771 775 if depth == 1 or not opts['nonrecursive']: return r, True
772 776 return None, False
773 777 relname, ret = body(name)
774 778 if ret:
775 779 chosen[relname] = 1
776 780 return ret
777 781
778 782 r = repo.update(node, False, True, choose, False)
779 783 for n in relnames:
780 784 if n not in chosen:
781 785 ui.warn('error: no matches for %s\n' % n)
782 786 r = 1
783 787 sys.stdout.flush()
784 788 return r
785 789
786 790 def root(ui, repo):
787 791 """print the root (top) of the current working dir"""
788 792 ui.write(repo.root + "\n")
789 793
790 794 def serve(ui, repo, **opts):
791 795 """export the repository via HTTP"""
792 796 hgweb.server(repo.root, opts["name"], opts["templates"],
793 797 opts["address"], opts["port"])
794 798
795 799 def status(ui, repo):
796 800 '''show changed files in the working directory
797 801
798 802 C = changed
799 803 A = added
800 804 R = removed
801 805 ? = not tracked'''
802 806
803 807 (c, a, d, u) = repo.changes(None, None)
804 808 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
805 809
806 810 for f in c: ui.write("C ", f, "\n")
807 811 for f in a: ui.write("A ", f, "\n")
808 812 for f in d: ui.write("R ", f, "\n")
809 813 for f in u: ui.write("? ", f, "\n")
810 814
811 815 def tag(ui, repo, name, rev = None, **opts):
812 816 """add a tag for the current tip or a given revision"""
813 817
814 818 if name == "tip":
815 819 ui.warn("abort: 'tip' is a reserved name!\n")
816 820 return -1
817 821 if name.find(revrangesep) >= 0:
818 822 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
819 823 return -1
820 824
821 825 (c, a, d, u) = repo.changes(None, None)
822 826 for x in (c, a, d, u):
823 827 if ".hgtags" in x:
824 828 ui.warn("abort: working copy of .hgtags is changed!\n")
825 829 ui.status("(please commit .hgtags manually)\n")
826 830 return -1
827 831
828 832 if rev:
829 833 r = hg.hex(repo.lookup(rev))
830 834 else:
831 835 r = hg.hex(repo.changelog.tip())
832 836
833 837 add = 0
834 838 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
835 839 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
836 840 if add: repo.add([".hgtags"])
837 841
838 842 if not opts['text']:
839 843 opts['text'] = "Added tag %s for changeset %s" % (name, r)
840 844
841 845 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
842 846
843 847 def tags(ui, repo):
844 848 """list repository tags"""
845 849
846 850 l = repo.tagslist()
847 851 l.reverse()
848 852 for t, n in l:
849 853 try:
850 854 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
851 855 except KeyError:
852 856 r = " ?:?"
853 857 ui.write("%-30s %s\n" % (t, r))
854 858
855 859 def tip(ui, repo):
856 860 """show the tip revision"""
857 861 n = repo.changelog.tip()
858 862 show_changeset(ui, repo, changenode=n)
859 863
860 864 def undo(ui, repo):
861 """undo the last transaction"""
865 """undo the last commit or pull
866
867 Roll back the last pull or commit transaction on the
868 repository, restoring the project to its earlier state.
869
870 This command should be used with care. There is only one level of
871 undo and there is no redo.
872
873 This command is not intended for use on public repositories. Once
874 a change is visible for pull by other users, undoing it locally is
875 ineffective.
876 """
862 877 repo.undo()
863 878
864 879 def update(ui, repo, node=None, merge=False, clean=False):
865 880 '''update or merge working directory
866 881
867 882 If there are no outstanding changes in the working directory and
868 883 there is a linear relationship between the current version and the
869 884 requested version, the result is the requested version.
870 885
871 886 Otherwise the result is a merge between the contents of the
872 887 current working directory and the requested version. Files that
873 888 changed between either parent are marked as changed for the next
874 889 commit and a commit must be performed before any further updates
875 890 are allowed.
876 891 '''
877 892 node = node and repo.lookup(node) or repo.changelog.tip()
878 893 return repo.update(node, allow=merge, force=clean)
879 894
880 895 def verify(ui, repo):
881 896 """verify the integrity of the repository"""
882 897 return repo.verify()
883 898
884 899 # Command options and aliases are listed here, alphabetically
885 900
886 901 table = {
887 902 "^add": (add, [], "hg add [files]"),
888 903 "addremove": (addremove, [], "hg addremove [files]"),
889 "annotate": (annotate,
904 "^annotate": (annotate,
890 905 [('r', 'revision', '', 'revision'),
891 906 ('u', 'user', None, 'show user'),
892 907 ('n', 'number', None, 'show revision number'),
893 908 ('c', 'changeset', None, 'show changeset')],
894 909 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
895 910 "cat": (cat, [], 'hg cat <file> [rev]'),
896 911 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
897 912 'hg clone [options] <source> [dest]'),
898 913 "^commit|ci": (commit,
899 914 [('t', 'text', "", 'commit text'),
900 915 ('A', 'addremove', None, 'run add/remove during commit'),
901 916 ('l', 'logfile', "", 'commit text file'),
902 917 ('d', 'date', "", 'date code'),
903 918 ('u', 'user', "", 'user')],
904 919 'hg commit [files]'),
905 920 "copy": (copy, [], 'hg copy <source> <dest>'),
906 "debugcheckdirstate": (debugcheckdirstate, [], 'debugcheckdirstate'),
907 "debugdumpdirstate": (debugdumpdirstate, [], 'debugdumpdirstate'),
921 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
922 "debugstate": (debugstate, [], 'debugstate'),
908 923 "debugindex": (debugindex, [], 'debugindex <file>'),
909 924 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
910 925 "^diff": (diff, [('r', 'rev', [], 'revision')],
911 926 'hg diff [-r A] [-r B] [files]'),
912 "export": (export, [('o', 'output', "", 'output to file')],
927 "^export": (export, [('o', 'output', "", 'output to file')],
913 928 "hg export [-o file] <changeset> ..."),
914 929 "forget": (forget, [], "hg forget [files]"),
915 930 "heads": (heads, [], 'hg heads'),
916 931 "help": (help, [], 'hg help [command]'),
917 932 "identify|id": (identify, [], 'hg identify'),
918 933 "import|patch": (import_,
919 934 [('p', 'strip', 1, 'path strip'),
920 935 ('b', 'base', "", 'base path')],
921 936 "hg import [options] <patches>"),
922 937 "^init": (init, [], 'hg init'),
923 938 "^log|history": (log,
924 939 [('r', 'rev', [], 'revision')],
925 940 'hg log [-r A] [-r B] [file]'),
926 941 "manifest": (manifest, [], 'hg manifest [rev]'),
927 942 "parents": (parents, [], 'hg parents [node]'),
928 943 "^pull": (pull,
929 944 [('u', 'update', None, 'update working directory')],
930 945 'hg pull [options] [source]'),
931 946 "^push": (push, [], 'hg push <destination>'),
932 947 "rawcommit": (rawcommit,
933 948 [('p', 'parent', [], 'parent'),
934 949 ('d', 'date', "", 'date code'),
935 950 ('u', 'user', "", 'user'),
936 951 ('F', 'files', "", 'file list'),
937 952 ('t', 'text', "", 'commit text'),
938 953 ('l', 'logfile', "", 'commit text file')],
939 954 'hg rawcommit [options] [files]'),
940 955 "recover": (recover, [], "hg recover"),
941 956 "^remove|rm": (remove, [], "hg remove [files]"),
942 "revert": (revert,
957 "^revert": (revert,
943 958 [("n", "nonrecursive", None, "don't recurse into subdirs"),
944 959 ("r", "rev", "", "revision")],
945 960 "hg revert [files|dirs]"),
946 961 "root": (root, [], "hg root"),
947 962 "^serve": (serve, [('p', 'port', 8000, 'listen port'),
948 963 ('a', 'address', '', 'interface address'),
949 964 ('n', 'name', os.getcwd(), 'repository name'),
950 965 ('t', 'templates', "", 'template map')],
951 966 "hg serve [options]"),
952 967 "^status": (status, [], 'hg status'),
953 968 "tag": (tag, [('t', 'text', "", 'commit text'),
954 969 ('d', 'date', "", 'date code'),
955 970 ('u', 'user', "", 'user')],
956 971 'hg tag [options] <name> [rev]'),
957 972 "tags": (tags, [], 'hg tags'),
958 973 "tip": (tip, [], 'hg tip'),
959 974 "undo": (undo, [], 'hg undo'),
960 975 "^update|up|checkout|co":
961 976 (update,
962 977 [('m', 'merge', None, 'allow merging of conflicts'),
963 978 ('C', 'clean', None, 'overwrite locally modified files')],
964 979 'hg update [options] [node]'),
965 980 "verify": (verify, [], 'hg verify'),
966 981 "version": (show_version, [], 'hg version'),
967 982 }
968 983
984 globalopts = [('v', 'verbose', None, 'verbose'),
985 ('', 'debug', None, 'debug'),
986 ('q', 'quiet', None, 'quiet'),
987 ('', 'profile', None, 'profile'),
988 ('R', 'repository', "", 'repository root directory'),
989 ('', 'traceback', None, 'print traceback on exception'),
990 ('y', 'noninteractive', None, 'run non-interactively'),
991 ('', 'version', None, 'output version information and exit'),
992 ]
993
969 994 norepo = "clone init version help debugindex debugindexdot"
970 995
971 996 def find(cmd):
972 997 for e in table.keys():
973 998 if re.match("(%s)$" % e, cmd):
974 999 return table[e]
975 1000
976 1001 raise UnknownCommand(cmd)
977 1002
978 1003 class SignalInterrupt(Exception): pass
979 1004
980 1005 def catchterm(*args):
981 1006 raise SignalInterrupt
982 1007
983 1008 def run():
984 1009 sys.exit(dispatch(sys.argv[1:]))
985 1010
986 def dispatch(args):
987 signal.signal(signal.SIGTERM, catchterm)
1011 class ParseError(Exception): pass
988 1012
989 def get_ui():
990 return ui.ui(options["verbose"], options["debug"], options["quiet"],
991 not options["noninteractive"])
992
1013 def parse(args):
993 1014 options = {}
994 opts = [('v', 'verbose', None, 'verbose'),
995 ('', 'debug', None, 'debug'),
996 ('q', 'quiet', None, 'quiet'),
997 ('', 'profile', None, 'profile'),
998 ('R', 'repository', "", 'repository root directory'),
999 ('', 'traceback', None, 'print traceback on exception'),
1000 ('y', 'noninteractive', None, 'run non-interactively'),
1001 ('', 'version', None, 'output version information and exit'),
1002 ]
1015 cmdoptions = {}
1003 1016
1004 1017 try:
1005 args = fancyopts.fancyopts(args, opts, options,
1006 'hg [options] <command> [options] [files]')
1018 args = fancyopts.fancyopts(args, globalopts, options)
1007 1019 except fancyopts.getopt.GetoptError, inst:
1008 u = ui.ui()
1009 u.warn("hg: %s\n" % (inst))
1010 sys.exit(-1)
1020 raise ParseError(cmd, inst)
1011 1021
1012 if not args:
1013 cmd = "help"
1022 if options["version"]:
1023 return ("version", show_version, [], options, cmdoptions)
1024 elif not args:
1025 return ("help", help, [], options, cmdoptions)
1014 1026 else:
1015 1027 cmd, args = args[0], args[1:]
1016 1028
1017 if options["version"]:
1018 show_version(get_ui())
1019 sys.exit(0)
1020
1021 try:
1022 1029 i = find(cmd)
1023 except UnknownCommand:
1024 u = get_ui()
1025 u.warn("hg: unknown command '%s'\n" % cmd)
1026 help(u)
1027 sys.exit(1)
1028 1030
1029 1031 # combine global options into local
1030 1032 c = list(i[1])
1031 1033 l = len(c)
1032 for o in opts:
1034 for o in globalopts:
1033 1035 c.append((o[0], o[1], options[o[1]], o[3]))
1034 1036
1035 cmdoptions = {}
1036 1037 try:
1037 args = fancyopts.fancyopts(args, c, cmdoptions, i[2])
1038 args = fancyopts.fancyopts(args, c, cmdoptions)
1038 1039 except fancyopts.getopt.GetoptError, inst:
1039 u = get_ui()
1040 u.warn("hg %s: %s\n" % (cmd, inst))
1041 help(u, cmd)
1042 sys.exit(-1)
1040 raise ParseError(cmd, inst)
1043 1041
1044 1042 # separate global options back out
1045 for o in opts:
1043 for o in globalopts:
1046 1044 n = o[1]
1047 1045 options[n] = cmdoptions[n]
1048 1046 del cmdoptions[n]
1049 1047
1050 u = get_ui()
1048 return (cmd, i[0], args, options, cmdoptions)
1049
1050 def dispatch(args):
1051 signal.signal(signal.SIGTERM, catchterm)
1052
1053 try:
1054 cmd, func, args, options, cmdoptions = parse(args)
1055 except ParseError, inst:
1056 u = ui.ui()
1057 if inst.args[0]:
1058 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1059 help(u, inst.args[0])
1060 else:
1061 u.warn("hg: %s\n" % inst.args[1])
1062 help(u)
1063 sys.exit(-1)
1064 except UnknownCommand, inst:
1065 u = ui.ui()
1066 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1067 help(u)
1068 sys.exit(1)
1069
1070 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1071 not options["noninteractive"])
1051 1072
1052 1073 try:
1053 1074 try:
1054 1075 if cmd not in norepo.split():
1055 1076 path = options["repository"] or ""
1056 1077 repo = hg.repository(ui=u, path=path)
1057 d = lambda: i[0](u, repo, *args, **cmdoptions)
1078 d = lambda: func(u, repo, *args, **cmdoptions)
1058 1079 else:
1059 d = lambda: i[0](u, *args, **cmdoptions)
1080 d = lambda: func(u, *args, **cmdoptions)
1060 1081
1061 1082 if options['profile']:
1062 1083 import hotshot, hotshot.stats
1063 1084 prof = hotshot.Profile("hg.prof")
1064 1085 r = prof.runcall(d)
1065 1086 prof.close()
1066 1087 stats = hotshot.stats.load("hg.prof")
1067 1088 stats.strip_dirs()
1068 1089 stats.sort_stats('time', 'calls')
1069 1090 stats.print_stats(40)
1070 1091 return r
1071 1092 else:
1072 1093 return d()
1073 1094 except:
1074 1095 if options['traceback']:
1075 1096 traceback.print_exc()
1076 1097 raise
1077 1098 except util.CommandError, inst:
1078 1099 u.warn("abort: %s\n" % inst.args)
1079 1100 except hg.RepoError, inst:
1080 1101 u.warn("abort: ", inst, "!\n")
1081 1102 except SignalInterrupt:
1082 1103 u.warn("killed!\n")
1083 1104 except KeyboardInterrupt:
1084 1105 u.warn("interrupted!\n")
1085 1106 except IOError, inst:
1086 1107 if hasattr(inst, "code"):
1087 1108 u.warn("abort: %s\n" % inst)
1088 1109 elif hasattr(inst, "reason"):
1089 1110 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1090 1111 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1091 1112 u.warn("broken pipe\n")
1092 1113 else:
1093 1114 raise
1094 1115 except OSError, inst:
1095 1116 if hasattr(inst, "filename"):
1096 1117 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1097 1118 else:
1098 1119 u.warn("abort: %s\n" % inst.strerror)
1099 1120 except TypeError, inst:
1100 1121 # was this an argument error?
1101 1122 tb = traceback.extract_tb(sys.exc_info()[2])
1102 1123 if len(tb) > 2: # no
1103 1124 raise
1104 1125 u.debug(inst, "\n")
1105 u.warn("%s: invalid arguments\n" % i[0].__name__)
1126 u.warn("%s: invalid arguments\n" % cmd)
1106 1127 help(u, cmd)
1107 1128
1108 1129 sys.exit(-1)
@@ -1,30 +1,30 b''
1 1 import os, getopt
2 2
3 def fancyopts(args, options, state, syntax='', minlen = 0):
3 def fancyopts(args, options, state):
4 4 long=[]
5 5 short=''
6 6 map={}
7 7 dt={}
8 8
9 9 for s, l, d, c in options:
10 10 map['-'+s] = map['--'+l]=l
11 11 state[l] = d
12 12 dt[l] = type(d)
13 13 if not d is None and not callable(d): s, l=s+':', l+'='
14 14 if s: short = short + s
15 15 if l: long.append(l)
16 16
17 17 if os.environ.has_key("HG_OPTS"):
18 18 args = os.environ["HG_OPTS"].split() + args
19 19
20 20 opts, args = getopt.getopt(args, short, long)
21 21
22 22 for opt, arg in opts:
23 23 if dt[map[opt]] is type(fancyopts): state[map[opt]](state,map[opt],arg)
24 24 elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
25 25 elif dt[map[opt]] is type(''): state[map[opt]] = arg
26 26 elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
27 27 elif dt[map[opt]] is type(None): state[map[opt]] = 1
28 28
29 29 return args
30 30
@@ -1,11 +1,11 b''
1 1 #!/bin/sh
2 2
3 set -x
4
3 hg help
5 4 hg -q help
6 5 hg add -h
6 hg add --skjdfks
7 7 hg help diff
8 8 hg help foo
9 9 hg -q commands
10 10
11 11 exit 0
@@ -1,46 +1,67 b''
1 + hg -q help
2 basic hg commands (use -v for long list):
1 basic hg commands (use "hg help -v" for more):
3 2
4 3 add add the specified files on the next commit
4 annotate show changeset information per file line
5 5 clone make a copy of an existing repository
6 6 commit commit the specified files or all outstanding changes
7 7 diff diff working directory (or selected files)
8 export dump the header and diffs for one or more changesets
8 9 init create a new repository in the current directory
9 10 log show the revision history of the repository or a single file
10 11 pull pull changes from the specified source
11 12 push push changes to the specified destination
12 13 remove remove the specified files on the next commit
14 revert revert modified files or dirs back to their unmodified states
13 15 serve export the repository via HTTP
14 16 status show changed files in the working directory
15 17 update update or merge working directory
16 + hg add -h
18 basic hg commands (use "hg help -v" for more):
19
20 add add the specified files on the next commit
21 annotate show changeset information per file line
22 clone make a copy of an existing repository
23 commit commit the specified files or all outstanding changes
24 diff diff working directory (or selected files)
25 export dump the header and diffs for one or more changesets
26 init create a new repository in the current directory
27 log show the revision history of the repository or a single file
28 pull pull changes from the specified source
29 push push changes to the specified destination
30 remove remove the specified files on the next commit
31 revert revert modified files or dirs back to their unmodified states
32 serve export the repository via HTTP
33 status show changed files in the working directory
34 update update or merge working directory
17 35 hg add: option -h not recognized
18 36 hg add [files]
19 37
20 38 add the specified files on the next commit
21 + hg help diff
39 hg add: option --skjdfks not recognized
40 hg add [files]
41
42 add the specified files on the next commit
22 43 hg diff [-r A] [-r B] [files]
23 44
24 45 -r --rev
25 46 revision
26 47
27 48 diff working directory (or selected files)
28 + hg help foo
29 49 hg: unknown command foo
30 + hg -q commands
31 50 hg: unknown command 'commands'
32 basic hg commands (use -v for long list):
51 basic hg commands (use "hg help -v" for more):
33 52
34 53 add add the specified files on the next commit
54 annotate show changeset information per file line
35 55 clone make a copy of an existing repository
36 56 commit commit the specified files or all outstanding changes
37 57 diff diff working directory (or selected files)
58 export dump the header and diffs for one or more changesets
38 59 init create a new repository in the current directory
39 60 log show the revision history of the repository or a single file
40 61 pull pull changes from the specified source
41 62 push push changes to the specified destination
42 63 remove remove the specified files on the next commit
64 revert revert modified files or dirs back to their unmodified states
43 65 serve export the repository via HTTP
44 66 status show changed files in the working directory
45 67 update update or merge working directory
46 + exit 0
General Comments 0
You need to be logged in to leave comments. Login now