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