##// END OF EJS Templates
Update tests to reflect walk changes.
Bryan O'Sullivan -
r736:1e84f101 default
parent child Browse files
Show More
@@ -1,1374 +1,1376 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 demandload(globals(), "os re sys signal shutil")
9 demandload(globals(), "os re sys signal shutil")
10 demandload(globals(), "fancyopts ui hg util")
10 demandload(globals(), "fancyopts ui hg util")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 demandload(globals(), "errno socket version struct")
12 demandload(globals(), "errno socket version struct")
13
13
14 class UnknownCommand(Exception):
14 class UnknownCommand(Exception):
15 """Exception raised if command is not in the command table."""
15 """Exception raised if command is not in the command table."""
16
16
17 class Abort(Exception):
17 class Abort(Exception):
18 """Raised if a command needs to print an error and exit."""
18 """Raised if a command needs to print an error and exit."""
19
19
20 def filterfiles(filters, files):
20 def filterfiles(filters, files):
21 l = [x for x in files if x in filters]
21 l = [x for x in files if x in filters]
22
22
23 for t in filters:
23 for t in filters:
24 if t and t[-1] != "/":
24 if t and t[-1] != "/":
25 t += "/"
25 t += "/"
26 l += [x for x in files if x.startswith(t)]
26 l += [x for x in files if x.startswith(t)]
27 return l
27 return l
28
28
29 def relfilter(repo, files):
29 def relfilter(repo, files):
30 cwd = repo.getcwd()
30 cwd = repo.getcwd()
31 if cwd:
31 if cwd:
32 return filterfiles([util.pconvert(cwd)], files)
32 return filterfiles([util.pconvert(cwd)], files)
33 return files
33 return files
34
34
35 def relpath(repo, args):
35 def relpath(repo, args):
36 cwd = repo.getcwd()
36 cwd = repo.getcwd()
37 if cwd:
37 if cwd:
38 return [util.pconvert(os.path.normpath(os.path.join(cwd, x)))
38 return [util.pconvert(os.path.normpath(os.path.join(cwd, x)))
39 for x in args]
39 for x in args]
40 return args
40 return args
41
41
42 def matchpats(ui, cwd, pats = [], opts = {}, emptyok = True):
42 def matchpats(ui, cwd, pats = [], opts = {}, emptyok = True):
43 if not pats and not emptyok:
43 if not pats and not emptyok:
44 raise Abort('at least one file name or pattern required')
44 raise Abort('at least one file name or pattern required')
45 head = ''
45 head = ''
46 if opts.get('rootless'): head = '(?:.*/|)'
46 if opts.get('rootless'): head = '(?:.*/|)'
47 def reify(name, tail):
47 def reify(name, tail):
48 if name.startswith('re:'):
48 if name.startswith('re:'):
49 return name[3:]
49 return name[3:]
50 elif name.startswith('glob:'):
50 elif name.startswith('glob:'):
51 return head + util.globre(name[5:], '', tail)
51 return head + util.globre(name[5:], '', tail)
52 elif name.startswith('path:'):
52 elif name.startswith('path:'):
53 return '^' + re.escape(name[5:]) + '$'
53 return '^' + re.escape(name[5:]) + '$'
54 return head + util.globre(name, '', tail)
54 return head + util.globre(name, '', tail)
55 cwdsep = cwd + os.sep
55 cwdsep = cwd + os.sep
56 def under(fn):
56 def under(fn):
57 if not cwd or fn.startswith(cwdsep): return True
57 if not cwd or fn.startswith(cwdsep): return True
58 def matchfn(pats, tail, ifempty = util.always):
58 def matchfn(pats, tail, ifempty = util.always):
59 if not pats: return ifempty
59 if not pats: return ifempty
60 pat = '(?:%s)' % '|'.join([reify(p, tail) for p in pats])
60 pat = '(?:%s)' % '|'.join([reify(p, tail) for p in pats])
61 if cwd: pat = re.escape(cwd + os.sep) + pat
61 if cwd: pat = re.escape(cwd + os.sep) + pat
62 ui.debug('regexp: %s\n' % pat)
62 ui.debug('regexp: %s\n' % pat)
63 return re.compile(pat).match
63 return re.compile(pat).match
64 patmatch = matchfn(pats, '$')
64 patmatch = matchfn(pats, '$')
65 incmatch = matchfn(opts.get('include'), '(?:/|$)', under)
65 incmatch = matchfn(opts.get('include'), '(?:/|$)', under)
66 excmatch = matchfn(opts.get('exclude'), '(?:/|$)', util.never)
66 excmatch = matchfn(opts.get('exclude'), '(?:/|$)', util.never)
67 return lambda fn: (incmatch(fn) and not excmatch(fn) and
67 return lambda fn: (incmatch(fn) and not excmatch(fn) and
68 (fn.endswith('/') or patmatch(fn)))
68 (fn.endswith('/') or patmatch(fn)))
69
69
70 def walk(repo, pats, opts, emptyok = True):
70 def walk(repo, pats, opts, emptyok = True):
71 cwd = repo.getcwd()
71 cwd = repo.getcwd()
72 if cwd: c = len(cwd) + 1
72 if cwd: c = len(cwd) + 1
73 for src, fn in repo.walk(match = matchpats(repo.ui, cwd, pats, opts, emptyok)):
73 for src, fn in repo.walk(match = matchpats(repo.ui, cwd, pats, opts, emptyok)):
74 if cwd: yield src, fn, fn[c:]
74 if cwd: yield src, fn, fn[c:]
75 else: yield src, fn, fn
75 else: yield src, fn, fn
76
76
77 revrangesep = ':'
77 revrangesep = ':'
78
78
79 def revrange(ui, repo, revs, revlog=None):
79 def revrange(ui, repo, revs, revlog=None):
80 if revlog is None:
80 if revlog is None:
81 revlog = repo.changelog
81 revlog = repo.changelog
82 revcount = revlog.count()
82 revcount = revlog.count()
83 def fix(val, defval):
83 def fix(val, defval):
84 if not val:
84 if not val:
85 return defval
85 return defval
86 try:
86 try:
87 num = int(val)
87 num = int(val)
88 if str(num) != val:
88 if str(num) != val:
89 raise ValueError
89 raise ValueError
90 if num < 0:
90 if num < 0:
91 num += revcount
91 num += revcount
92 if not (0 <= num < revcount):
92 if not (0 <= num < revcount):
93 raise ValueError
93 raise ValueError
94 except ValueError:
94 except ValueError:
95 try:
95 try:
96 num = repo.changelog.rev(repo.lookup(val))
96 num = repo.changelog.rev(repo.lookup(val))
97 except KeyError:
97 except KeyError:
98 try:
98 try:
99 num = revlog.rev(revlog.lookup(val))
99 num = revlog.rev(revlog.lookup(val))
100 except KeyError:
100 except KeyError:
101 raise Abort('invalid revision identifier %s', val)
101 raise Abort('invalid revision identifier %s', val)
102 return num
102 return num
103 for spec in revs:
103 for spec in revs:
104 if spec.find(revrangesep) >= 0:
104 if spec.find(revrangesep) >= 0:
105 start, end = spec.split(revrangesep, 1)
105 start, end = spec.split(revrangesep, 1)
106 start = fix(start, 0)
106 start = fix(start, 0)
107 end = fix(end, revcount - 1)
107 end = fix(end, revcount - 1)
108 if end > start:
108 if end > start:
109 end += 1
109 end += 1
110 step = 1
110 step = 1
111 else:
111 else:
112 end -= 1
112 end -= 1
113 step = -1
113 step = -1
114 for rev in xrange(start, end, step):
114 for rev in xrange(start, end, step):
115 yield str(rev)
115 yield str(rev)
116 else:
116 else:
117 yield spec
117 yield spec
118
118
119 def make_file(repo, r, pat, node=None,
119 def make_file(repo, r, pat, node=None,
120 total=None, seqno=None, revwidth=None, mode='wb'):
120 total=None, seqno=None, revwidth=None, mode='wb'):
121 if pat == '-':
121 if not pat or pat == '-':
122 if 'w' in mode: return sys.stdout
122 if 'w' in mode: return sys.stdout
123 else: return sys.stdin
123 else: return sys.stdin
124 node_expander = {
124 node_expander = {
125 'H': lambda: hg.hex(node),
125 'H': lambda: hg.hex(node),
126 'R': lambda: str(r.rev(node)),
126 'R': lambda: str(r.rev(node)),
127 'h': lambda: hg.short(node),
127 'h': lambda: hg.short(node),
128 }
128 }
129 expander = {
129 expander = {
130 '%': lambda: '%',
130 '%': lambda: '%',
131 'b': lambda: os.path.basename(repo.root),
131 'b': lambda: os.path.basename(repo.root),
132 }
132 }
133
133
134 try:
134 try:
135 if node:
135 if node:
136 expander.update(node_expander)
136 expander.update(node_expander)
137 if node and revwidth is not None:
137 if node and revwidth is not None:
138 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
138 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
139 if total is not None:
139 if total is not None:
140 expander['N'] = lambda: str(total)
140 expander['N'] = lambda: str(total)
141 if seqno is not None:
141 if seqno is not None:
142 expander['n'] = lambda: str(seqno)
142 expander['n'] = lambda: str(seqno)
143 if total is not None and seqno is not None:
143 if total is not None and seqno is not None:
144 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
144 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
145
145
146 newname = []
146 newname = []
147 patlen = len(pat)
147 patlen = len(pat)
148 i = 0
148 i = 0
149 while i < patlen:
149 while i < patlen:
150 c = pat[i]
150 c = pat[i]
151 if c == '%':
151 if c == '%':
152 i += 1
152 i += 1
153 c = pat[i]
153 c = pat[i]
154 c = expander[c]()
154 c = expander[c]()
155 newname.append(c)
155 newname.append(c)
156 i += 1
156 i += 1
157 return open(''.join(newname), mode)
157 return open(''.join(newname), mode)
158 except KeyError, inst:
158 except KeyError, inst:
159 raise Abort("invalid format spec '%%%s' in output file name",
159 raise Abort("invalid format spec '%%%s' in output file name",
160 inst.args[0])
160 inst.args[0])
161
161
162 def dodiff(fp, ui, repo, files=None, node1=None, node2=None):
162 def dodiff(fp, ui, repo, files=None, node1=None, node2=None):
163 def date(c):
163 def date(c):
164 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
164 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
165
165
166 (c, a, d, u) = repo.changes(node1, node2, files)
166 (c, a, d, u) = repo.changes(node1, node2, files)
167 if files:
167 if files:
168 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
168 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
169
169
170 if not c and not a and not d:
170 if not c and not a and not d:
171 return
171 return
172
172
173 if node2:
173 if node2:
174 change = repo.changelog.read(node2)
174 change = repo.changelog.read(node2)
175 mmap2 = repo.manifest.read(change[0])
175 mmap2 = repo.manifest.read(change[0])
176 date2 = date(change)
176 date2 = date(change)
177 def read(f):
177 def read(f):
178 return repo.file(f).read(mmap2[f])
178 return repo.file(f).read(mmap2[f])
179 else:
179 else:
180 date2 = time.asctime()
180 date2 = time.asctime()
181 if not node1:
181 if not node1:
182 node1 = repo.dirstate.parents()[0]
182 node1 = repo.dirstate.parents()[0]
183 def read(f):
183 def read(f):
184 return repo.wfile(f).read()
184 return repo.wfile(f).read()
185
185
186 if ui.quiet:
186 if ui.quiet:
187 r = None
187 r = None
188 else:
188 else:
189 hexfunc = ui.verbose and hg.hex or hg.short
189 hexfunc = ui.verbose and hg.hex or hg.short
190 r = [hexfunc(node) for node in [node1, node2] if node]
190 r = [hexfunc(node) for node in [node1, node2] if node]
191
191
192 change = repo.changelog.read(node1)
192 change = repo.changelog.read(node1)
193 mmap = repo.manifest.read(change[0])
193 mmap = repo.manifest.read(change[0])
194 date1 = date(change)
194 date1 = date(change)
195
195
196 for f in c:
196 for f in c:
197 to = None
197 to = None
198 if f in mmap:
198 if f in mmap:
199 to = repo.file(f).read(mmap[f])
199 to = repo.file(f).read(mmap[f])
200 tn = read(f)
200 tn = read(f)
201 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
201 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
202 for f in a:
202 for f in a:
203 to = None
203 to = None
204 tn = read(f)
204 tn = read(f)
205 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
205 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
206 for f in d:
206 for f in d:
207 to = repo.file(f).read(mmap[f])
207 to = repo.file(f).read(mmap[f])
208 tn = None
208 tn = None
209 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
209 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
210
210
211 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
211 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
212 """show a single changeset or file revision"""
212 """show a single changeset or file revision"""
213 changelog = repo.changelog
213 changelog = repo.changelog
214 if filelog:
214 if filelog:
215 log = filelog
215 log = filelog
216 filerev = rev
216 filerev = rev
217 node = filenode = filelog.node(filerev)
217 node = filenode = filelog.node(filerev)
218 changerev = filelog.linkrev(filenode)
218 changerev = filelog.linkrev(filenode)
219 changenode = changenode or changelog.node(changerev)
219 changenode = changenode or changelog.node(changerev)
220 else:
220 else:
221 log = changelog
221 log = changelog
222 changerev = rev
222 changerev = rev
223 if changenode is None:
223 if changenode is None:
224 changenode = changelog.node(changerev)
224 changenode = changelog.node(changerev)
225 elif not changerev:
225 elif not changerev:
226 rev = changerev = changelog.rev(changenode)
226 rev = changerev = changelog.rev(changenode)
227 node = changenode
227 node = changenode
228
228
229 if ui.quiet:
229 if ui.quiet:
230 ui.write("%d:%s\n" % (rev, hg.hex(node)))
230 ui.write("%d:%s\n" % (rev, hg.hex(node)))
231 return
231 return
232
232
233 changes = changelog.read(changenode)
233 changes = changelog.read(changenode)
234
234
235 parents = [(log.rev(parent), hg.hex(parent))
235 parents = [(log.rev(parent), hg.hex(parent))
236 for parent in log.parents(node)
236 for parent in log.parents(node)
237 if ui.debugflag or parent != hg.nullid]
237 if ui.debugflag or parent != hg.nullid]
238 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
238 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
239 parents = []
239 parents = []
240
240
241 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
241 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
242 for tag in repo.nodetags(changenode):
242 for tag in repo.nodetags(changenode):
243 ui.status("tag: %s\n" % tag)
243 ui.status("tag: %s\n" % tag)
244 for parent in parents:
244 for parent in parents:
245 ui.write("parent: %d:%s\n" % parent)
245 ui.write("parent: %d:%s\n" % parent)
246 if filelog:
246 if filelog:
247 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
247 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
248 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
248 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
249 hg.hex(changes[0])))
249 hg.hex(changes[0])))
250 ui.status("user: %s\n" % changes[1])
250 ui.status("user: %s\n" % changes[1])
251 ui.status("date: %s\n" % time.asctime(
251 ui.status("date: %s\n" % time.asctime(
252 time.localtime(float(changes[2].split(' ')[0]))))
252 time.localtime(float(changes[2].split(' ')[0]))))
253 if ui.debugflag:
253 if ui.debugflag:
254 files = repo.changes(changelog.parents(changenode)[0], changenode)
254 files = repo.changes(changelog.parents(changenode)[0], changenode)
255 for key, value in zip(["files:", "files+:", "files-:"], files):
255 for key, value in zip(["files:", "files+:", "files-:"], files):
256 if value:
256 if value:
257 ui.note("%-12s %s\n" % (key, " ".join(value)))
257 ui.note("%-12s %s\n" % (key, " ".join(value)))
258 else:
258 else:
259 ui.note("files: %s\n" % " ".join(changes[3]))
259 ui.note("files: %s\n" % " ".join(changes[3]))
260 description = changes[4].strip()
260 description = changes[4].strip()
261 if description:
261 if description:
262 if ui.verbose:
262 if ui.verbose:
263 ui.status("description:\n")
263 ui.status("description:\n")
264 ui.status(description)
264 ui.status(description)
265 ui.status("\n\n")
265 ui.status("\n\n")
266 else:
266 else:
267 ui.status("summary: %s\n" % description.splitlines()[0])
267 ui.status("summary: %s\n" % description.splitlines()[0])
268 ui.status("\n")
268 ui.status("\n")
269
269
270 def show_version(ui):
270 def show_version(ui):
271 """output version and copyright information"""
271 """output version and copyright information"""
272 ui.write("Mercurial version %s\n" % version.get_version())
272 ui.write("Mercurial version %s\n" % version.get_version())
273 ui.status(
273 ui.status(
274 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
274 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
275 "This is free software; see the source for copying conditions. "
275 "This is free software; see the source for copying conditions. "
276 "There is NO\nwarranty; "
276 "There is NO\nwarranty; "
277 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
277 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
278 )
278 )
279
279
280 def help_(ui, cmd=None):
280 def help_(ui, cmd=None):
281 """show help for a given command or all commands"""
281 """show help for a given command or all commands"""
282 if cmd:
282 if cmd:
283 try:
283 try:
284 i = find(cmd)
284 i = find(cmd)
285 ui.write("%s\n\n" % i[2])
285 ui.write("%s\n\n" % i[2])
286
286
287 if i[1]:
287 if i[1]:
288 for s, l, d, c in i[1]:
288 for s, l, d, c in i[1]:
289 opt = ' '
289 opt = ' '
290 if s:
290 if s:
291 opt = opt + '-' + s + ' '
291 opt = opt + '-' + s + ' '
292 if l:
292 if l:
293 opt = opt + '--' + l + ' '
293 opt = opt + '--' + l + ' '
294 if d:
294 if d:
295 opt = opt + '(' + str(d) + ')'
295 opt = opt + '(' + str(d) + ')'
296 ui.write(opt, "\n")
296 ui.write(opt, "\n")
297 if c:
297 if c:
298 ui.write(' %s\n' % c)
298 ui.write(' %s\n' % c)
299 ui.write("\n")
299 ui.write("\n")
300
300
301 ui.write(i[0].__doc__, "\n")
301 ui.write(i[0].__doc__, "\n")
302 except UnknownCommand:
302 except UnknownCommand:
303 ui.warn("hg: unknown command %s\n" % cmd)
303 ui.warn("hg: unknown command %s\n" % cmd)
304 sys.exit(0)
304 sys.exit(0)
305 else:
305 else:
306 if ui.verbose:
306 if ui.verbose:
307 show_version(ui)
307 show_version(ui)
308 ui.write('\n')
308 ui.write('\n')
309 if ui.verbose:
309 if ui.verbose:
310 ui.write('hg commands:\n\n')
310 ui.write('hg commands:\n\n')
311 else:
311 else:
312 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
312 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
313
313
314 h = {}
314 h = {}
315 for c, e in table.items():
315 for c, e in table.items():
316 f = c.split("|")[0]
316 f = c.split("|")[0]
317 if not ui.verbose and not f.startswith("^"):
317 if not ui.verbose and not f.startswith("^"):
318 continue
318 continue
319 if not ui.debugflag and f.startswith("debug"):
319 if not ui.debugflag and f.startswith("debug"):
320 continue
320 continue
321 f = f.lstrip("^")
321 f = f.lstrip("^")
322 d = ""
322 d = ""
323 if e[0].__doc__:
323 if e[0].__doc__:
324 d = e[0].__doc__.splitlines(0)[0].rstrip()
324 d = e[0].__doc__.splitlines(0)[0].rstrip()
325 h[f] = d
325 h[f] = d
326
326
327 fns = h.keys()
327 fns = h.keys()
328 fns.sort()
328 fns.sort()
329 m = max(map(len, fns))
329 m = max(map(len, fns))
330 for f in fns:
330 for f in fns:
331 ui.write(' %-*s %s\n' % (m, f, h[f]))
331 ui.write(' %-*s %s\n' % (m, f, h[f]))
332
332
333 # Commands start here, listed alphabetically
333 # Commands start here, listed alphabetically
334
334
335 def add(ui, repo, *pats, **opts):
335 def add(ui, repo, *pats, **opts):
336 '''add the specified files on the next commit'''
336 '''add the specified files on the next commit'''
337 names = []
337 names = []
338 q = dict(zip(pats, pats))
338 q = dict(zip(pats, pats))
339 for src, abs, rel in walk(repo, pats, opts):
339 for src, abs, rel in walk(repo, pats, opts):
340 if rel in q or abs in q:
340 if rel in q or abs in q:
341 names.append(abs)
341 names.append(abs)
342 elif repo.dirstate.state(abs) == '?':
342 elif repo.dirstate.state(abs) == '?':
343 ui.status('adding %s\n' % rel)
343 ui.status('adding %s\n' % rel)
344 names.append(abs)
344 names.append(abs)
345 repo.add(names)
345 repo.add(names)
346
346
347 def addremove(ui, repo, *files):
347 def addremove(ui, repo, *files):
348 """add all new files, delete all missing files"""
348 """add all new files, delete all missing files"""
349 if files:
349 if files:
350 files = relpath(repo, files)
350 files = relpath(repo, files)
351 d = []
351 d = []
352 u = []
352 u = []
353 for f in files:
353 for f in files:
354 p = repo.wjoin(f)
354 p = repo.wjoin(f)
355 s = repo.dirstate.state(f)
355 s = repo.dirstate.state(f)
356 isfile = os.path.isfile(p)
356 isfile = os.path.isfile(p)
357 if s != 'r' and not isfile:
357 if s != 'r' and not isfile:
358 d.append(f)
358 d.append(f)
359 elif s not in 'nmai' and isfile:
359 elif s not in 'nmai' and isfile:
360 u.append(f)
360 u.append(f)
361 else:
361 else:
362 (c, a, d, u) = repo.changes()
362 (c, a, d, u) = repo.changes()
363 repo.add(u)
363 repo.add(u)
364 repo.remove(d)
364 repo.remove(d)
365
365
366 def annotate(ui, repo, *pats, **opts):
366 def annotate(ui, repo, *pats, **opts):
367 """show changeset information per file line"""
367 """show changeset information per file line"""
368 def getnode(rev):
368 def getnode(rev):
369 return hg.short(repo.changelog.node(rev))
369 return hg.short(repo.changelog.node(rev))
370
370
371 def getname(rev):
371 def getname(rev):
372 try:
372 try:
373 return bcache[rev]
373 return bcache[rev]
374 except KeyError:
374 except KeyError:
375 cl = repo.changelog.read(repo.changelog.node(rev))
375 cl = repo.changelog.read(repo.changelog.node(rev))
376 name = cl[1]
376 name = cl[1]
377 f = name.find('@')
377 f = name.find('@')
378 if f >= 0:
378 if f >= 0:
379 name = name[:f]
379 name = name[:f]
380 f = name.find('<')
380 f = name.find('<')
381 if f >= 0:
381 if f >= 0:
382 name = name[f+1:]
382 name = name[f+1:]
383 bcache[rev] = name
383 bcache[rev] = name
384 return name
384 return name
385
385
386 bcache = {}
386 bcache = {}
387 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
387 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
388 if not opts['user'] and not opts['changeset']:
388 if not opts['user'] and not opts['changeset']:
389 opts['number'] = 1
389 opts['number'] = 1
390
390
391 if opts['rev']:
391 if opts['rev']:
392 node = repo.changelog.lookup(opts['rev'])
392 node = repo.changelog.lookup(opts['rev'])
393 else:
393 else:
394 node = repo.dirstate.parents()[0]
394 node = repo.dirstate.parents()[0]
395 change = repo.changelog.read(node)
395 change = repo.changelog.read(node)
396 mmap = repo.manifest.read(change[0])
396 mmap = repo.manifest.read(change[0])
397 for src, abs, rel in walk(repo, pats, opts, emptyok = False):
397 for src, abs, rel in walk(repo, pats, opts, emptyok = False):
398 lines = repo.file(abs).annotate(mmap[abs])
398 lines = repo.file(abs).annotate(mmap[abs])
399 pieces = []
399 pieces = []
400
400
401 for o, f in opmap:
401 for o, f in opmap:
402 if opts[o]:
402 if opts[o]:
403 l = [f(n) for n, dummy in lines]
403 l = [f(n) for n, dummy in lines]
404 m = max(map(len, l))
404 m = max(map(len, l))
405 pieces.append(["%*s" % (m, x) for x in l])
405 pieces.append(["%*s" % (m, x) for x in l])
406
406
407 for p, l in zip(zip(*pieces), lines):
407 for p, l in zip(zip(*pieces), lines):
408 ui.write("%s: %s" % (" ".join(p), l[1]))
408 ui.write("%s: %s" % (" ".join(p), l[1]))
409
409
410 def cat(ui, repo, file1, rev=None, **opts):
410 def cat(ui, repo, file1, rev=None, **opts):
411 """output the latest or given revision of a file"""
411 """output the latest or given revision of a file"""
412 r = repo.file(relpath(repo, [file1])[0])
412 r = repo.file(relpath(repo, [file1])[0])
413 if rev:
413 if rev:
414 n = r.lookup(rev)
414 n = r.lookup(rev)
415 else:
415 else:
416 n = r.tip()
416 n = r.tip()
417 fp = make_file(repo, r, opts['output'], node=n)
417 fp = make_file(repo, r, opts['output'], node=n)
418 fp.write(r.read(n))
418 fp.write(r.read(n))
419
419
420 def clone(ui, source, dest=None, **opts):
420 def clone(ui, source, dest=None, **opts):
421 """make a copy of an existing repository"""
421 """make a copy of an existing repository"""
422 if dest is None:
422 if dest is None:
423 dest = os.path.basename(os.path.normpath(source))
423 dest = os.path.basename(os.path.normpath(source))
424
424
425 if os.path.exists(dest):
425 if os.path.exists(dest):
426 ui.warn("abort: destination '%s' already exists\n" % dest)
426 ui.warn("abort: destination '%s' already exists\n" % dest)
427 return 1
427 return 1
428
428
429 class Dircleanup:
429 class Dircleanup:
430 def __init__(self, dir_):
430 def __init__(self, dir_):
431 self.rmtree = shutil.rmtree
431 self.rmtree = shutil.rmtree
432 self.dir_ = dir_
432 self.dir_ = dir_
433 os.mkdir(dir_)
433 os.mkdir(dir_)
434 def close(self):
434 def close(self):
435 self.dir_ = None
435 self.dir_ = None
436 def __del__(self):
436 def __del__(self):
437 if self.dir_:
437 if self.dir_:
438 self.rmtree(self.dir_, True)
438 self.rmtree(self.dir_, True)
439
439
440 d = Dircleanup(dest)
440 d = Dircleanup(dest)
441 abspath = source
441 abspath = source
442 source = ui.expandpath(source)
442 source = ui.expandpath(source)
443 other = hg.repository(ui, source)
443 other = hg.repository(ui, source)
444
444
445 if other.dev() != -1:
445 if other.dev() != -1:
446 abspath = os.path.abspath(source)
446 abspath = os.path.abspath(source)
447 copyfile = (os.stat(dest).st_dev == other.dev()
447 copyfile = (os.stat(dest).st_dev == other.dev()
448 and getattr(os, 'link', None) or shutil.copy2)
448 and getattr(os, 'link', None) or shutil.copy2)
449 if copyfile is not shutil.copy2:
449 if copyfile is not shutil.copy2:
450 ui.note("cloning by hardlink\n")
450 ui.note("cloning by hardlink\n")
451 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
451 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
452 copyfile)
452 copyfile)
453 try:
453 try:
454 os.unlink(os.path.join(dest, ".hg", "dirstate"))
454 os.unlink(os.path.join(dest, ".hg", "dirstate"))
455 except IOError:
455 except IOError:
456 pass
456 pass
457
457
458 repo = hg.repository(ui, dest)
458 repo = hg.repository(ui, dest)
459
459
460 else:
460 else:
461 repo = hg.repository(ui, dest, create=1)
461 repo = hg.repository(ui, dest, create=1)
462 repo.pull(other)
462 repo.pull(other)
463
463
464 f = repo.opener("hgrc", "w")
464 f = repo.opener("hgrc", "w")
465 f.write("[paths]\n")
465 f.write("[paths]\n")
466 f.write("default = %s\n" % abspath)
466 f.write("default = %s\n" % abspath)
467
467
468 if not opts['noupdate']:
468 if not opts['noupdate']:
469 update(ui, repo)
469 update(ui, repo)
470
470
471 d.close()
471 d.close()
472
472
473 def commit(ui, repo, *files, **opts):
473 def commit(ui, repo, *files, **opts):
474 """commit the specified files or all outstanding changes"""
474 """commit the specified files or all outstanding changes"""
475 text = opts['text']
475 text = opts['text']
476 logfile = opts['logfile']
476 logfile = opts['logfile']
477 if not text and logfile:
477 if not text and logfile:
478 try:
478 try:
479 text = open(logfile).read()
479 text = open(logfile).read()
480 except IOError, why:
480 except IOError, why:
481 ui.warn("Can't read commit text %s: %s\n" % (logfile, why))
481 ui.warn("Can't read commit text %s: %s\n" % (logfile, why))
482
482
483 if opts['addremove']:
483 if opts['addremove']:
484 addremove(ui, repo, *files)
484 addremove(ui, repo, *files)
485 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
485 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
486
486
487 def copy(ui, repo, source, dest):
487 def copy(ui, repo, source, dest):
488 """mark a file as copied or renamed for the next commit"""
488 """mark a file as copied or renamed for the next commit"""
489 return repo.copy(*relpath(repo, (source, dest)))
489 return repo.copy(*relpath(repo, (source, dest)))
490
490
491 def debugcheckstate(ui, repo):
491 def debugcheckstate(ui, repo):
492 """validate the correctness of the current dirstate"""
492 """validate the correctness of the current dirstate"""
493 parent1, parent2 = repo.dirstate.parents()
493 parent1, parent2 = repo.dirstate.parents()
494 repo.dirstate.read()
494 repo.dirstate.read()
495 dc = repo.dirstate.map
495 dc = repo.dirstate.map
496 keys = dc.keys()
496 keys = dc.keys()
497 keys.sort()
497 keys.sort()
498 m1n = repo.changelog.read(parent1)[0]
498 m1n = repo.changelog.read(parent1)[0]
499 m2n = repo.changelog.read(parent2)[0]
499 m2n = repo.changelog.read(parent2)[0]
500 m1 = repo.manifest.read(m1n)
500 m1 = repo.manifest.read(m1n)
501 m2 = repo.manifest.read(m2n)
501 m2 = repo.manifest.read(m2n)
502 errors = 0
502 errors = 0
503 for f in dc:
503 for f in dc:
504 state = repo.dirstate.state(f)
504 state = repo.dirstate.state(f)
505 if state in "nr" and f not in m1:
505 if state in "nr" and f not in m1:
506 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
506 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
507 errors += 1
507 errors += 1
508 if state in "a" and f in m1:
508 if state in "a" and f in m1:
509 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
509 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
510 errors += 1
510 errors += 1
511 if state in "m" and f not in m1 and f not in m2:
511 if state in "m" and f not in m1 and f not in m2:
512 ui.warn("%s in state %s, but not in either manifest\n" %
512 ui.warn("%s in state %s, but not in either manifest\n" %
513 (f, state))
513 (f, state))
514 errors += 1
514 errors += 1
515 for f in m1:
515 for f in m1:
516 state = repo.dirstate.state(f)
516 state = repo.dirstate.state(f)
517 if state not in "nrm":
517 if state not in "nrm":
518 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
518 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
519 errors += 1
519 errors += 1
520 if errors:
520 if errors:
521 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
521 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
522
522
523 def debugstate(ui, repo):
523 def debugstate(ui, repo):
524 """show the contents of the current dirstate"""
524 """show the contents of the current dirstate"""
525 repo.dirstate.read()
525 repo.dirstate.read()
526 dc = repo.dirstate.map
526 dc = repo.dirstate.map
527 keys = dc.keys()
527 keys = dc.keys()
528 keys.sort()
528 keys.sort()
529 for file_ in keys:
529 for file_ in keys:
530 ui.write("%c %s\n" % (dc[file_][0], file_))
530 ui.write("%c %s\n" % (dc[file_][0], file_))
531
531
532 def debugindex(ui, file_):
532 def debugindex(ui, file_):
533 """dump the contents of an index file"""
533 """dump the contents of an index file"""
534 r = hg.revlog(hg.opener(""), file_, "")
534 r = hg.revlog(hg.opener(""), file_, "")
535 ui.write(" rev offset length base linkrev" +
535 ui.write(" rev offset length base linkrev" +
536 " p1 p2 nodeid\n")
536 " p1 p2 nodeid\n")
537 for i in range(r.count()):
537 for i in range(r.count()):
538 e = r.index[i]
538 e = r.index[i]
539 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
539 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
540 i, e[0], e[1], e[2], e[3],
540 i, e[0], e[1], e[2], e[3],
541 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
541 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
542
542
543 def debugindexdot(ui, file_):
543 def debugindexdot(ui, file_):
544 """dump an index DAG as a .dot file"""
544 """dump an index DAG as a .dot file"""
545 r = hg.revlog(hg.opener(""), file_, "")
545 r = hg.revlog(hg.opener(""), file_, "")
546 ui.write("digraph G {\n")
546 ui.write("digraph G {\n")
547 for i in range(r.count()):
547 for i in range(r.count()):
548 e = r.index[i]
548 e = r.index[i]
549 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
549 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
550 if e[5] != hg.nullid:
550 if e[5] != hg.nullid:
551 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
551 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
552 ui.write("}\n")
552 ui.write("}\n")
553
553
554 def diff(ui, repo, *pats, **opts):
554 def diff(ui, repo, *pats, **opts):
555 """diff working directory (or selected files)"""
555 """diff working directory (or selected files)"""
556 revs = []
556 revs = []
557 if opts['rev']:
557 if opts['rev']:
558 revs = map(lambda x: repo.lookup(x), opts['rev'])
558 revs = map(lambda x: repo.lookup(x), opts['rev'])
559
559
560 if len(revs) > 2:
560 if len(revs) > 2:
561 raise Abort("too many revisions to diff")
561 raise Abort("too many revisions to diff")
562
562
563 files = []
563 files = []
564 for src, abs, rel in walk(repo, pats, opts):
564 for src, abs, rel in walk(repo, pats, opts):
565 files.append(abs)
565 files.append(abs)
566 dodiff(sys.stdout, ui, repo, files, *revs)
566 dodiff(sys.stdout, ui, repo, files, *revs)
567
567
568 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
568 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
569 node = repo.lookup(changeset)
569 node = repo.lookup(changeset)
570 prev, other = repo.changelog.parents(node)
570 prev, other = repo.changelog.parents(node)
571 change = repo.changelog.read(node)
571 change = repo.changelog.read(node)
572
572
573 fp = make_file(repo, repo.changelog, opts['output'],
573 fp = make_file(repo, repo.changelog, opts['output'],
574 node=node, total=total, seqno=seqno,
574 node=node, total=total, seqno=seqno,
575 revwidth=revwidth)
575 revwidth=revwidth)
576 if fp != sys.stdout:
576 if fp != sys.stdout:
577 ui.note("Exporting patch to '%s'.\n" % fp.name)
577 ui.note("Exporting patch to '%s'.\n" % fp.name)
578
578
579 fp.write("# HG changeset patch\n")
579 fp.write("# HG changeset patch\n")
580 fp.write("# User %s\n" % change[1])
580 fp.write("# User %s\n" % change[1])
581 fp.write("# Node ID %s\n" % hg.hex(node))
581 fp.write("# Node ID %s\n" % hg.hex(node))
582 fp.write("# Parent %s\n" % hg.hex(prev))
582 fp.write("# Parent %s\n" % hg.hex(prev))
583 if other != hg.nullid:
583 if other != hg.nullid:
584 fp.write("# Parent %s\n" % hg.hex(other))
584 fp.write("# Parent %s\n" % hg.hex(other))
585 fp.write(change[4].rstrip())
585 fp.write(change[4].rstrip())
586 fp.write("\n\n")
586 fp.write("\n\n")
587
587
588 dodiff(fp, ui, repo, None, prev, node)
588 dodiff(fp, ui, repo, None, prev, node)
589
589
590 def export(ui, repo, *changesets, **opts):
590 def export(ui, repo, *changesets, **opts):
591 """dump the header and diffs for one or more changesets"""
591 """dump the header and diffs for one or more changesets"""
592 if not changesets:
592 if not changesets:
593 raise Abort("export requires at least one changeset")
593 raise Abort("export requires at least one changeset")
594 seqno = 0
594 seqno = 0
595 revs = list(revrange(ui, repo, changesets))
595 revs = list(revrange(ui, repo, changesets))
596 total = len(revs)
596 total = len(revs)
597 revwidth = max(len(revs[0]), len(revs[-1]))
597 revwidth = max(len(revs[0]), len(revs[-1]))
598 for cset in revs:
598 for cset in revs:
599 seqno += 1
599 seqno += 1
600 doexport(ui, repo, cset, seqno, total, revwidth, opts)
600 doexport(ui, repo, cset, seqno, total, revwidth, opts)
601
601
602 def forget(ui, repo, file1, *files):
602 def forget(ui, repo, file1, *files):
603 """don't add the specified files on the next commit"""
603 """don't add the specified files on the next commit"""
604 repo.forget(relpath(repo, (file1,) + files))
604 repo.forget(relpath(repo, (file1,) + files))
605
605
606 def heads(ui, repo):
606 def heads(ui, repo):
607 """show current repository heads"""
607 """show current repository heads"""
608 for n in repo.changelog.heads():
608 for n in repo.changelog.heads():
609 show_changeset(ui, repo, changenode=n)
609 show_changeset(ui, repo, changenode=n)
610
610
611 def identify(ui, repo):
611 def identify(ui, repo):
612 """print information about the working copy"""
612 """print information about the working copy"""
613 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
613 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
614 if not parents:
614 if not parents:
615 ui.write("unknown\n")
615 ui.write("unknown\n")
616 return
616 return
617
617
618 hexfunc = ui.verbose and hg.hex or hg.short
618 hexfunc = ui.verbose and hg.hex or hg.short
619 (c, a, d, u) = repo.changes()
619 (c, a, d, u) = repo.changes()
620 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
620 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
621 (c or a or d) and "+" or "")]
621 (c or a or d) and "+" or "")]
622
622
623 if not ui.quiet:
623 if not ui.quiet:
624 # multiple tags for a single parent separated by '/'
624 # multiple tags for a single parent separated by '/'
625 parenttags = ['/'.join(tags)
625 parenttags = ['/'.join(tags)
626 for tags in map(repo.nodetags, parents) if tags]
626 for tags in map(repo.nodetags, parents) if tags]
627 # tags for multiple parents separated by ' + '
627 # tags for multiple parents separated by ' + '
628 output.append(' + '.join(parenttags))
628 output.append(' + '.join(parenttags))
629
629
630 ui.write("%s\n" % ' '.join(output))
630 ui.write("%s\n" % ' '.join(output))
631
631
632 def import_(ui, repo, patch1, *patches, **opts):
632 def import_(ui, repo, patch1, *patches, **opts):
633 """import an ordered set of patches"""
633 """import an ordered set of patches"""
634 try:
634 try:
635 import psyco
635 import psyco
636 psyco.full()
636 psyco.full()
637 except ImportError:
637 except ImportError:
638 pass
638 pass
639
639
640 patches = (patch1,) + patches
640 patches = (patch1,) + patches
641
641
642 d = opts["base"]
642 d = opts["base"]
643 strip = opts["strip"]
643 strip = opts["strip"]
644
644
645 for patch in patches:
645 for patch in patches:
646 ui.status("applying %s\n" % patch)
646 ui.status("applying %s\n" % patch)
647 pf = os.path.join(d, patch)
647 pf = os.path.join(d, patch)
648
648
649 text = []
649 text = []
650 user = None
650 user = None
651 hgpatch = False
651 hgpatch = False
652 for line in file(pf):
652 for line in file(pf):
653 line = line.rstrip()
653 line = line.rstrip()
654 if line.startswith("--- ") or line.startswith("diff -r"):
654 if line.startswith("--- ") or line.startswith("diff -r"):
655 break
655 break
656 elif hgpatch:
656 elif hgpatch:
657 # parse values when importing the result of an hg export
657 # parse values when importing the result of an hg export
658 if line.startswith("# User "):
658 if line.startswith("# User "):
659 user = line[7:]
659 user = line[7:]
660 ui.debug('User: %s\n' % user)
660 ui.debug('User: %s\n' % user)
661 elif not line.startswith("# ") and line:
661 elif not line.startswith("# ") and line:
662 text.append(line)
662 text.append(line)
663 hgpatch = False
663 hgpatch = False
664 elif line == '# HG changeset patch':
664 elif line == '# HG changeset patch':
665 hgpatch = True
665 hgpatch = True
666 else:
666 else:
667 text.append(line)
667 text.append(line)
668
668
669 # make sure text isn't empty
669 # make sure text isn't empty
670 if not text:
670 if not text:
671 text = "imported patch %s\n" % patch
671 text = "imported patch %s\n" % patch
672 else:
672 else:
673 text = "%s\n" % '\n'.join(text)
673 text = "%s\n" % '\n'.join(text)
674 ui.debug('text:\n%s\n' % text)
674 ui.debug('text:\n%s\n' % text)
675
675
676 f = os.popen("patch -p%d < %s" % (strip, pf))
676 f = os.popen("patch -p%d < %s" % (strip, pf))
677 files = []
677 files = []
678 for l in f.read().splitlines():
678 for l in f.read().splitlines():
679 l.rstrip('\r\n');
679 l.rstrip('\r\n');
680 ui.status("%s\n" % l)
680 ui.status("%s\n" % l)
681 if l.startswith('patching file '):
681 if l.startswith('patching file '):
682 pf = l[14:]
682 pf = l[14:]
683 if pf not in files:
683 if pf not in files:
684 files.append(pf)
684 files.append(pf)
685 patcherr = f.close()
685 patcherr = f.close()
686 if patcherr:
686 if patcherr:
687 raise Abort("patch failed")
687 raise Abort("patch failed")
688
688
689 if len(files) > 0:
689 if len(files) > 0:
690 addremove(ui, repo, *files)
690 addremove(ui, repo, *files)
691 repo.commit(files, text, user)
691 repo.commit(files, text, user)
692
692
693 def init(ui, source=None):
693 def init(ui, source=None):
694 """create a new repository in the current directory"""
694 """create a new repository in the current directory"""
695
695
696 if source:
696 if source:
697 raise Abort("no longer supported: use \"hg clone\" instead")
697 raise Abort("no longer supported: use \"hg clone\" instead")
698 hg.repository(ui, ".", create=1)
698 hg.repository(ui, ".", create=1)
699
699
700 def locate(ui, repo, *pats, **opts):
700 def locate(ui, repo, *pats, **opts):
701 """locate files matching specific patterns"""
701 """locate files matching specific patterns"""
702 if opts['print0']: end = '\0'
702 if opts['print0']: end = '\0'
703 else: end = '\n'
703 else: end = '\n'
704 opts['rootless'] = True
704 opts['rootless'] = True
705 for src, abs, rel in walk(repo, pats, opts):
705 for src, abs, rel in walk(repo, pats, opts):
706 if repo.dirstate.state(abs) == '?': continue
706 if repo.dirstate.state(abs) == '?': continue
707 if opts['fullpath']:
707 if opts['fullpath']:
708 ui.write(os.path.join(repo.root, abs), end)
708 ui.write(os.path.join(repo.root, abs), end)
709 else:
709 else:
710 ui.write(rel, end)
710 ui.write(rel, end)
711
711
712 def log(ui, repo, f=None, **opts):
712 def log(ui, repo, f=None, **opts):
713 """show the revision history of the repository or a single file"""
713 """show the revision history of the repository or a single file"""
714 if f:
714 if f:
715 files = relpath(repo, [f])
715 files = relpath(repo, [f])
716 filelog = repo.file(files[0])
716 filelog = repo.file(files[0])
717 log = filelog
717 log = filelog
718 lookup = filelog.lookup
718 lookup = filelog.lookup
719 else:
719 else:
720 files = None
720 files = None
721 filelog = None
721 filelog = None
722 log = repo.changelog
722 log = repo.changelog
723 lookup = repo.lookup
723 lookup = repo.lookup
724 revlist = []
724 revlist = []
725 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
725 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
726 while revs:
726 while revs:
727 if len(revs) == 1:
727 if len(revs) == 1:
728 revlist.append(revs.pop(0))
728 revlist.append(revs.pop(0))
729 else:
729 else:
730 a = revs.pop(0)
730 a = revs.pop(0)
731 b = revs.pop(0)
731 b = revs.pop(0)
732 off = a > b and -1 or 1
732 off = a > b and -1 or 1
733 revlist.extend(range(a, b + off, off))
733 revlist.extend(range(a, b + off, off))
734
734
735 for i in revlist or range(log.count() - 1, -1, -1):
735 for i in revlist or range(log.count() - 1, -1, -1):
736 show_changeset(ui, repo, filelog=filelog, rev=i)
736 show_changeset(ui, repo, filelog=filelog, rev=i)
737 if opts['patch']:
737 if opts['patch']:
738 if filelog:
738 if filelog:
739 filenode = filelog.node(i)
739 filenode = filelog.node(i)
740 i = filelog.linkrev(filenode)
740 i = filelog.linkrev(filenode)
741 changenode = repo.changelog.node(i)
741 changenode = repo.changelog.node(i)
742 prev, other = repo.changelog.parents(changenode)
742 prev, other = repo.changelog.parents(changenode)
743 dodiff(sys.stdout, ui, repo, files, prev, changenode)
743 dodiff(sys.stdout, ui, repo, files, prev, changenode)
744 ui.write("\n\n")
744 ui.write("\n\n")
745
745
746 def ls(ui, repo, *pats, **opts):
746 def ls(ui, repo, *pats, **opts):
747 """list files"""
747 """list files"""
748 for src, abs, rel in walk(repo, pats, opts):
748 for src, abs, rel in walk(repo, pats, opts):
749 ui.write(rel, '\n')
749 ui.write(rel, '\n')
750
750
751 def manifest(ui, repo, rev=None):
751 def manifest(ui, repo, rev=None):
752 """output the latest or given revision of the project manifest"""
752 """output the latest or given revision of the project manifest"""
753 if rev:
753 if rev:
754 try:
754 try:
755 # assume all revision numbers are for changesets
755 # assume all revision numbers are for changesets
756 n = repo.lookup(rev)
756 n = repo.lookup(rev)
757 change = repo.changelog.read(n)
757 change = repo.changelog.read(n)
758 n = change[0]
758 n = change[0]
759 except hg.RepoError:
759 except hg.RepoError:
760 n = repo.manifest.lookup(rev)
760 n = repo.manifest.lookup(rev)
761 else:
761 else:
762 n = repo.manifest.tip()
762 n = repo.manifest.tip()
763 m = repo.manifest.read(n)
763 m = repo.manifest.read(n)
764 mf = repo.manifest.readflags(n)
764 mf = repo.manifest.readflags(n)
765 files = m.keys()
765 files = m.keys()
766 files.sort()
766 files.sort()
767
767
768 for f in files:
768 for f in files:
769 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
769 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
770
770
771 def parents(ui, repo, rev=None):
771 def parents(ui, repo, rev=None):
772 """show the parents of the working dir or revision"""
772 """show the parents of the working dir or revision"""
773 if rev:
773 if rev:
774 p = repo.changelog.parents(repo.lookup(rev))
774 p = repo.changelog.parents(repo.lookup(rev))
775 else:
775 else:
776 p = repo.dirstate.parents()
776 p = repo.dirstate.parents()
777
777
778 for n in p:
778 for n in p:
779 if n != hg.nullid:
779 if n != hg.nullid:
780 show_changeset(ui, repo, changenode=n)
780 show_changeset(ui, repo, changenode=n)
781
781
782 def pull(ui, repo, source="default", **opts):
782 def pull(ui, repo, source="default", **opts):
783 """pull changes from the specified source"""
783 """pull changes from the specified source"""
784 source = ui.expandpath(source)
784 source = ui.expandpath(source)
785 ui.status('pulling from %s\n' % (source))
785 ui.status('pulling from %s\n' % (source))
786
786
787 other = hg.repository(ui, source)
787 other = hg.repository(ui, source)
788 r = repo.pull(other)
788 r = repo.pull(other)
789 if not r:
789 if not r:
790 if opts['update']:
790 if opts['update']:
791 return update(ui, repo)
791 return update(ui, repo)
792 else:
792 else:
793 ui.status("(run 'hg update' to get a working copy)\n")
793 ui.status("(run 'hg update' to get a working copy)\n")
794
794
795 return r
795 return r
796
796
797 def push(ui, repo, dest="default-push"):
797 def push(ui, repo, dest="default-push"):
798 """push changes to the specified destination"""
798 """push changes to the specified destination"""
799 dest = ui.expandpath(dest)
799 dest = ui.expandpath(dest)
800 ui.status('pushing to %s\n' % (dest))
800 ui.status('pushing to %s\n' % (dest))
801
801
802 other = hg.repository(ui, dest)
802 other = hg.repository(ui, dest)
803 r = repo.push(other)
803 r = repo.push(other)
804 return r
804 return r
805
805
806 def rawcommit(ui, repo, *flist, **rc):
806 def rawcommit(ui, repo, *flist, **rc):
807 "raw commit interface"
807 "raw commit interface"
808
808
809 text = rc['text']
809 text = rc['text']
810 if not text and rc['logfile']:
810 if not text and rc['logfile']:
811 try:
811 try:
812 text = open(rc['logfile']).read()
812 text = open(rc['logfile']).read()
813 except IOError:
813 except IOError:
814 pass
814 pass
815 if not text and not rc['logfile']:
815 if not text and not rc['logfile']:
816 ui.warn("abort: missing commit text\n")
816 ui.warn("abort: missing commit text\n")
817 return 1
817 return 1
818
818
819 files = relpath(repo, list(flist))
819 files = relpath(repo, list(flist))
820 if rc['files']:
820 if rc['files']:
821 files += open(rc['files']).read().splitlines()
821 files += open(rc['files']).read().splitlines()
822
822
823 rc['parent'] = map(repo.lookup, rc['parent'])
823 rc['parent'] = map(repo.lookup, rc['parent'])
824
824
825 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
825 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
826
826
827 def recover(ui, repo):
827 def recover(ui, repo):
828 """roll back an interrupted transaction"""
828 """roll back an interrupted transaction"""
829 repo.recover()
829 repo.recover()
830
830
831 def remove(ui, repo, file1, *files):
831 def remove(ui, repo, file1, *files):
832 """remove the specified files on the next commit"""
832 """remove the specified files on the next commit"""
833 repo.remove(relpath(repo, (file1,) + files))
833 repo.remove(relpath(repo, (file1,) + files))
834
834
835 def revert(ui, repo, *names, **opts):
835 def revert(ui, repo, *names, **opts):
836 """revert modified files or dirs back to their unmodified states"""
836 """revert modified files or dirs back to their unmodified states"""
837 node = opts['rev'] and repo.lookup(opts['rev']) or \
837 node = opts['rev'] and repo.lookup(opts['rev']) or \
838 repo.dirstate.parents()[0]
838 repo.dirstate.parents()[0]
839 root = os.path.realpath(repo.root)
839 root = os.path.realpath(repo.root)
840
840
841 def trimpath(p):
841 def trimpath(p):
842 p = os.path.realpath(p)
842 p = os.path.realpath(p)
843 if p.startswith(root):
843 if p.startswith(root):
844 rest = p[len(root):]
844 rest = p[len(root):]
845 if not rest:
845 if not rest:
846 return rest
846 return rest
847 if p.startswith(os.sep):
847 if p.startswith(os.sep):
848 return rest[1:]
848 return rest[1:]
849 return p
849 return p
850
850
851 relnames = map(trimpath, names or [os.getcwd()])
851 relnames = map(trimpath, names or [os.getcwd()])
852 chosen = {}
852 chosen = {}
853
853
854 def choose(name):
854 def choose(name):
855 def body(name):
855 def body(name):
856 for r in relnames:
856 for r in relnames:
857 if not name.startswith(r):
857 if not name.startswith(r):
858 continue
858 continue
859 rest = name[len(r):]
859 rest = name[len(r):]
860 if not rest:
860 if not rest:
861 return r, True
861 return r, True
862 depth = rest.count(os.sep)
862 depth = rest.count(os.sep)
863 if not r:
863 if not r:
864 if depth == 0 or not opts['nonrecursive']:
864 if depth == 0 or not opts['nonrecursive']:
865 return r, True
865 return r, True
866 elif rest[0] == os.sep:
866 elif rest[0] == os.sep:
867 if depth == 1 or not opts['nonrecursive']:
867 if depth == 1 or not opts['nonrecursive']:
868 return r, True
868 return r, True
869 return None, False
869 return None, False
870 relname, ret = body(name)
870 relname, ret = body(name)
871 if ret:
871 if ret:
872 chosen[relname] = 1
872 chosen[relname] = 1
873 return ret
873 return ret
874
874
875 r = repo.update(node, False, True, choose, False)
875 r = repo.update(node, False, True, choose, False)
876 for n in relnames:
876 for n in relnames:
877 if n not in chosen:
877 if n not in chosen:
878 ui.warn('error: no matches for %s\n' % n)
878 ui.warn('error: no matches for %s\n' % n)
879 r = 1
879 r = 1
880 sys.stdout.flush()
880 sys.stdout.flush()
881 return r
881 return r
882
882
883 def root(ui, repo):
883 def root(ui, repo):
884 """print the root (top) of the current working dir"""
884 """print the root (top) of the current working dir"""
885 ui.write(repo.root + "\n")
885 ui.write(repo.root + "\n")
886
886
887 def serve(ui, repo, **opts):
887 def serve(ui, repo, **opts):
888 """export the repository via HTTP"""
888 """export the repository via HTTP"""
889
889
890 if opts["stdio"]:
890 if opts["stdio"]:
891 fin, fout = sys.stdin, sys.stdout
891 fin, fout = sys.stdin, sys.stdout
892 sys.stdout = sys.stderr
892 sys.stdout = sys.stderr
893
893
894 def getarg():
894 def getarg():
895 argline = fin.readline()[:-1]
895 argline = fin.readline()[:-1]
896 arg, l = argline.split()
896 arg, l = argline.split()
897 val = fin.read(int(l))
897 val = fin.read(int(l))
898 return arg, val
898 return arg, val
899 def respond(v):
899 def respond(v):
900 fout.write("%d\n" % len(v))
900 fout.write("%d\n" % len(v))
901 fout.write(v)
901 fout.write(v)
902 fout.flush()
902 fout.flush()
903
903
904 lock = None
904 lock = None
905
905
906 while 1:
906 while 1:
907 cmd = fin.readline()[:-1]
907 cmd = fin.readline()[:-1]
908 if cmd == '':
908 if cmd == '':
909 return
909 return
910 if cmd == "heads":
910 if cmd == "heads":
911 h = repo.heads()
911 h = repo.heads()
912 respond(" ".join(map(hg.hex, h)) + "\n")
912 respond(" ".join(map(hg.hex, h)) + "\n")
913 if cmd == "lock":
913 if cmd == "lock":
914 lock = repo.lock()
914 lock = repo.lock()
915 respond("")
915 respond("")
916 if cmd == "unlock":
916 if cmd == "unlock":
917 if lock:
917 if lock:
918 lock.release()
918 lock.release()
919 lock = None
919 lock = None
920 respond("")
920 respond("")
921 elif cmd == "branches":
921 elif cmd == "branches":
922 arg, nodes = getarg()
922 arg, nodes = getarg()
923 nodes = map(hg.bin, nodes.split(" "))
923 nodes = map(hg.bin, nodes.split(" "))
924 r = []
924 r = []
925 for b in repo.branches(nodes):
925 for b in repo.branches(nodes):
926 r.append(" ".join(map(hg.hex, b)) + "\n")
926 r.append(" ".join(map(hg.hex, b)) + "\n")
927 respond("".join(r))
927 respond("".join(r))
928 elif cmd == "between":
928 elif cmd == "between":
929 arg, pairs = getarg()
929 arg, pairs = getarg()
930 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
930 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
931 r = []
931 r = []
932 for b in repo.between(pairs):
932 for b in repo.between(pairs):
933 r.append(" ".join(map(hg.hex, b)) + "\n")
933 r.append(" ".join(map(hg.hex, b)) + "\n")
934 respond("".join(r))
934 respond("".join(r))
935 elif cmd == "changegroup":
935 elif cmd == "changegroup":
936 nodes = []
936 nodes = []
937 arg, roots = getarg()
937 arg, roots = getarg()
938 nodes = map(hg.bin, roots.split(" "))
938 nodes = map(hg.bin, roots.split(" "))
939
939
940 cg = repo.changegroup(nodes)
940 cg = repo.changegroup(nodes)
941 while 1:
941 while 1:
942 d = cg.read(4096)
942 d = cg.read(4096)
943 if not d:
943 if not d:
944 break
944 break
945 fout.write(d)
945 fout.write(d)
946
946
947 fout.flush()
947 fout.flush()
948
948
949 elif cmd == "addchangegroup":
949 elif cmd == "addchangegroup":
950 if not lock:
950 if not lock:
951 respond("not locked")
951 respond("not locked")
952 continue
952 continue
953 respond("")
953 respond("")
954
954
955 r = repo.addchangegroup(fin)
955 r = repo.addchangegroup(fin)
956 respond("")
956 respond("")
957
957
958 def openlog(opt, default):
958 def openlog(opt, default):
959 if opts[opt] and opts[opt] != '-':
959 if opts[opt] and opts[opt] != '-':
960 return open(opts[opt], 'w')
960 return open(opts[opt], 'w')
961 else:
961 else:
962 return default
962 return default
963
963
964 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
964 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
965 opts["address"], opts["port"],
965 opts["address"], opts["port"],
966 openlog('accesslog', sys.stdout),
966 openlog('accesslog', sys.stdout),
967 openlog('errorlog', sys.stderr))
967 openlog('errorlog', sys.stderr))
968 if ui.verbose:
968 if ui.verbose:
969 addr, port = httpd.socket.getsockname()
969 addr, port = httpd.socket.getsockname()
970 if addr == '0.0.0.0':
970 if addr == '0.0.0.0':
971 addr = socket.gethostname()
971 addr = socket.gethostname()
972 else:
972 else:
973 try:
973 try:
974 addr = socket.gethostbyaddr(addr)[0]
974 addr = socket.gethostbyaddr(addr)[0]
975 except socket.error:
975 except socket.error:
976 pass
976 pass
977 if port != 80:
977 if port != 80:
978 ui.status('listening at http://%s:%d/\n' % (addr, port))
978 ui.status('listening at http://%s:%d/\n' % (addr, port))
979 else:
979 else:
980 ui.status('listening at http://%s/\n' % addr)
980 ui.status('listening at http://%s/\n' % addr)
981 httpd.serve_forever()
981 httpd.serve_forever()
982
982
983 def status(ui, repo, *pats, **opts):
983 def status(ui, repo, *pats, **opts):
984 '''show changed files in the working directory
984 '''show changed files in the working directory
985
985
986 C = changed
986 C = changed
987 A = added
987 A = added
988 R = removed
988 R = removed
989 ? = not tracked'''
989 ? = not tracked'''
990
990
991 (c, a, d, u) = repo.changes(match = matchpats(ui, repo.getcwd(),
991 (c, a, d, u) = repo.changes(match = matchpats(ui, repo.getcwd(),
992 pats, opts))
992 pats, opts))
993 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
993 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
994
994
995 for f in c:
995 for f in c:
996 ui.write("C ", f, "\n")
996 ui.write("C ", f, "\n")
997 for f in a:
997 for f in a:
998 ui.write("A ", f, "\n")
998 ui.write("A ", f, "\n")
999 for f in d:
999 for f in d:
1000 ui.write("R ", f, "\n")
1000 ui.write("R ", f, "\n")
1001 for f in u:
1001 for f in u:
1002 ui.write("? ", f, "\n")
1002 ui.write("? ", f, "\n")
1003
1003
1004 def tag(ui, repo, name, rev=None, **opts):
1004 def tag(ui, repo, name, rev=None, **opts):
1005 """add a tag for the current tip or a given revision"""
1005 """add a tag for the current tip or a given revision"""
1006
1006
1007 if name == "tip":
1007 if name == "tip":
1008 ui.warn("abort: 'tip' is a reserved name!\n")
1008 ui.warn("abort: 'tip' is a reserved name!\n")
1009 return -1
1009 return -1
1010 if rev:
1010 if rev:
1011 r = hg.hex(repo.lookup(rev))
1011 r = hg.hex(repo.lookup(rev))
1012 else:
1012 else:
1013 r = hg.hex(repo.changelog.tip())
1013 r = hg.hex(repo.changelog.tip())
1014
1014
1015 if name.find(revrangesep) >= 0:
1015 if name.find(revrangesep) >= 0:
1016 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1016 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1017 return -1
1017 return -1
1018
1018
1019 if opts['local']:
1019 if opts['local']:
1020 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1020 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1021 return
1021 return
1022
1022
1023 (c, a, d, u) = repo.changes()
1023 (c, a, d, u) = repo.changes()
1024 for x in (c, a, d, u):
1024 for x in (c, a, d, u):
1025 if ".hgtags" in x:
1025 if ".hgtags" in x:
1026 ui.warn("abort: working copy of .hgtags is changed!\n")
1026 ui.warn("abort: working copy of .hgtags is changed!\n")
1027 ui.status("(please commit .hgtags manually)\n")
1027 ui.status("(please commit .hgtags manually)\n")
1028 return -1
1028 return -1
1029
1029
1030 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1030 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1031 if repo.dirstate.state(".hgtags") == '?':
1031 if repo.dirstate.state(".hgtags") == '?':
1032 repo.add([".hgtags"])
1032 repo.add([".hgtags"])
1033
1033
1034 if not opts['text']:
1034 if not opts['text']:
1035 opts['text'] = "Added tag %s for changeset %s" % (name, r)
1035 opts['text'] = "Added tag %s for changeset %s" % (name, r)
1036
1036
1037 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
1037 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
1038
1038
1039 def tags(ui, repo):
1039 def tags(ui, repo):
1040 """list repository tags"""
1040 """list repository tags"""
1041
1041
1042 l = repo.tagslist()
1042 l = repo.tagslist()
1043 l.reverse()
1043 l.reverse()
1044 for t, n in l:
1044 for t, n in l:
1045 try:
1045 try:
1046 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1046 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1047 except KeyError:
1047 except KeyError:
1048 r = " ?:?"
1048 r = " ?:?"
1049 ui.write("%-30s %s\n" % (t, r))
1049 ui.write("%-30s %s\n" % (t, r))
1050
1050
1051 def tip(ui, repo):
1051 def tip(ui, repo):
1052 """show the tip revision"""
1052 """show the tip revision"""
1053 n = repo.changelog.tip()
1053 n = repo.changelog.tip()
1054 show_changeset(ui, repo, changenode=n)
1054 show_changeset(ui, repo, changenode=n)
1055
1055
1056 def undo(ui, repo):
1056 def undo(ui, repo):
1057 """undo the last commit or pull
1057 """undo the last commit or pull
1058
1058
1059 Roll back the last pull or commit transaction on the
1059 Roll back the last pull or commit transaction on the
1060 repository, restoring the project to its earlier state.
1060 repository, restoring the project to its earlier state.
1061
1061
1062 This command should be used with care. There is only one level of
1062 This command should be used with care. There is only one level of
1063 undo and there is no redo.
1063 undo and there is no redo.
1064
1064
1065 This command is not intended for use on public repositories. Once
1065 This command is not intended for use on public repositories. Once
1066 a change is visible for pull by other users, undoing it locally is
1066 a change is visible for pull by other users, undoing it locally is
1067 ineffective.
1067 ineffective.
1068 """
1068 """
1069 repo.undo()
1069 repo.undo()
1070
1070
1071 def update(ui, repo, node=None, merge=False, clean=False):
1071 def update(ui, repo, node=None, merge=False, clean=False):
1072 '''update or merge working directory
1072 '''update or merge working directory
1073
1073
1074 If there are no outstanding changes in the working directory and
1074 If there are no outstanding changes in the working directory and
1075 there is a linear relationship between the current version and the
1075 there is a linear relationship between the current version and the
1076 requested version, the result is the requested version.
1076 requested version, the result is the requested version.
1077
1077
1078 Otherwise the result is a merge between the contents of the
1078 Otherwise the result is a merge between the contents of the
1079 current working directory and the requested version. Files that
1079 current working directory and the requested version. Files that
1080 changed between either parent are marked as changed for the next
1080 changed between either parent are marked as changed for the next
1081 commit and a commit must be performed before any further updates
1081 commit and a commit must be performed before any further updates
1082 are allowed.
1082 are allowed.
1083 '''
1083 '''
1084 node = node and repo.lookup(node) or repo.changelog.tip()
1084 node = node and repo.lookup(node) or repo.changelog.tip()
1085 return repo.update(node, allow=merge, force=clean)
1085 return repo.update(node, allow=merge, force=clean)
1086
1086
1087 def verify(ui, repo):
1087 def verify(ui, repo):
1088 """verify the integrity of the repository"""
1088 """verify the integrity of the repository"""
1089 return repo.verify()
1089 return repo.verify()
1090
1090
1091 # Command options and aliases are listed here, alphabetically
1091 # Command options and aliases are listed here, alphabetically
1092
1092
1093 table = {
1093 table = {
1094 "^add": (add,
1094 "^add": (add,
1095 [('I', 'include', [], 'include path in search'),
1095 [('I', 'include', [], 'include path in search'),
1096 ('X', 'exclude', [], 'exclude path from search')],
1096 ('X', 'exclude', [], 'exclude path from search')],
1097 "hg add [OPTIONS] [FILES]"),
1097 "hg add [OPTIONS] [FILES]"),
1098 "addremove": (addremove, [], "hg addremove [FILES]"),
1098 "addremove": (addremove, [], "hg addremove [FILES]"),
1099 "^annotate":
1099 "^annotate":
1100 (annotate,
1100 (annotate,
1101 [('r', 'rev', '', 'revision'),
1101 [('I', 'include', [], 'include path in search'),
1102 ('X', 'exclude', [], 'exclude path from search'),
1103 ('r', 'rev', '', 'revision'),
1102 ('u', 'user', None, 'show user'),
1104 ('u', 'user', None, 'show user'),
1103 ('n', 'number', None, 'show revision number'),
1105 ('n', 'number', None, 'show revision number'),
1104 ('c', 'changeset', None, 'show changeset')],
1106 ('c', 'changeset', None, 'show changeset')],
1105 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1107 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1106 "cat":
1108 "cat":
1107 (cat,
1109 (cat,
1108 [('o', 'output', "", 'output to file')],
1110 [('o', 'output', "", 'output to file')],
1109 'hg cat [-o OUTFILE] FILE [REV]'),
1111 'hg cat [-o OUTFILE] FILE [REV]'),
1110 "^clone":
1112 "^clone":
1111 (clone,
1113 (clone,
1112 [('U', 'noupdate', None, 'skip update after cloning')],
1114 [('U', 'noupdate', None, 'skip update after cloning')],
1113 'hg clone [-U] SOURCE [DEST]'),
1115 'hg clone [-U] SOURCE [DEST]'),
1114 "^commit|ci":
1116 "^commit|ci":
1115 (commit,
1117 (commit,
1116 [('A', 'addremove', None, 'run add/remove during commit'),
1118 [('A', 'addremove', None, 'run add/remove during commit'),
1117 ('t', 'text', "", 'commit text'),
1119 ('t', 'text', "", 'commit text'),
1118 ('l', 'logfile', "", 'commit text file'),
1120 ('l', 'logfile', "", 'commit text file'),
1119 ('d', 'date', "", 'date code'),
1121 ('d', 'date', "", 'date code'),
1120 ('u', 'user', "", 'user')],
1122 ('u', 'user', "", 'user')],
1121 'hg commit [OPTION]... [FILE]...'),
1123 'hg commit [OPTION]... [FILE]...'),
1122 "copy": (copy, [], 'hg copy SOURCE DEST'),
1124 "copy": (copy, [], 'hg copy SOURCE DEST'),
1123 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1125 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1124 "debugstate": (debugstate, [], 'debugstate'),
1126 "debugstate": (debugstate, [], 'debugstate'),
1125 "debugindex": (debugindex, [], 'debugindex FILE'),
1127 "debugindex": (debugindex, [], 'debugindex FILE'),
1126 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1128 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1127 "^diff":
1129 "^diff":
1128 (diff,
1130 (diff,
1129 [('I', 'include', [], 'include path in search'),
1131 [('I', 'include', [], 'include path in search'),
1130 ('X', 'exclude', [], 'exclude path from search'),
1132 ('X', 'exclude', [], 'exclude path from search'),
1131 ('r', 'rev', [], 'revision')],
1133 ('r', 'rev', [], 'revision')],
1132 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1134 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1133 "^export":
1135 "^export":
1134 (export,
1136 (export,
1135 [('o', 'output', "", 'output to file')],
1137 [('o', 'output', "", 'output to file')],
1136 "hg export [-o OUTFILE] REV..."),
1138 "hg export [-o OUTFILE] REV..."),
1137 "forget": (forget, [], "hg forget FILE..."),
1139 "forget": (forget, [], "hg forget FILE..."),
1138 "heads": (heads, [], 'hg heads'),
1140 "heads": (heads, [], 'hg heads'),
1139 "help": (help_, [], 'hg help [COMMAND]'),
1141 "help": (help_, [], 'hg help [COMMAND]'),
1140 "identify|id": (identify, [], 'hg identify'),
1142 "identify|id": (identify, [], 'hg identify'),
1141 "import|patch":
1143 "import|patch":
1142 (import_,
1144 (import_,
1143 [('p', 'strip', 1, 'path strip'),
1145 [('p', 'strip', 1, 'path strip'),
1144 ('b', 'base', "", 'base path')],
1146 ('b', 'base', "", 'base path')],
1145 "hg import [-p NUM] [-b BASE] PATCH..."),
1147 "hg import [-p NUM] [-b BASE] PATCH..."),
1146 "^init": (init, [], 'hg init'),
1148 "^init": (init, [], 'hg init'),
1147 "locate":
1149 "locate":
1148 (locate,
1150 (locate,
1149 [('0', 'print0', None, 'end records with NUL'),
1151 [('0', 'print0', None, 'end records with NUL'),
1150 ('f', 'fullpath', None, 'print complete paths'),
1152 ('f', 'fullpath', None, 'print complete paths'),
1151 ('I', 'include', [], 'include path in search'),
1153 ('I', 'include', [], 'include path in search'),
1152 ('r', 'rev', '', 'revision'),
1154 ('r', 'rev', '', 'revision'),
1153 ('X', 'exclude', [], 'exclude path from search')],
1155 ('X', 'exclude', [], 'exclude path from search')],
1154 'hg locate [OPTION]... [PATTERN]...'),
1156 'hg locate [OPTION]... [PATTERN]...'),
1155 "^log|history":
1157 "^log|history":
1156 (log,
1158 (log,
1157 [('r', 'rev', [], 'revision'),
1159 [('r', 'rev', [], 'revision'),
1158 ('p', 'patch', None, 'show patch')],
1160 ('p', 'patch', None, 'show patch')],
1159 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1161 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1160 "list|ls": (ls,
1162 "list|ls": (ls,
1161 [('I', 'include', [], 'include path in search'),
1163 [('I', 'include', [], 'include path in search'),
1162 ('X', 'exclude', [], 'exclude path from search')],
1164 ('X', 'exclude', [], 'exclude path from search')],
1163 "hg ls [OPTION]... [PATTERN]...."),
1165 "hg ls [OPTION]... [PATTERN]...."),
1164 "manifest": (manifest, [], 'hg manifest [REV]'),
1166 "manifest": (manifest, [], 'hg manifest [REV]'),
1165 "parents": (parents, [], 'hg parents [REV]'),
1167 "parents": (parents, [], 'hg parents [REV]'),
1166 "^pull":
1168 "^pull":
1167 (pull,
1169 (pull,
1168 [('u', 'update', None, 'update working directory')],
1170 [('u', 'update', None, 'update working directory')],
1169 'hg pull [-u] [SOURCE]'),
1171 'hg pull [-u] [SOURCE]'),
1170 "^push": (push, [], 'hg push [DEST]'),
1172 "^push": (push, [], 'hg push [DEST]'),
1171 "rawcommit":
1173 "rawcommit":
1172 (rawcommit,
1174 (rawcommit,
1173 [('p', 'parent', [], 'parent'),
1175 [('p', 'parent', [], 'parent'),
1174 ('d', 'date', "", 'date code'),
1176 ('d', 'date', "", 'date code'),
1175 ('u', 'user', "", 'user'),
1177 ('u', 'user', "", 'user'),
1176 ('F', 'files', "", 'file list'),
1178 ('F', 'files', "", 'file list'),
1177 ('t', 'text', "", 'commit text'),
1179 ('t', 'text', "", 'commit text'),
1178 ('l', 'logfile', "", 'commit text file')],
1180 ('l', 'logfile', "", 'commit text file')],
1179 'hg rawcommit [OPTION]... [FILE]...'),
1181 'hg rawcommit [OPTION]... [FILE]...'),
1180 "recover": (recover, [], "hg recover"),
1182 "recover": (recover, [], "hg recover"),
1181 "^remove|rm": (remove, [], "hg remove FILE..."),
1183 "^remove|rm": (remove, [], "hg remove FILE..."),
1182 "^revert":
1184 "^revert":
1183 (revert,
1185 (revert,
1184 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1186 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1185 ("r", "rev", "", "revision")],
1187 ("r", "rev", "", "revision")],
1186 "hg revert [-n] [-r REV] NAME..."),
1188 "hg revert [-n] [-r REV] NAME..."),
1187 "root": (root, [], "hg root"),
1189 "root": (root, [], "hg root"),
1188 "^serve":
1190 "^serve":
1189 (serve,
1191 (serve,
1190 [('A', 'accesslog', '', 'access log file'),
1192 [('A', 'accesslog', '', 'access log file'),
1191 ('E', 'errorlog', '', 'error log file'),
1193 ('E', 'errorlog', '', 'error log file'),
1192 ('p', 'port', 8000, 'listen port'),
1194 ('p', 'port', 8000, 'listen port'),
1193 ('a', 'address', '', 'interface address'),
1195 ('a', 'address', '', 'interface address'),
1194 ('n', 'name', os.getcwd(), 'repository name'),
1196 ('n', 'name', os.getcwd(), 'repository name'),
1195 ('', 'stdio', None, 'for remote clients'),
1197 ('', 'stdio', None, 'for remote clients'),
1196 ('t', 'templates', "", 'template map')],
1198 ('t', 'templates', "", 'template map')],
1197 "hg serve [OPTION]..."),
1199 "hg serve [OPTION]..."),
1198 "^status": (status,
1200 "^status": (status,
1199 [('I', 'include', [], 'include path in search'),
1201 [('I', 'include', [], 'include path in search'),
1200 ('X', 'exclude', [], 'exclude path from search')],
1202 ('X', 'exclude', [], 'exclude path from search')],
1201 'hg status [OPTION]... [FILE]...'),
1203 'hg status [OPTION]... [FILE]...'),
1202 "tag":
1204 "tag":
1203 (tag,
1205 (tag,
1204 [('l', 'local', None, 'make the tag local'),
1206 [('l', 'local', None, 'make the tag local'),
1205 ('t', 'text', "", 'commit text'),
1207 ('t', 'text', "", 'commit text'),
1206 ('d', 'date', "", 'date code'),
1208 ('d', 'date', "", 'date code'),
1207 ('u', 'user', "", 'user')],
1209 ('u', 'user', "", 'user')],
1208 'hg tag [OPTION]... NAME [REV]'),
1210 'hg tag [OPTION]... NAME [REV]'),
1209 "tags": (tags, [], 'hg tags'),
1211 "tags": (tags, [], 'hg tags'),
1210 "tip": (tip, [], 'hg tip'),
1212 "tip": (tip, [], 'hg tip'),
1211 "undo": (undo, [], 'hg undo'),
1213 "undo": (undo, [], 'hg undo'),
1212 "^update|up|checkout|co":
1214 "^update|up|checkout|co":
1213 (update,
1215 (update,
1214 [('m', 'merge', None, 'allow merging of conflicts'),
1216 [('m', 'merge', None, 'allow merging of conflicts'),
1215 ('C', 'clean', None, 'overwrite locally modified files')],
1217 ('C', 'clean', None, 'overwrite locally modified files')],
1216 'hg update [-m] [-C] [REV]'),
1218 'hg update [-m] [-C] [REV]'),
1217 "verify": (verify, [], 'hg verify'),
1219 "verify": (verify, [], 'hg verify'),
1218 "version": (show_version, [], 'hg version'),
1220 "version": (show_version, [], 'hg version'),
1219 }
1221 }
1220
1222
1221 globalopts = [('v', 'verbose', None, 'verbose'),
1223 globalopts = [('v', 'verbose', None, 'verbose'),
1222 ('', 'debug', None, 'debug'),
1224 ('', 'debug', None, 'debug'),
1223 ('q', 'quiet', None, 'quiet'),
1225 ('q', 'quiet', None, 'quiet'),
1224 ('', 'profile', None, 'profile'),
1226 ('', 'profile', None, 'profile'),
1225 ('R', 'repository', "", 'repository root directory'),
1227 ('R', 'repository', "", 'repository root directory'),
1226 ('', 'traceback', None, 'print traceback on exception'),
1228 ('', 'traceback', None, 'print traceback on exception'),
1227 ('y', 'noninteractive', None, 'run non-interactively'),
1229 ('y', 'noninteractive', None, 'run non-interactively'),
1228 ('', 'version', None, 'output version information and exit'),
1230 ('', 'version', None, 'output version information and exit'),
1229 ]
1231 ]
1230
1232
1231 norepo = "clone init version help debugindex debugindexdot"
1233 norepo = "clone init version help debugindex debugindexdot"
1232
1234
1233 def find(cmd):
1235 def find(cmd):
1234 for e in table.keys():
1236 for e in table.keys():
1235 if re.match("(%s)$" % e, cmd):
1237 if re.match("(%s)$" % e, cmd):
1236 return table[e]
1238 return table[e]
1237
1239
1238 raise UnknownCommand(cmd)
1240 raise UnknownCommand(cmd)
1239
1241
1240 class SignalInterrupt(Exception):
1242 class SignalInterrupt(Exception):
1241 """Exception raised on SIGTERM and SIGHUP."""
1243 """Exception raised on SIGTERM and SIGHUP."""
1242
1244
1243 def catchterm(*args):
1245 def catchterm(*args):
1244 raise SignalInterrupt
1246 raise SignalInterrupt
1245
1247
1246 def run():
1248 def run():
1247 sys.exit(dispatch(sys.argv[1:]))
1249 sys.exit(dispatch(sys.argv[1:]))
1248
1250
1249 class ParseError(Exception):
1251 class ParseError(Exception):
1250 """Exception raised on errors in parsing the command line."""
1252 """Exception raised on errors in parsing the command line."""
1251
1253
1252 def parse(args):
1254 def parse(args):
1253 options = {}
1255 options = {}
1254 cmdoptions = {}
1256 cmdoptions = {}
1255
1257
1256 try:
1258 try:
1257 args = fancyopts.fancyopts(args, globalopts, options)
1259 args = fancyopts.fancyopts(args, globalopts, options)
1258 except fancyopts.getopt.GetoptError, inst:
1260 except fancyopts.getopt.GetoptError, inst:
1259 raise ParseError(None, inst)
1261 raise ParseError(None, inst)
1260
1262
1261 if options["version"]:
1263 if options["version"]:
1262 return ("version", show_version, [], options, cmdoptions)
1264 return ("version", show_version, [], options, cmdoptions)
1263 elif not args:
1265 elif not args:
1264 return ("help", help_, [], options, cmdoptions)
1266 return ("help", help_, [], options, cmdoptions)
1265 else:
1267 else:
1266 cmd, args = args[0], args[1:]
1268 cmd, args = args[0], args[1:]
1267
1269
1268 i = find(cmd)
1270 i = find(cmd)
1269
1271
1270 # combine global options into local
1272 # combine global options into local
1271 c = list(i[1])
1273 c = list(i[1])
1272 for o in globalopts:
1274 for o in globalopts:
1273 c.append((o[0], o[1], options[o[1]], o[3]))
1275 c.append((o[0], o[1], options[o[1]], o[3]))
1274
1276
1275 try:
1277 try:
1276 args = fancyopts.fancyopts(args, c, cmdoptions)
1278 args = fancyopts.fancyopts(args, c, cmdoptions)
1277 except fancyopts.getopt.GetoptError, inst:
1279 except fancyopts.getopt.GetoptError, inst:
1278 raise ParseError(cmd, inst)
1280 raise ParseError(cmd, inst)
1279
1281
1280 # separate global options back out
1282 # separate global options back out
1281 for o in globalopts:
1283 for o in globalopts:
1282 n = o[1]
1284 n = o[1]
1283 options[n] = cmdoptions[n]
1285 options[n] = cmdoptions[n]
1284 del cmdoptions[n]
1286 del cmdoptions[n]
1285
1287
1286 return (cmd, i[0], args, options, cmdoptions)
1288 return (cmd, i[0], args, options, cmdoptions)
1287
1289
1288 def dispatch(args):
1290 def dispatch(args):
1289 signal.signal(signal.SIGTERM, catchterm)
1291 signal.signal(signal.SIGTERM, catchterm)
1290 try:
1292 try:
1291 signal.signal(signal.SIGHUP, catchterm)
1293 signal.signal(signal.SIGHUP, catchterm)
1292 except AttributeError:
1294 except AttributeError:
1293 pass
1295 pass
1294
1296
1295 try:
1297 try:
1296 cmd, func, args, options, cmdoptions = parse(args)
1298 cmd, func, args, options, cmdoptions = parse(args)
1297 except ParseError, inst:
1299 except ParseError, inst:
1298 u = ui.ui()
1300 u = ui.ui()
1299 if inst.args[0]:
1301 if inst.args[0]:
1300 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1302 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1301 help_(u, inst.args[0])
1303 help_(u, inst.args[0])
1302 else:
1304 else:
1303 u.warn("hg: %s\n" % inst.args[1])
1305 u.warn("hg: %s\n" % inst.args[1])
1304 help_(u)
1306 help_(u)
1305 sys.exit(-1)
1307 sys.exit(-1)
1306 except UnknownCommand, inst:
1308 except UnknownCommand, inst:
1307 u = ui.ui()
1309 u = ui.ui()
1308 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1310 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1309 help_(u)
1311 help_(u)
1310 sys.exit(1)
1312 sys.exit(1)
1311
1313
1312 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1314 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1313 not options["noninteractive"])
1315 not options["noninteractive"])
1314
1316
1315 try:
1317 try:
1316 try:
1318 try:
1317 if cmd not in norepo.split():
1319 if cmd not in norepo.split():
1318 path = options["repository"] or ""
1320 path = options["repository"] or ""
1319 repo = hg.repository(ui=u, path=path)
1321 repo = hg.repository(ui=u, path=path)
1320 d = lambda: func(u, repo, *args, **cmdoptions)
1322 d = lambda: func(u, repo, *args, **cmdoptions)
1321 else:
1323 else:
1322 d = lambda: func(u, *args, **cmdoptions)
1324 d = lambda: func(u, *args, **cmdoptions)
1323
1325
1324 if options['profile']:
1326 if options['profile']:
1325 import hotshot, hotshot.stats
1327 import hotshot, hotshot.stats
1326 prof = hotshot.Profile("hg.prof")
1328 prof = hotshot.Profile("hg.prof")
1327 r = prof.runcall(d)
1329 r = prof.runcall(d)
1328 prof.close()
1330 prof.close()
1329 stats = hotshot.stats.load("hg.prof")
1331 stats = hotshot.stats.load("hg.prof")
1330 stats.strip_dirs()
1332 stats.strip_dirs()
1331 stats.sort_stats('time', 'calls')
1333 stats.sort_stats('time', 'calls')
1332 stats.print_stats(40)
1334 stats.print_stats(40)
1333 return r
1335 return r
1334 else:
1336 else:
1335 return d()
1337 return d()
1336 except:
1338 except:
1337 if options['traceback']:
1339 if options['traceback']:
1338 traceback.print_exc()
1340 traceback.print_exc()
1339 raise
1341 raise
1340 except util.CommandError, inst:
1342 except util.CommandError, inst:
1341 u.warn("abort: %s\n" % inst.args)
1343 u.warn("abort: %s\n" % inst.args)
1342 except hg.RepoError, inst:
1344 except hg.RepoError, inst:
1343 u.warn("abort: ", inst, "!\n")
1345 u.warn("abort: ", inst, "!\n")
1344 except SignalInterrupt:
1346 except SignalInterrupt:
1345 u.warn("killed!\n")
1347 u.warn("killed!\n")
1346 except KeyboardInterrupt:
1348 except KeyboardInterrupt:
1347 u.warn("interrupted!\n")
1349 u.warn("interrupted!\n")
1348 except IOError, inst:
1350 except IOError, inst:
1349 if hasattr(inst, "code"):
1351 if hasattr(inst, "code"):
1350 u.warn("abort: %s\n" % inst)
1352 u.warn("abort: %s\n" % inst)
1351 elif hasattr(inst, "reason"):
1353 elif hasattr(inst, "reason"):
1352 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1354 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1353 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1355 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1354 if u.debugflag: u.warn("broken pipe\n")
1356 if u.debugflag: u.warn("broken pipe\n")
1355 else:
1357 else:
1356 raise
1358 raise
1357 except OSError, inst:
1359 except OSError, inst:
1358 if hasattr(inst, "filename"):
1360 if hasattr(inst, "filename"):
1359 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1361 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1360 else:
1362 else:
1361 u.warn("abort: %s\n" % inst.strerror)
1363 u.warn("abort: %s\n" % inst.strerror)
1362 except Abort, inst:
1364 except Abort, inst:
1363 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1365 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1364 sys.exit(1)
1366 sys.exit(1)
1365 except TypeError, inst:
1367 except TypeError, inst:
1366 # was this an argument error?
1368 # was this an argument error?
1367 tb = traceback.extract_tb(sys.exc_info()[2])
1369 tb = traceback.extract_tb(sys.exc_info()[2])
1368 if len(tb) > 2: # no
1370 if len(tb) > 2: # no
1369 raise
1371 raise
1370 u.debug(inst, "\n")
1372 u.debug(inst, "\n")
1371 u.warn("%s: invalid arguments\n" % cmd)
1373 u.warn("%s: invalid arguments\n" % cmd)
1372 help_(u, cmd)
1374 help_(u, cmd)
1373
1375
1374 sys.exit(-1)
1376 sys.exit(-1)
@@ -1,67 +1,81 b''
1 basic hg commands (use "hg help -v" for more):
1 basic hg commands (use "hg help -v" for more):
2
2
3 add add the specified files on the next commit
3 add add the specified files on the next commit
4 annotate show changeset information per file line
4 annotate show changeset information per file line
5 clone make a copy of an existing repository
5 clone make a copy of an existing repository
6 commit commit the specified files or all outstanding changes
6 commit commit the specified files or all outstanding changes
7 diff diff working directory (or selected files)
7 diff diff working directory (or selected files)
8 export dump the header and diffs for one or more changesets
8 export dump the header and diffs for one or more changesets
9 init create a new repository in the current directory
9 init create a new repository in the current directory
10 log show the revision history of the repository or a single file
10 log show the revision history of the repository or a single file
11 pull pull changes from the specified source
11 pull pull changes from the specified source
12 push push changes to the specified destination
12 push push changes to the specified destination
13 remove remove the specified files on the next commit
13 remove remove the specified files on the next commit
14 revert revert modified files or dirs back to their unmodified states
14 revert revert modified files or dirs back to their unmodified states
15 serve export the repository via HTTP
15 serve export the repository via HTTP
16 status show changed files in the working directory
16 status show changed files in the working directory
17 update update or merge working directory
17 update update or merge working directory
18 basic hg commands (use "hg help -v" for more):
18 basic hg commands (use "hg help -v" for more):
19
19
20 add add the specified files on the next commit
20 add add the specified files on the next commit
21 annotate show changeset information per file line
21 annotate show changeset information per file line
22 clone make a copy of an existing repository
22 clone make a copy of an existing repository
23 commit commit the specified files or all outstanding changes
23 commit commit the specified files or all outstanding changes
24 diff diff working directory (or selected files)
24 diff diff working directory (or selected files)
25 export dump the header and diffs for one or more changesets
25 export dump the header and diffs for one or more changesets
26 init create a new repository in the current directory
26 init create a new repository in the current directory
27 log show the revision history of the repository or a single file
27 log show the revision history of the repository or a single file
28 pull pull changes from the specified source
28 pull pull changes from the specified source
29 push push changes to the specified destination
29 push push changes to the specified destination
30 remove remove the specified files on the next commit
30 remove remove the specified files on the next commit
31 revert revert modified files or dirs back to their unmodified states
31 revert revert modified files or dirs back to their unmodified states
32 serve export the repository via HTTP
32 serve export the repository via HTTP
33 status show changed files in the working directory
33 status show changed files in the working directory
34 update update or merge working directory
34 update update or merge working directory
35 hg add: option -h not recognized
35 hg add: option -h not recognized
36 hg add FILE...
36 hg add [OPTIONS] [FILES]
37
38 -I --include
39 include path in search
40 -X --exclude
41 exclude path from search
37
42
38 add the specified files on the next commit
43 add the specified files on the next commit
39 hg add: option --skjdfks not recognized
44 hg add: option --skjdfks not recognized
40 hg add FILE...
45 hg add [OPTIONS] [FILES]
46
47 -I --include
48 include path in search
49 -X --exclude
50 exclude path from search
41
51
42 add the specified files on the next commit
52 add the specified files on the next commit
43 hg diff [-r REV1 [-r REV2]] [FILE]...
53 hg diff [-r REV1 [-r REV2]] [FILE]...
44
54
55 -I --include
56 include path in search
57 -X --exclude
58 exclude path from search
45 -r --rev
59 -r --rev
46 revision
60 revision
47
61
48 diff working directory (or selected files)
62 diff working directory (or selected files)
49 hg: unknown command foo
63 hg: unknown command foo
50 hg: unknown command 'commands'
64 hg: unknown command 'commands'
51 basic hg commands (use "hg help -v" for more):
65 basic hg commands (use "hg help -v" for more):
52
66
53 add add the specified files on the next commit
67 add add the specified files on the next commit
54 annotate show changeset information per file line
68 annotate show changeset information per file line
55 clone make a copy of an existing repository
69 clone make a copy of an existing repository
56 commit commit the specified files or all outstanding changes
70 commit commit the specified files or all outstanding changes
57 diff diff working directory (or selected files)
71 diff diff working directory (or selected files)
58 export dump the header and diffs for one or more changesets
72 export dump the header and diffs for one or more changesets
59 init create a new repository in the current directory
73 init create a new repository in the current directory
60 log show the revision history of the repository or a single file
74 log show the revision history of the repository or a single file
61 pull pull changes from the specified source
75 pull pull changes from the specified source
62 push push changes to the specified destination
76 push push changes to the specified destination
63 remove remove the specified files on the next commit
77 remove remove the specified files on the next commit
64 revert revert modified files or dirs back to their unmodified states
78 revert revert modified files or dirs back to their unmodified states
65 serve export the repository via HTTP
79 serve export the repository via HTTP
66 status show changed files in the working directory
80 status show changed files in the working directory
67 update update or merge working directory
81 update update or merge working directory
General Comments 0
You need to be logged in to leave comments. Login now