##// END OF EJS Templates
Refactor annotate copy support.
Brendan Cully -
r3172:5c93dd0a default
parent child Browse files
Show More
@@ -1,3406 +1,3408 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 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 shlex")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb shlex")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 demandload(globals(), "archival cStringIO changegroup")
15 demandload(globals(), "archival cStringIO changegroup")
16 demandload(globals(), "cmdutil hgweb.server sshserver")
16 demandload(globals(), "cmdutil hgweb.server sshserver")
17
17
18 class UnknownCommand(Exception):
18 class UnknownCommand(Exception):
19 """Exception raised if command is not in the command table."""
19 """Exception raised if command is not in the command table."""
20 class AmbiguousCommand(Exception):
20 class AmbiguousCommand(Exception):
21 """Exception raised if command shortcut matches more than one command."""
21 """Exception raised if command shortcut matches more than one command."""
22
22
23 def bail_if_changed(repo):
23 def bail_if_changed(repo):
24 modified, added, removed, deleted = repo.status()[:4]
24 modified, added, removed, deleted = repo.status()[:4]
25 if modified or added or removed or deleted:
25 if modified or added or removed or deleted:
26 raise util.Abort(_("outstanding uncommitted changes"))
26 raise util.Abort(_("outstanding uncommitted changes"))
27
27
28 def relpath(repo, args):
28 def relpath(repo, args):
29 cwd = repo.getcwd()
29 cwd = repo.getcwd()
30 if cwd:
30 if cwd:
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
32 return args
32 return args
33
33
34 def logmessage(opts):
34 def logmessage(opts):
35 """ get the log message according to -m and -l option """
35 """ get the log message according to -m and -l option """
36 message = opts['message']
36 message = opts['message']
37 logfile = opts['logfile']
37 logfile = opts['logfile']
38
38
39 if message and logfile:
39 if message and logfile:
40 raise util.Abort(_('options --message and --logfile are mutually '
40 raise util.Abort(_('options --message and --logfile are mutually '
41 'exclusive'))
41 'exclusive'))
42 if not message and logfile:
42 if not message and logfile:
43 try:
43 try:
44 if logfile == '-':
44 if logfile == '-':
45 message = sys.stdin.read()
45 message = sys.stdin.read()
46 else:
46 else:
47 message = open(logfile).read()
47 message = open(logfile).read()
48 except IOError, inst:
48 except IOError, inst:
49 raise util.Abort(_("can't read commit message '%s': %s") %
49 raise util.Abort(_("can't read commit message '%s': %s") %
50 (logfile, inst.strerror))
50 (logfile, inst.strerror))
51 return message
51 return message
52
52
53 def walkchangerevs(ui, repo, pats, opts):
53 def walkchangerevs(ui, repo, pats, opts):
54 '''Iterate over files and the revs they changed in.
54 '''Iterate over files and the revs they changed in.
55
55
56 Callers most commonly need to iterate backwards over the history
56 Callers most commonly need to iterate backwards over the history
57 it is interested in. Doing so has awful (quadratic-looking)
57 it is interested in. Doing so has awful (quadratic-looking)
58 performance, so we use iterators in a "windowed" way.
58 performance, so we use iterators in a "windowed" way.
59
59
60 We walk a window of revisions in the desired order. Within the
60 We walk a window of revisions in the desired order. Within the
61 window, we first walk forwards to gather data, then in the desired
61 window, we first walk forwards to gather data, then in the desired
62 order (usually backwards) to display it.
62 order (usually backwards) to display it.
63
63
64 This function returns an (iterator, getchange, matchfn) tuple. The
64 This function returns an (iterator, getchange, matchfn) tuple. The
65 getchange function returns the changelog entry for a numeric
65 getchange function returns the changelog entry for a numeric
66 revision. The iterator yields 3-tuples. They will be of one of
66 revision. The iterator yields 3-tuples. They will be of one of
67 the following forms:
67 the following forms:
68
68
69 "window", incrementing, lastrev: stepping through a window,
69 "window", incrementing, lastrev: stepping through a window,
70 positive if walking forwards through revs, last rev in the
70 positive if walking forwards through revs, last rev in the
71 sequence iterated over - use to reset state for the current window
71 sequence iterated over - use to reset state for the current window
72
72
73 "add", rev, fns: out-of-order traversal of the given file names
73 "add", rev, fns: out-of-order traversal of the given file names
74 fns, which changed during revision rev - use to gather data for
74 fns, which changed during revision rev - use to gather data for
75 possible display
75 possible display
76
76
77 "iter", rev, None: in-order traversal of the revs earlier iterated
77 "iter", rev, None: in-order traversal of the revs earlier iterated
78 over with "add" - use to display data'''
78 over with "add" - use to display data'''
79
79
80 def increasing_windows(start, end, windowsize=8, sizelimit=512):
80 def increasing_windows(start, end, windowsize=8, sizelimit=512):
81 if start < end:
81 if start < end:
82 while start < end:
82 while start < end:
83 yield start, min(windowsize, end-start)
83 yield start, min(windowsize, end-start)
84 start += windowsize
84 start += windowsize
85 if windowsize < sizelimit:
85 if windowsize < sizelimit:
86 windowsize *= 2
86 windowsize *= 2
87 else:
87 else:
88 while start > end:
88 while start > end:
89 yield start, min(windowsize, start-end-1)
89 yield start, min(windowsize, start-end-1)
90 start -= windowsize
90 start -= windowsize
91 if windowsize < sizelimit:
91 if windowsize < sizelimit:
92 windowsize *= 2
92 windowsize *= 2
93
93
94
94
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
96 follow = opts.get('follow') or opts.get('follow_first')
96 follow = opts.get('follow') or opts.get('follow_first')
97
97
98 if repo.changelog.count() == 0:
98 if repo.changelog.count() == 0:
99 return [], False, matchfn
99 return [], False, matchfn
100
100
101 if follow:
101 if follow:
102 defrange = '%s:0' % repo.changectx().rev()
102 defrange = '%s:0' % repo.changectx().rev()
103 else:
103 else:
104 defrange = 'tip:0'
104 defrange = 'tip:0'
105 revs = map(int, cmdutil.revrange(ui, repo, opts['rev'] or [defrange]))
105 revs = map(int, cmdutil.revrange(ui, repo, opts['rev'] or [defrange]))
106 wanted = {}
106 wanted = {}
107 slowpath = anypats
107 slowpath = anypats
108 fncache = {}
108 fncache = {}
109
109
110 chcache = {}
110 chcache = {}
111 def getchange(rev):
111 def getchange(rev):
112 ch = chcache.get(rev)
112 ch = chcache.get(rev)
113 if ch is None:
113 if ch is None:
114 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
114 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
115 return ch
115 return ch
116
116
117 if not slowpath and not files:
117 if not slowpath and not files:
118 # No files, no patterns. Display all revs.
118 # No files, no patterns. Display all revs.
119 wanted = dict(zip(revs, revs))
119 wanted = dict(zip(revs, revs))
120 copies = []
120 copies = []
121 if not slowpath:
121 if not slowpath:
122 # Only files, no patterns. Check the history of each file.
122 # Only files, no patterns. Check the history of each file.
123 def filerevgen(filelog, node):
123 def filerevgen(filelog, node):
124 cl_count = repo.changelog.count()
124 cl_count = repo.changelog.count()
125 if node is None:
125 if node is None:
126 last = filelog.count() - 1
126 last = filelog.count() - 1
127 else:
127 else:
128 last = filelog.rev(node)
128 last = filelog.rev(node)
129 for i, window in increasing_windows(last, -1):
129 for i, window in increasing_windows(last, -1):
130 revs = []
130 revs = []
131 for j in xrange(i - window, i + 1):
131 for j in xrange(i - window, i + 1):
132 n = filelog.node(j)
132 n = filelog.node(j)
133 revs.append((filelog.linkrev(n),
133 revs.append((filelog.linkrev(n),
134 follow and filelog.renamed(n)))
134 follow and filelog.renamed(n)))
135 revs.reverse()
135 revs.reverse()
136 for rev in revs:
136 for rev in revs:
137 # only yield rev for which we have the changelog, it can
137 # only yield rev for which we have the changelog, it can
138 # happen while doing "hg log" during a pull or commit
138 # happen while doing "hg log" during a pull or commit
139 if rev[0] < cl_count:
139 if rev[0] < cl_count:
140 yield rev
140 yield rev
141 def iterfiles():
141 def iterfiles():
142 for filename in files:
142 for filename in files:
143 yield filename, None
143 yield filename, None
144 for filename_node in copies:
144 for filename_node in copies:
145 yield filename_node
145 yield filename_node
146 minrev, maxrev = min(revs), max(revs)
146 minrev, maxrev = min(revs), max(revs)
147 for file_, node in iterfiles():
147 for file_, node in iterfiles():
148 filelog = repo.file(file_)
148 filelog = repo.file(file_)
149 # A zero count may be a directory or deleted file, so
149 # A zero count may be a directory or deleted file, so
150 # try to find matching entries on the slow path.
150 # try to find matching entries on the slow path.
151 if filelog.count() == 0:
151 if filelog.count() == 0:
152 slowpath = True
152 slowpath = True
153 break
153 break
154 for rev, copied in filerevgen(filelog, node):
154 for rev, copied in filerevgen(filelog, node):
155 if rev <= maxrev:
155 if rev <= maxrev:
156 if rev < minrev:
156 if rev < minrev:
157 break
157 break
158 fncache.setdefault(rev, [])
158 fncache.setdefault(rev, [])
159 fncache[rev].append(file_)
159 fncache[rev].append(file_)
160 wanted[rev] = 1
160 wanted[rev] = 1
161 if follow and copied:
161 if follow and copied:
162 copies.append(copied)
162 copies.append(copied)
163 if slowpath:
163 if slowpath:
164 if follow:
164 if follow:
165 raise util.Abort(_('can only follow copies/renames for explicit '
165 raise util.Abort(_('can only follow copies/renames for explicit '
166 'file names'))
166 'file names'))
167
167
168 # The slow path checks files modified in every changeset.
168 # The slow path checks files modified in every changeset.
169 def changerevgen():
169 def changerevgen():
170 for i, window in increasing_windows(repo.changelog.count()-1, -1):
170 for i, window in increasing_windows(repo.changelog.count()-1, -1):
171 for j in xrange(i - window, i + 1):
171 for j in xrange(i - window, i + 1):
172 yield j, getchange(j)[3]
172 yield j, getchange(j)[3]
173
173
174 for rev, changefiles in changerevgen():
174 for rev, changefiles in changerevgen():
175 matches = filter(matchfn, changefiles)
175 matches = filter(matchfn, changefiles)
176 if matches:
176 if matches:
177 fncache[rev] = matches
177 fncache[rev] = matches
178 wanted[rev] = 1
178 wanted[rev] = 1
179
179
180 class followfilter:
180 class followfilter:
181 def __init__(self, onlyfirst=False):
181 def __init__(self, onlyfirst=False):
182 self.startrev = -1
182 self.startrev = -1
183 self.roots = []
183 self.roots = []
184 self.onlyfirst = onlyfirst
184 self.onlyfirst = onlyfirst
185
185
186 def match(self, rev):
186 def match(self, rev):
187 def realparents(rev):
187 def realparents(rev):
188 if self.onlyfirst:
188 if self.onlyfirst:
189 return repo.changelog.parentrevs(rev)[0:1]
189 return repo.changelog.parentrevs(rev)[0:1]
190 else:
190 else:
191 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
191 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
192
192
193 if self.startrev == -1:
193 if self.startrev == -1:
194 self.startrev = rev
194 self.startrev = rev
195 return True
195 return True
196
196
197 if rev > self.startrev:
197 if rev > self.startrev:
198 # forward: all descendants
198 # forward: all descendants
199 if not self.roots:
199 if not self.roots:
200 self.roots.append(self.startrev)
200 self.roots.append(self.startrev)
201 for parent in realparents(rev):
201 for parent in realparents(rev):
202 if parent in self.roots:
202 if parent in self.roots:
203 self.roots.append(rev)
203 self.roots.append(rev)
204 return True
204 return True
205 else:
205 else:
206 # backwards: all parents
206 # backwards: all parents
207 if not self.roots:
207 if not self.roots:
208 self.roots.extend(realparents(self.startrev))
208 self.roots.extend(realparents(self.startrev))
209 if rev in self.roots:
209 if rev in self.roots:
210 self.roots.remove(rev)
210 self.roots.remove(rev)
211 self.roots.extend(realparents(rev))
211 self.roots.extend(realparents(rev))
212 return True
212 return True
213
213
214 return False
214 return False
215
215
216 # it might be worthwhile to do this in the iterator if the rev range
216 # it might be worthwhile to do this in the iterator if the rev range
217 # is descending and the prune args are all within that range
217 # is descending and the prune args are all within that range
218 for rev in opts.get('prune', ()):
218 for rev in opts.get('prune', ()):
219 rev = repo.changelog.rev(repo.lookup(rev))
219 rev = repo.changelog.rev(repo.lookup(rev))
220 ff = followfilter()
220 ff = followfilter()
221 stop = min(revs[0], revs[-1])
221 stop = min(revs[0], revs[-1])
222 for x in range(rev, stop-1, -1):
222 for x in range(rev, stop-1, -1):
223 if ff.match(x) and wanted.has_key(x):
223 if ff.match(x) and wanted.has_key(x):
224 del wanted[x]
224 del wanted[x]
225
225
226 def iterate():
226 def iterate():
227 if follow and not files:
227 if follow and not files:
228 ff = followfilter(onlyfirst=opts.get('follow_first'))
228 ff = followfilter(onlyfirst=opts.get('follow_first'))
229 def want(rev):
229 def want(rev):
230 if ff.match(rev) and rev in wanted:
230 if ff.match(rev) and rev in wanted:
231 return True
231 return True
232 return False
232 return False
233 else:
233 else:
234 def want(rev):
234 def want(rev):
235 return rev in wanted
235 return rev in wanted
236
236
237 for i, window in increasing_windows(0, len(revs)):
237 for i, window in increasing_windows(0, len(revs)):
238 yield 'window', revs[0] < revs[-1], revs[-1]
238 yield 'window', revs[0] < revs[-1], revs[-1]
239 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
239 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
240 srevs = list(nrevs)
240 srevs = list(nrevs)
241 srevs.sort()
241 srevs.sort()
242 for rev in srevs:
242 for rev in srevs:
243 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
243 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
244 yield 'add', rev, fns
244 yield 'add', rev, fns
245 for rev in nrevs:
245 for rev in nrevs:
246 yield 'iter', rev, None
246 yield 'iter', rev, None
247 return iterate(), getchange, matchfn
247 return iterate(), getchange, matchfn
248
248
249 def write_bundle(cg, filename=None, compress=True):
249 def write_bundle(cg, filename=None, compress=True):
250 """Write a bundle file and return its filename.
250 """Write a bundle file and return its filename.
251
251
252 Existing files will not be overwritten.
252 Existing files will not be overwritten.
253 If no filename is specified, a temporary file is created.
253 If no filename is specified, a temporary file is created.
254 bz2 compression can be turned off.
254 bz2 compression can be turned off.
255 The bundle file will be deleted in case of errors.
255 The bundle file will be deleted in case of errors.
256 """
256 """
257 class nocompress(object):
257 class nocompress(object):
258 def compress(self, x):
258 def compress(self, x):
259 return x
259 return x
260 def flush(self):
260 def flush(self):
261 return ""
261 return ""
262
262
263 fh = None
263 fh = None
264 cleanup = None
264 cleanup = None
265 try:
265 try:
266 if filename:
266 if filename:
267 if os.path.exists(filename):
267 if os.path.exists(filename):
268 raise util.Abort(_("file '%s' already exists") % filename)
268 raise util.Abort(_("file '%s' already exists") % filename)
269 fh = open(filename, "wb")
269 fh = open(filename, "wb")
270 else:
270 else:
271 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
271 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
272 fh = os.fdopen(fd, "wb")
272 fh = os.fdopen(fd, "wb")
273 cleanup = filename
273 cleanup = filename
274
274
275 if compress:
275 if compress:
276 fh.write("HG10")
276 fh.write("HG10")
277 z = bz2.BZ2Compressor(9)
277 z = bz2.BZ2Compressor(9)
278 else:
278 else:
279 fh.write("HG10UN")
279 fh.write("HG10UN")
280 z = nocompress()
280 z = nocompress()
281 # parse the changegroup data, otherwise we will block
281 # parse the changegroup data, otherwise we will block
282 # in case of sshrepo because we don't know the end of the stream
282 # in case of sshrepo because we don't know the end of the stream
283
283
284 # an empty chunkiter is the end of the changegroup
284 # an empty chunkiter is the end of the changegroup
285 empty = False
285 empty = False
286 while not empty:
286 while not empty:
287 empty = True
287 empty = True
288 for chunk in changegroup.chunkiter(cg):
288 for chunk in changegroup.chunkiter(cg):
289 empty = False
289 empty = False
290 fh.write(z.compress(changegroup.genchunk(chunk)))
290 fh.write(z.compress(changegroup.genchunk(chunk)))
291 fh.write(z.compress(changegroup.closechunk()))
291 fh.write(z.compress(changegroup.closechunk()))
292 fh.write(z.flush())
292 fh.write(z.flush())
293 cleanup = None
293 cleanup = None
294 return filename
294 return filename
295 finally:
295 finally:
296 if fh is not None:
296 if fh is not None:
297 fh.close()
297 fh.close()
298 if cleanup is not None:
298 if cleanup is not None:
299 os.unlink(cleanup)
299 os.unlink(cleanup)
300
300
301 def trimuser(ui, name, rev, revcache):
301 def trimuser(ui, name, rev, revcache):
302 """trim the name of the user who committed a change"""
302 """trim the name of the user who committed a change"""
303 user = revcache.get(rev)
303 user = revcache.get(rev)
304 if user is None:
304 if user is None:
305 user = revcache[rev] = ui.shortuser(name)
305 user = revcache[rev] = ui.shortuser(name)
306 return user
306 return user
307
307
308 class changeset_printer(object):
308 class changeset_printer(object):
309 '''show changeset information when templating not requested.'''
309 '''show changeset information when templating not requested.'''
310
310
311 def __init__(self, ui, repo):
311 def __init__(self, ui, repo):
312 self.ui = ui
312 self.ui = ui
313 self.repo = repo
313 self.repo = repo
314
314
315 def show(self, rev=0, changenode=None, brinfo=None):
315 def show(self, rev=0, changenode=None, brinfo=None):
316 '''show a single changeset or file revision'''
316 '''show a single changeset or file revision'''
317 log = self.repo.changelog
317 log = self.repo.changelog
318 if changenode is None:
318 if changenode is None:
319 changenode = log.node(rev)
319 changenode = log.node(rev)
320 elif not rev:
320 elif not rev:
321 rev = log.rev(changenode)
321 rev = log.rev(changenode)
322
322
323 if self.ui.quiet:
323 if self.ui.quiet:
324 self.ui.write("%d:%s\n" % (rev, short(changenode)))
324 self.ui.write("%d:%s\n" % (rev, short(changenode)))
325 return
325 return
326
326
327 changes = log.read(changenode)
327 changes = log.read(changenode)
328 date = util.datestr(changes[2])
328 date = util.datestr(changes[2])
329
329
330 hexfunc = self.ui.debugflag and hex or short
330 hexfunc = self.ui.debugflag and hex or short
331
331
332 parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
332 parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
333 if self.ui.debugflag or p != nullid]
333 if self.ui.debugflag or p != nullid]
334 if (not self.ui.debugflag and len(parents) == 1 and
334 if (not self.ui.debugflag and len(parents) == 1 and
335 parents[0][0] == rev-1):
335 parents[0][0] == rev-1):
336 parents = []
336 parents = []
337
337
338 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
338 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
339
339
340 for tag in self.repo.nodetags(changenode):
340 for tag in self.repo.nodetags(changenode):
341 self.ui.status(_("tag: %s\n") % tag)
341 self.ui.status(_("tag: %s\n") % tag)
342 for parent in parents:
342 for parent in parents:
343 self.ui.write(_("parent: %d:%s\n") % parent)
343 self.ui.write(_("parent: %d:%s\n") % parent)
344
344
345 if brinfo and changenode in brinfo:
345 if brinfo and changenode in brinfo:
346 br = brinfo[changenode]
346 br = brinfo[changenode]
347 self.ui.write(_("branch: %s\n") % " ".join(br))
347 self.ui.write(_("branch: %s\n") % " ".join(br))
348
348
349 self.ui.debug(_("manifest: %d:%s\n") %
349 self.ui.debug(_("manifest: %d:%s\n") %
350 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
350 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
351 self.ui.status(_("user: %s\n") % changes[1])
351 self.ui.status(_("user: %s\n") % changes[1])
352 self.ui.status(_("date: %s\n") % date)
352 self.ui.status(_("date: %s\n") % date)
353
353
354 if self.ui.debugflag:
354 if self.ui.debugflag:
355 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
355 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
356 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
356 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
357 files):
357 files):
358 if value:
358 if value:
359 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
359 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
360 else:
360 else:
361 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
361 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
362
362
363 description = changes[4].strip()
363 description = changes[4].strip()
364 if description:
364 if description:
365 if self.ui.verbose:
365 if self.ui.verbose:
366 self.ui.status(_("description:\n"))
366 self.ui.status(_("description:\n"))
367 self.ui.status(description)
367 self.ui.status(description)
368 self.ui.status("\n\n")
368 self.ui.status("\n\n")
369 else:
369 else:
370 self.ui.status(_("summary: %s\n") %
370 self.ui.status(_("summary: %s\n") %
371 description.splitlines()[0])
371 description.splitlines()[0])
372 self.ui.status("\n")
372 self.ui.status("\n")
373
373
374 def show_changeset(ui, repo, opts):
374 def show_changeset(ui, repo, opts):
375 '''show one changeset. uses template or regular display. caller
375 '''show one changeset. uses template or regular display. caller
376 can pass in 'style' and 'template' options in opts.'''
376 can pass in 'style' and 'template' options in opts.'''
377
377
378 tmpl = opts.get('template')
378 tmpl = opts.get('template')
379 if tmpl:
379 if tmpl:
380 tmpl = templater.parsestring(tmpl, quoted=False)
380 tmpl = templater.parsestring(tmpl, quoted=False)
381 else:
381 else:
382 tmpl = ui.config('ui', 'logtemplate')
382 tmpl = ui.config('ui', 'logtemplate')
383 if tmpl: tmpl = templater.parsestring(tmpl)
383 if tmpl: tmpl = templater.parsestring(tmpl)
384 mapfile = opts.get('style') or ui.config('ui', 'style')
384 mapfile = opts.get('style') or ui.config('ui', 'style')
385 if tmpl or mapfile:
385 if tmpl or mapfile:
386 if mapfile:
386 if mapfile:
387 if not os.path.isfile(mapfile):
387 if not os.path.isfile(mapfile):
388 mapname = templater.templatepath('map-cmdline.' + mapfile)
388 mapname = templater.templatepath('map-cmdline.' + mapfile)
389 if not mapname: mapname = templater.templatepath(mapfile)
389 if not mapname: mapname = templater.templatepath(mapfile)
390 if mapname: mapfile = mapname
390 if mapname: mapfile = mapname
391 try:
391 try:
392 t = templater.changeset_templater(ui, repo, mapfile)
392 t = templater.changeset_templater(ui, repo, mapfile)
393 except SyntaxError, inst:
393 except SyntaxError, inst:
394 raise util.Abort(inst.args[0])
394 raise util.Abort(inst.args[0])
395 if tmpl: t.use_template(tmpl)
395 if tmpl: t.use_template(tmpl)
396 return t
396 return t
397 return changeset_printer(ui, repo)
397 return changeset_printer(ui, repo)
398
398
399 def setremoteconfig(ui, opts):
399 def setremoteconfig(ui, opts):
400 "copy remote options to ui tree"
400 "copy remote options to ui tree"
401 if opts.get('ssh'):
401 if opts.get('ssh'):
402 ui.setconfig("ui", "ssh", opts['ssh'])
402 ui.setconfig("ui", "ssh", opts['ssh'])
403 if opts.get('remotecmd'):
403 if opts.get('remotecmd'):
404 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
404 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
405
405
406 def show_version(ui):
406 def show_version(ui):
407 """output version and copyright information"""
407 """output version and copyright information"""
408 ui.write(_("Mercurial Distributed SCM (version %s)\n")
408 ui.write(_("Mercurial Distributed SCM (version %s)\n")
409 % version.get_version())
409 % version.get_version())
410 ui.status(_(
410 ui.status(_(
411 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
411 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
412 "This is free software; see the source for copying conditions. "
412 "This is free software; see the source for copying conditions. "
413 "There is NO\nwarranty; "
413 "There is NO\nwarranty; "
414 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
414 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
415 ))
415 ))
416
416
417 def help_(ui, name=None, with_version=False):
417 def help_(ui, name=None, with_version=False):
418 """show help for a command, extension, or list of commands
418 """show help for a command, extension, or list of commands
419
419
420 With no arguments, print a list of commands and short help.
420 With no arguments, print a list of commands and short help.
421
421
422 Given a command name, print help for that command.
422 Given a command name, print help for that command.
423
423
424 Given an extension name, print help for that extension, and the
424 Given an extension name, print help for that extension, and the
425 commands it provides."""
425 commands it provides."""
426 option_lists = []
426 option_lists = []
427
427
428 def helpcmd(name):
428 def helpcmd(name):
429 if with_version:
429 if with_version:
430 show_version(ui)
430 show_version(ui)
431 ui.write('\n')
431 ui.write('\n')
432 aliases, i = findcmd(ui, name)
432 aliases, i = findcmd(ui, name)
433 # synopsis
433 # synopsis
434 ui.write("%s\n\n" % i[2])
434 ui.write("%s\n\n" % i[2])
435
435
436 # description
436 # description
437 doc = i[0].__doc__
437 doc = i[0].__doc__
438 if not doc:
438 if not doc:
439 doc = _("(No help text available)")
439 doc = _("(No help text available)")
440 if ui.quiet:
440 if ui.quiet:
441 doc = doc.splitlines(0)[0]
441 doc = doc.splitlines(0)[0]
442 ui.write("%s\n" % doc.rstrip())
442 ui.write("%s\n" % doc.rstrip())
443
443
444 if not ui.quiet:
444 if not ui.quiet:
445 # aliases
445 # aliases
446 if len(aliases) > 1:
446 if len(aliases) > 1:
447 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
447 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
448
448
449 # options
449 # options
450 if i[1]:
450 if i[1]:
451 option_lists.append(("options", i[1]))
451 option_lists.append(("options", i[1]))
452
452
453 def helplist(select=None):
453 def helplist(select=None):
454 h = {}
454 h = {}
455 cmds = {}
455 cmds = {}
456 for c, e in table.items():
456 for c, e in table.items():
457 f = c.split("|", 1)[0]
457 f = c.split("|", 1)[0]
458 if select and not select(f):
458 if select and not select(f):
459 continue
459 continue
460 if name == "shortlist" and not f.startswith("^"):
460 if name == "shortlist" and not f.startswith("^"):
461 continue
461 continue
462 f = f.lstrip("^")
462 f = f.lstrip("^")
463 if not ui.debugflag and f.startswith("debug"):
463 if not ui.debugflag and f.startswith("debug"):
464 continue
464 continue
465 doc = e[0].__doc__
465 doc = e[0].__doc__
466 if not doc:
466 if not doc:
467 doc = _("(No help text available)")
467 doc = _("(No help text available)")
468 h[f] = doc.splitlines(0)[0].rstrip()
468 h[f] = doc.splitlines(0)[0].rstrip()
469 cmds[f] = c.lstrip("^")
469 cmds[f] = c.lstrip("^")
470
470
471 fns = h.keys()
471 fns = h.keys()
472 fns.sort()
472 fns.sort()
473 m = max(map(len, fns))
473 m = max(map(len, fns))
474 for f in fns:
474 for f in fns:
475 if ui.verbose:
475 if ui.verbose:
476 commands = cmds[f].replace("|",", ")
476 commands = cmds[f].replace("|",", ")
477 ui.write(" %s:\n %s\n"%(commands, h[f]))
477 ui.write(" %s:\n %s\n"%(commands, h[f]))
478 else:
478 else:
479 ui.write(' %-*s %s\n' % (m, f, h[f]))
479 ui.write(' %-*s %s\n' % (m, f, h[f]))
480
480
481 def helpext(name):
481 def helpext(name):
482 try:
482 try:
483 mod = findext(name)
483 mod = findext(name)
484 except KeyError:
484 except KeyError:
485 raise UnknownCommand(name)
485 raise UnknownCommand(name)
486
486
487 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
487 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
488 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
488 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
489 for d in doc[1:]:
489 for d in doc[1:]:
490 ui.write(d, '\n')
490 ui.write(d, '\n')
491
491
492 ui.status('\n')
492 ui.status('\n')
493 if ui.verbose:
493 if ui.verbose:
494 ui.status(_('list of commands:\n\n'))
494 ui.status(_('list of commands:\n\n'))
495 else:
495 else:
496 ui.status(_('list of commands (use "hg help -v %s" '
496 ui.status(_('list of commands (use "hg help -v %s" '
497 'to show aliases and global options):\n\n') % name)
497 'to show aliases and global options):\n\n') % name)
498
498
499 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
499 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
500 helplist(modcmds.has_key)
500 helplist(modcmds.has_key)
501
501
502 if name and name != 'shortlist':
502 if name and name != 'shortlist':
503 try:
503 try:
504 helpcmd(name)
504 helpcmd(name)
505 except UnknownCommand:
505 except UnknownCommand:
506 helpext(name)
506 helpext(name)
507
507
508 else:
508 else:
509 # program name
509 # program name
510 if ui.verbose or with_version:
510 if ui.verbose or with_version:
511 show_version(ui)
511 show_version(ui)
512 else:
512 else:
513 ui.status(_("Mercurial Distributed SCM\n"))
513 ui.status(_("Mercurial Distributed SCM\n"))
514 ui.status('\n')
514 ui.status('\n')
515
515
516 # list of commands
516 # list of commands
517 if name == "shortlist":
517 if name == "shortlist":
518 ui.status(_('basic commands (use "hg help" '
518 ui.status(_('basic commands (use "hg help" '
519 'for the full list or option "-v" for details):\n\n'))
519 'for the full list or option "-v" for details):\n\n'))
520 elif ui.verbose:
520 elif ui.verbose:
521 ui.status(_('list of commands:\n\n'))
521 ui.status(_('list of commands:\n\n'))
522 else:
522 else:
523 ui.status(_('list of commands (use "hg help -v" '
523 ui.status(_('list of commands (use "hg help -v" '
524 'to show aliases and global options):\n\n'))
524 'to show aliases and global options):\n\n'))
525
525
526 helplist()
526 helplist()
527
527
528 # global options
528 # global options
529 if ui.verbose:
529 if ui.verbose:
530 option_lists.append(("global options", globalopts))
530 option_lists.append(("global options", globalopts))
531
531
532 # list all option lists
532 # list all option lists
533 opt_output = []
533 opt_output = []
534 for title, options in option_lists:
534 for title, options in option_lists:
535 opt_output.append(("\n%s:\n" % title, None))
535 opt_output.append(("\n%s:\n" % title, None))
536 for shortopt, longopt, default, desc in options:
536 for shortopt, longopt, default, desc in options:
537 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
537 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
538 longopt and " --%s" % longopt),
538 longopt and " --%s" % longopt),
539 "%s%s" % (desc,
539 "%s%s" % (desc,
540 default
540 default
541 and _(" (default: %s)") % default
541 and _(" (default: %s)") % default
542 or "")))
542 or "")))
543
543
544 if opt_output:
544 if opt_output:
545 opts_len = max([len(line[0]) for line in opt_output if line[1]])
545 opts_len = max([len(line[0]) for line in opt_output if line[1]])
546 for first, second in opt_output:
546 for first, second in opt_output:
547 if second:
547 if second:
548 ui.write(" %-*s %s\n" % (opts_len, first, second))
548 ui.write(" %-*s %s\n" % (opts_len, first, second))
549 else:
549 else:
550 ui.write("%s\n" % first)
550 ui.write("%s\n" % first)
551
551
552 # Commands start here, listed alphabetically
552 # Commands start here, listed alphabetically
553
553
554 def add(ui, repo, *pats, **opts):
554 def add(ui, repo, *pats, **opts):
555 """add the specified files on the next commit
555 """add the specified files on the next commit
556
556
557 Schedule files to be version controlled and added to the repository.
557 Schedule files to be version controlled and added to the repository.
558
558
559 The files will be added to the repository at the next commit.
559 The files will be added to the repository at the next commit.
560
560
561 If no names are given, add all files in the repository.
561 If no names are given, add all files in the repository.
562 """
562 """
563
563
564 names = []
564 names = []
565 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
565 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
566 if exact:
566 if exact:
567 if ui.verbose:
567 if ui.verbose:
568 ui.status(_('adding %s\n') % rel)
568 ui.status(_('adding %s\n') % rel)
569 names.append(abs)
569 names.append(abs)
570 elif repo.dirstate.state(abs) == '?':
570 elif repo.dirstate.state(abs) == '?':
571 ui.status(_('adding %s\n') % rel)
571 ui.status(_('adding %s\n') % rel)
572 names.append(abs)
572 names.append(abs)
573 if not opts.get('dry_run'):
573 if not opts.get('dry_run'):
574 repo.add(names)
574 repo.add(names)
575
575
576 def addremove(ui, repo, *pats, **opts):
576 def addremove(ui, repo, *pats, **opts):
577 """add all new files, delete all missing files (DEPRECATED)
577 """add all new files, delete all missing files (DEPRECATED)
578
578
579 Add all new files and remove all missing files from the repository.
579 Add all new files and remove all missing files from the repository.
580
580
581 New files are ignored if they match any of the patterns in .hgignore. As
581 New files are ignored if they match any of the patterns in .hgignore. As
582 with add, these changes take effect at the next commit.
582 with add, these changes take effect at the next commit.
583
583
584 Use the -s option to detect renamed files. With a parameter > 0,
584 Use the -s option to detect renamed files. With a parameter > 0,
585 this compares every removed file with every added file and records
585 this compares every removed file with every added file and records
586 those similar enough as renames. This option takes a percentage
586 those similar enough as renames. This option takes a percentage
587 between 0 (disabled) and 100 (files must be identical) as its
587 between 0 (disabled) and 100 (files must be identical) as its
588 parameter. Detecting renamed files this way can be expensive.
588 parameter. Detecting renamed files this way can be expensive.
589 """
589 """
590 sim = float(opts.get('similarity') or 0)
590 sim = float(opts.get('similarity') or 0)
591 if sim < 0 or sim > 100:
591 if sim < 0 or sim > 100:
592 raise util.Abort(_('similarity must be between 0 and 100'))
592 raise util.Abort(_('similarity must be between 0 and 100'))
593 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
593 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
594
594
595 def annotate(ui, repo, *pats, **opts):
595 def annotate(ui, repo, *pats, **opts):
596 """show changeset information per file line
596 """show changeset information per file line
597
597
598 List changes in files, showing the revision id responsible for each line
598 List changes in files, showing the revision id responsible for each line
599
599
600 This command is useful to discover who did a change or when a change took
600 This command is useful to discover who did a change or when a change took
601 place.
601 place.
602
602
603 Without the -a option, annotate will avoid processing files it
603 Without the -a option, annotate will avoid processing files it
604 detects as binary. With -a, annotate will generate an annotation
604 detects as binary. With -a, annotate will generate an annotation
605 anyway, probably with undesirable results.
605 anyway, probably with undesirable results.
606 """
606 """
607 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
607 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
608
608
609 if not pats:
609 if not pats:
610 raise util.Abort(_('at least one file name or pattern required'))
610 raise util.Abort(_('at least one file name or pattern required'))
611
611
612 opmap = [['user', lambda x: ui.shortuser(x.user())],
612 opmap = [['user', lambda x: ui.shortuser(x.user())],
613 ['number', lambda x: str(x.rev())],
613 ['number', lambda x: str(x.rev())],
614 ['changeset', lambda x: short(x.node())],
614 ['changeset', lambda x: short(x.node())],
615 ['date', getdate]]
615 ['date', getdate], ['follow', lambda x: x.path()]]
616 if not opts['user'] and not opts['changeset'] and not opts['date']:
616 if (not opts['user'] and not opts['changeset'] and not opts['date']
617 and not opts['follow']):
617 opts['number'] = 1
618 opts['number'] = 1
618
619
619 ctx = repo.changectx(opts['rev'])
620 ctx = repo.changectx(opts['rev'])
620
621
621 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
622 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
622 node=ctx.node()):
623 node=ctx.node()):
623 fctx = ctx.filectx(abs)
624 fctx = ctx.filectx(abs)
624 if not opts['text'] and util.binary(fctx.data()):
625 if not opts['text'] and util.binary(fctx.data()):
625 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
626 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
626 continue
627 continue
627
628
628 lines = fctx.annotate()
629 lines = fctx.annotate(follow=opts.get('follow'))
629 pieces = []
630 pieces = []
630
631
631 for o, f in opmap:
632 for o, f in opmap:
632 if opts[o]:
633 if opts[o]:
633 l = [f(n) for n, dummy in lines]
634 l = [f(n) for n, dummy in lines]
634 if l:
635 if l:
635 m = max(map(len, l))
636 m = max(map(len, l))
636 pieces.append(["%*s" % (m, x) for x in l])
637 pieces.append(["%*s" % (m, x) for x in l])
637
638
638 if pieces:
639 if pieces:
639 for p, l in zip(zip(*pieces), lines):
640 for p, l in zip(zip(*pieces), lines):
640 ui.write("%s: %s" % (" ".join(p), l[1]))
641 ui.write("%s: %s" % (" ".join(p), l[1]))
641
642
642 def archive(ui, repo, dest, **opts):
643 def archive(ui, repo, dest, **opts):
643 '''create unversioned archive of a repository revision
644 '''create unversioned archive of a repository revision
644
645
645 By default, the revision used is the parent of the working
646 By default, the revision used is the parent of the working
646 directory; use "-r" to specify a different revision.
647 directory; use "-r" to specify a different revision.
647
648
648 To specify the type of archive to create, use "-t". Valid
649 To specify the type of archive to create, use "-t". Valid
649 types are:
650 types are:
650
651
651 "files" (default): a directory full of files
652 "files" (default): a directory full of files
652 "tar": tar archive, uncompressed
653 "tar": tar archive, uncompressed
653 "tbz2": tar archive, compressed using bzip2
654 "tbz2": tar archive, compressed using bzip2
654 "tgz": tar archive, compressed using gzip
655 "tgz": tar archive, compressed using gzip
655 "uzip": zip archive, uncompressed
656 "uzip": zip archive, uncompressed
656 "zip": zip archive, compressed using deflate
657 "zip": zip archive, compressed using deflate
657
658
658 The exact name of the destination archive or directory is given
659 The exact name of the destination archive or directory is given
659 using a format string; see "hg help export" for details.
660 using a format string; see "hg help export" for details.
660
661
661 Each member added to an archive file has a directory prefix
662 Each member added to an archive file has a directory prefix
662 prepended. Use "-p" to specify a format string for the prefix.
663 prepended. Use "-p" to specify a format string for the prefix.
663 The default is the basename of the archive, with suffixes removed.
664 The default is the basename of the archive, with suffixes removed.
664 '''
665 '''
665
666
666 node = repo.changectx(opts['rev']).node()
667 node = repo.changectx(opts['rev']).node()
667 dest = cmdutil.make_filename(repo, dest, node)
668 dest = cmdutil.make_filename(repo, dest, node)
668 if os.path.realpath(dest) == repo.root:
669 if os.path.realpath(dest) == repo.root:
669 raise util.Abort(_('repository root cannot be destination'))
670 raise util.Abort(_('repository root cannot be destination'))
670 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
671 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
671 kind = opts.get('type') or 'files'
672 kind = opts.get('type') or 'files'
672 prefix = opts['prefix']
673 prefix = opts['prefix']
673 if dest == '-':
674 if dest == '-':
674 if kind == 'files':
675 if kind == 'files':
675 raise util.Abort(_('cannot archive plain files to stdout'))
676 raise util.Abort(_('cannot archive plain files to stdout'))
676 dest = sys.stdout
677 dest = sys.stdout
677 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
678 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
678 prefix = cmdutil.make_filename(repo, prefix, node)
679 prefix = cmdutil.make_filename(repo, prefix, node)
679 archival.archive(repo, dest, node, kind, not opts['no_decode'],
680 archival.archive(repo, dest, node, kind, not opts['no_decode'],
680 matchfn, prefix)
681 matchfn, prefix)
681
682
682 def backout(ui, repo, rev, **opts):
683 def backout(ui, repo, rev, **opts):
683 '''reverse effect of earlier changeset
684 '''reverse effect of earlier changeset
684
685
685 Commit the backed out changes as a new changeset. The new
686 Commit the backed out changes as a new changeset. The new
686 changeset is a child of the backed out changeset.
687 changeset is a child of the backed out changeset.
687
688
688 If you back out a changeset other than the tip, a new head is
689 If you back out a changeset other than the tip, a new head is
689 created. This head is the parent of the working directory. If
690 created. This head is the parent of the working directory. If
690 you back out an old changeset, your working directory will appear
691 you back out an old changeset, your working directory will appear
691 old after the backout. You should merge the backout changeset
692 old after the backout. You should merge the backout changeset
692 with another head.
693 with another head.
693
694
694 The --merge option remembers the parent of the working directory
695 The --merge option remembers the parent of the working directory
695 before starting the backout, then merges the new head with that
696 before starting the backout, then merges the new head with that
696 changeset afterwards. This saves you from doing the merge by
697 changeset afterwards. This saves you from doing the merge by
697 hand. The result of this merge is not committed, as for a normal
698 hand. The result of this merge is not committed, as for a normal
698 merge.'''
699 merge.'''
699
700
700 bail_if_changed(repo)
701 bail_if_changed(repo)
701 op1, op2 = repo.dirstate.parents()
702 op1, op2 = repo.dirstate.parents()
702 if op2 != nullid:
703 if op2 != nullid:
703 raise util.Abort(_('outstanding uncommitted merge'))
704 raise util.Abort(_('outstanding uncommitted merge'))
704 node = repo.lookup(rev)
705 node = repo.lookup(rev)
705 p1, p2 = repo.changelog.parents(node)
706 p1, p2 = repo.changelog.parents(node)
706 if p1 == nullid:
707 if p1 == nullid:
707 raise util.Abort(_('cannot back out a change with no parents'))
708 raise util.Abort(_('cannot back out a change with no parents'))
708 if p2 != nullid:
709 if p2 != nullid:
709 if not opts['parent']:
710 if not opts['parent']:
710 raise util.Abort(_('cannot back out a merge changeset without '
711 raise util.Abort(_('cannot back out a merge changeset without '
711 '--parent'))
712 '--parent'))
712 p = repo.lookup(opts['parent'])
713 p = repo.lookup(opts['parent'])
713 if p not in (p1, p2):
714 if p not in (p1, p2):
714 raise util.Abort(_('%s is not a parent of %s' %
715 raise util.Abort(_('%s is not a parent of %s' %
715 (short(p), short(node))))
716 (short(p), short(node))))
716 parent = p
717 parent = p
717 else:
718 else:
718 if opts['parent']:
719 if opts['parent']:
719 raise util.Abort(_('cannot use --parent on non-merge changeset'))
720 raise util.Abort(_('cannot use --parent on non-merge changeset'))
720 parent = p1
721 parent = p1
721 hg.clean(repo, node, show_stats=False)
722 hg.clean(repo, node, show_stats=False)
722 revert_opts = opts.copy()
723 revert_opts = opts.copy()
723 revert_opts['all'] = True
724 revert_opts['all'] = True
724 revert_opts['rev'] = hex(parent)
725 revert_opts['rev'] = hex(parent)
725 revert(ui, repo, **revert_opts)
726 revert(ui, repo, **revert_opts)
726 commit_opts = opts.copy()
727 commit_opts = opts.copy()
727 commit_opts['addremove'] = False
728 commit_opts['addremove'] = False
728 if not commit_opts['message'] and not commit_opts['logfile']:
729 if not commit_opts['message'] and not commit_opts['logfile']:
729 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
730 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
730 commit_opts['force_editor'] = True
731 commit_opts['force_editor'] = True
731 commit(ui, repo, **commit_opts)
732 commit(ui, repo, **commit_opts)
732 def nice(node):
733 def nice(node):
733 return '%d:%s' % (repo.changelog.rev(node), short(node))
734 return '%d:%s' % (repo.changelog.rev(node), short(node))
734 ui.status(_('changeset %s backs out changeset %s\n') %
735 ui.status(_('changeset %s backs out changeset %s\n') %
735 (nice(repo.changelog.tip()), nice(node)))
736 (nice(repo.changelog.tip()), nice(node)))
736 if op1 != node:
737 if op1 != node:
737 if opts['merge']:
738 if opts['merge']:
738 ui.status(_('merging with changeset %s\n') % nice(op1))
739 ui.status(_('merging with changeset %s\n') % nice(op1))
739 n = _lookup(repo, hex(op1))
740 n = _lookup(repo, hex(op1))
740 hg.merge(repo, n)
741 hg.merge(repo, n)
741 else:
742 else:
742 ui.status(_('the backout changeset is a new head - '
743 ui.status(_('the backout changeset is a new head - '
743 'do not forget to merge\n'))
744 'do not forget to merge\n'))
744 ui.status(_('(use "backout --merge" '
745 ui.status(_('(use "backout --merge" '
745 'if you want to auto-merge)\n'))
746 'if you want to auto-merge)\n'))
746
747
747 def bundle(ui, repo, fname, dest=None, **opts):
748 def bundle(ui, repo, fname, dest=None, **opts):
748 """create a changegroup file
749 """create a changegroup file
749
750
750 Generate a compressed changegroup file collecting all changesets
751 Generate a compressed changegroup file collecting all changesets
751 not found in the other repository.
752 not found in the other repository.
752
753
753 This file can then be transferred using conventional means and
754 This file can then be transferred using conventional means and
754 applied to another repository with the unbundle command. This is
755 applied to another repository with the unbundle command. This is
755 useful when native push and pull are not available or when
756 useful when native push and pull are not available or when
756 exporting an entire repository is undesirable. The standard file
757 exporting an entire repository is undesirable. The standard file
757 extension is ".hg".
758 extension is ".hg".
758
759
759 Unlike import/export, this exactly preserves all changeset
760 Unlike import/export, this exactly preserves all changeset
760 contents including permissions, rename data, and revision history.
761 contents including permissions, rename data, and revision history.
761 """
762 """
762 dest = ui.expandpath(dest or 'default-push', dest or 'default')
763 dest = ui.expandpath(dest or 'default-push', dest or 'default')
763 other = hg.repository(ui, dest)
764 other = hg.repository(ui, dest)
764 o = repo.findoutgoing(other, force=opts['force'])
765 o = repo.findoutgoing(other, force=opts['force'])
765 cg = repo.changegroup(o, 'bundle')
766 cg = repo.changegroup(o, 'bundle')
766 write_bundle(cg, fname)
767 write_bundle(cg, fname)
767
768
768 def cat(ui, repo, file1, *pats, **opts):
769 def cat(ui, repo, file1, *pats, **opts):
769 """output the latest or given revisions of files
770 """output the latest or given revisions of files
770
771
771 Print the specified files as they were at the given revision.
772 Print the specified files as they were at the given revision.
772 If no revision is given then working dir parent is used, or tip
773 If no revision is given then working dir parent is used, or tip
773 if no revision is checked out.
774 if no revision is checked out.
774
775
775 Output may be to a file, in which case the name of the file is
776 Output may be to a file, in which case the name of the file is
776 given using a format string. The formatting rules are the same as
777 given using a format string. The formatting rules are the same as
777 for the export command, with the following additions:
778 for the export command, with the following additions:
778
779
779 %s basename of file being printed
780 %s basename of file being printed
780 %d dirname of file being printed, or '.' if in repo root
781 %d dirname of file being printed, or '.' if in repo root
781 %p root-relative path name of file being printed
782 %p root-relative path name of file being printed
782 """
783 """
783 ctx = repo.changectx(opts['rev'])
784 ctx = repo.changectx(opts['rev'])
784 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
785 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
785 ctx.node()):
786 ctx.node()):
786 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
787 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
787 fp.write(ctx.filectx(abs).data())
788 fp.write(ctx.filectx(abs).data())
788
789
789 def clone(ui, source, dest=None, **opts):
790 def clone(ui, source, dest=None, **opts):
790 """make a copy of an existing repository
791 """make a copy of an existing repository
791
792
792 Create a copy of an existing repository in a new directory.
793 Create a copy of an existing repository in a new directory.
793
794
794 If no destination directory name is specified, it defaults to the
795 If no destination directory name is specified, it defaults to the
795 basename of the source.
796 basename of the source.
796
797
797 The location of the source is added to the new repository's
798 The location of the source is added to the new repository's
798 .hg/hgrc file, as the default to be used for future pulls.
799 .hg/hgrc file, as the default to be used for future pulls.
799
800
800 For efficiency, hardlinks are used for cloning whenever the source
801 For efficiency, hardlinks are used for cloning whenever the source
801 and destination are on the same filesystem (note this applies only
802 and destination are on the same filesystem (note this applies only
802 to the repository data, not to the checked out files). Some
803 to the repository data, not to the checked out files). Some
803 filesystems, such as AFS, implement hardlinking incorrectly, but
804 filesystems, such as AFS, implement hardlinking incorrectly, but
804 do not report errors. In these cases, use the --pull option to
805 do not report errors. In these cases, use the --pull option to
805 avoid hardlinking.
806 avoid hardlinking.
806
807
807 You can safely clone repositories and checked out files using full
808 You can safely clone repositories and checked out files using full
808 hardlinks with
809 hardlinks with
809
810
810 $ cp -al REPO REPOCLONE
811 $ cp -al REPO REPOCLONE
811
812
812 which is the fastest way to clone. However, the operation is not
813 which is the fastest way to clone. However, the operation is not
813 atomic (making sure REPO is not modified during the operation is
814 atomic (making sure REPO is not modified during the operation is
814 up to you) and you have to make sure your editor breaks hardlinks
815 up to you) and you have to make sure your editor breaks hardlinks
815 (Emacs and most Linux Kernel tools do so).
816 (Emacs and most Linux Kernel tools do so).
816
817
817 If you use the -r option to clone up to a specific revision, no
818 If you use the -r option to clone up to a specific revision, no
818 subsequent revisions will be present in the cloned repository.
819 subsequent revisions will be present in the cloned repository.
819 This option implies --pull, even on local repositories.
820 This option implies --pull, even on local repositories.
820
821
821 See pull for valid source format details.
822 See pull for valid source format details.
822
823
823 It is possible to specify an ssh:// URL as the destination, but no
824 It is possible to specify an ssh:// URL as the destination, but no
824 .hg/hgrc will be created on the remote side. Look at the help text
825 .hg/hgrc will be created on the remote side. Look at the help text
825 for the pull command for important details about ssh:// URLs.
826 for the pull command for important details about ssh:// URLs.
826 """
827 """
827 setremoteconfig(ui, opts)
828 setremoteconfig(ui, opts)
828 hg.clone(ui, ui.expandpath(source), dest,
829 hg.clone(ui, ui.expandpath(source), dest,
829 pull=opts['pull'],
830 pull=opts['pull'],
830 stream=opts['uncompressed'],
831 stream=opts['uncompressed'],
831 rev=opts['rev'],
832 rev=opts['rev'],
832 update=not opts['noupdate'])
833 update=not opts['noupdate'])
833
834
834 def commit(ui, repo, *pats, **opts):
835 def commit(ui, repo, *pats, **opts):
835 """commit the specified files or all outstanding changes
836 """commit the specified files or all outstanding changes
836
837
837 Commit changes to the given files into the repository.
838 Commit changes to the given files into the repository.
838
839
839 If a list of files is omitted, all changes reported by "hg status"
840 If a list of files is omitted, all changes reported by "hg status"
840 will be committed.
841 will be committed.
841
842
842 If no commit message is specified, the editor configured in your hgrc
843 If no commit message is specified, the editor configured in your hgrc
843 or in the EDITOR environment variable is started to enter a message.
844 or in the EDITOR environment variable is started to enter a message.
844 """
845 """
845 message = logmessage(opts)
846 message = logmessage(opts)
846
847
847 if opts['addremove']:
848 if opts['addremove']:
848 cmdutil.addremove(repo, pats, opts)
849 cmdutil.addremove(repo, pats, opts)
849 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
850 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
850 if pats:
851 if pats:
851 modified, added, removed = repo.status(files=fns, match=match)[:3]
852 modified, added, removed = repo.status(files=fns, match=match)[:3]
852 files = modified + added + removed
853 files = modified + added + removed
853 else:
854 else:
854 files = []
855 files = []
855 try:
856 try:
856 repo.commit(files, message, opts['user'], opts['date'], match,
857 repo.commit(files, message, opts['user'], opts['date'], match,
857 force_editor=opts.get('force_editor'))
858 force_editor=opts.get('force_editor'))
858 except ValueError, inst:
859 except ValueError, inst:
859 raise util.Abort(str(inst))
860 raise util.Abort(str(inst))
860
861
861 def docopy(ui, repo, pats, opts, wlock):
862 def docopy(ui, repo, pats, opts, wlock):
862 # called with the repo lock held
863 # called with the repo lock held
863 cwd = repo.getcwd()
864 cwd = repo.getcwd()
864 errors = 0
865 errors = 0
865 copied = []
866 copied = []
866 targets = {}
867 targets = {}
867
868
868 def okaytocopy(abs, rel, exact):
869 def okaytocopy(abs, rel, exact):
869 reasons = {'?': _('is not managed'),
870 reasons = {'?': _('is not managed'),
870 'a': _('has been marked for add'),
871 'a': _('has been marked for add'),
871 'r': _('has been marked for remove')}
872 'r': _('has been marked for remove')}
872 state = repo.dirstate.state(abs)
873 state = repo.dirstate.state(abs)
873 reason = reasons.get(state)
874 reason = reasons.get(state)
874 if reason:
875 if reason:
875 if state == 'a':
876 if state == 'a':
876 origsrc = repo.dirstate.copied(abs)
877 origsrc = repo.dirstate.copied(abs)
877 if origsrc is not None:
878 if origsrc is not None:
878 return origsrc
879 return origsrc
879 if exact:
880 if exact:
880 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
881 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
881 else:
882 else:
882 return abs
883 return abs
883
884
884 def copy(origsrc, abssrc, relsrc, target, exact):
885 def copy(origsrc, abssrc, relsrc, target, exact):
885 abstarget = util.canonpath(repo.root, cwd, target)
886 abstarget = util.canonpath(repo.root, cwd, target)
886 reltarget = util.pathto(cwd, abstarget)
887 reltarget = util.pathto(cwd, abstarget)
887 prevsrc = targets.get(abstarget)
888 prevsrc = targets.get(abstarget)
888 if prevsrc is not None:
889 if prevsrc is not None:
889 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
890 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
890 (reltarget, abssrc, prevsrc))
891 (reltarget, abssrc, prevsrc))
891 return
892 return
892 if (not opts['after'] and os.path.exists(reltarget) or
893 if (not opts['after'] and os.path.exists(reltarget) or
893 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
894 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
894 if not opts['force']:
895 if not opts['force']:
895 ui.warn(_('%s: not overwriting - file exists\n') %
896 ui.warn(_('%s: not overwriting - file exists\n') %
896 reltarget)
897 reltarget)
897 return
898 return
898 if not opts['after'] and not opts.get('dry_run'):
899 if not opts['after'] and not opts.get('dry_run'):
899 os.unlink(reltarget)
900 os.unlink(reltarget)
900 if opts['after']:
901 if opts['after']:
901 if not os.path.exists(reltarget):
902 if not os.path.exists(reltarget):
902 return
903 return
903 else:
904 else:
904 targetdir = os.path.dirname(reltarget) or '.'
905 targetdir = os.path.dirname(reltarget) or '.'
905 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
906 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
906 os.makedirs(targetdir)
907 os.makedirs(targetdir)
907 try:
908 try:
908 restore = repo.dirstate.state(abstarget) == 'r'
909 restore = repo.dirstate.state(abstarget) == 'r'
909 if restore and not opts.get('dry_run'):
910 if restore and not opts.get('dry_run'):
910 repo.undelete([abstarget], wlock)
911 repo.undelete([abstarget], wlock)
911 try:
912 try:
912 if not opts.get('dry_run'):
913 if not opts.get('dry_run'):
913 shutil.copyfile(relsrc, reltarget)
914 shutil.copyfile(relsrc, reltarget)
914 shutil.copymode(relsrc, reltarget)
915 shutil.copymode(relsrc, reltarget)
915 restore = False
916 restore = False
916 finally:
917 finally:
917 if restore:
918 if restore:
918 repo.remove([abstarget], wlock)
919 repo.remove([abstarget], wlock)
919 except shutil.Error, inst:
920 except shutil.Error, inst:
920 raise util.Abort(str(inst))
921 raise util.Abort(str(inst))
921 except IOError, inst:
922 except IOError, inst:
922 if inst.errno == errno.ENOENT:
923 if inst.errno == errno.ENOENT:
923 ui.warn(_('%s: deleted in working copy\n') % relsrc)
924 ui.warn(_('%s: deleted in working copy\n') % relsrc)
924 else:
925 else:
925 ui.warn(_('%s: cannot copy - %s\n') %
926 ui.warn(_('%s: cannot copy - %s\n') %
926 (relsrc, inst.strerror))
927 (relsrc, inst.strerror))
927 errors += 1
928 errors += 1
928 return
929 return
929 if ui.verbose or not exact:
930 if ui.verbose or not exact:
930 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
931 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
931 targets[abstarget] = abssrc
932 targets[abstarget] = abssrc
932 if abstarget != origsrc and not opts.get('dry_run'):
933 if abstarget != origsrc and not opts.get('dry_run'):
933 repo.copy(origsrc, abstarget, wlock)
934 repo.copy(origsrc, abstarget, wlock)
934 copied.append((abssrc, relsrc, exact))
935 copied.append((abssrc, relsrc, exact))
935
936
936 def targetpathfn(pat, dest, srcs):
937 def targetpathfn(pat, dest, srcs):
937 if os.path.isdir(pat):
938 if os.path.isdir(pat):
938 abspfx = util.canonpath(repo.root, cwd, pat)
939 abspfx = util.canonpath(repo.root, cwd, pat)
939 if destdirexists:
940 if destdirexists:
940 striplen = len(os.path.split(abspfx)[0])
941 striplen = len(os.path.split(abspfx)[0])
941 else:
942 else:
942 striplen = len(abspfx)
943 striplen = len(abspfx)
943 if striplen:
944 if striplen:
944 striplen += len(os.sep)
945 striplen += len(os.sep)
945 res = lambda p: os.path.join(dest, p[striplen:])
946 res = lambda p: os.path.join(dest, p[striplen:])
946 elif destdirexists:
947 elif destdirexists:
947 res = lambda p: os.path.join(dest, os.path.basename(p))
948 res = lambda p: os.path.join(dest, os.path.basename(p))
948 else:
949 else:
949 res = lambda p: dest
950 res = lambda p: dest
950 return res
951 return res
951
952
952 def targetpathafterfn(pat, dest, srcs):
953 def targetpathafterfn(pat, dest, srcs):
953 if util.patkind(pat, None)[0]:
954 if util.patkind(pat, None)[0]:
954 # a mercurial pattern
955 # a mercurial pattern
955 res = lambda p: os.path.join(dest, os.path.basename(p))
956 res = lambda p: os.path.join(dest, os.path.basename(p))
956 else:
957 else:
957 abspfx = util.canonpath(repo.root, cwd, pat)
958 abspfx = util.canonpath(repo.root, cwd, pat)
958 if len(abspfx) < len(srcs[0][0]):
959 if len(abspfx) < len(srcs[0][0]):
959 # A directory. Either the target path contains the last
960 # A directory. Either the target path contains the last
960 # component of the source path or it does not.
961 # component of the source path or it does not.
961 def evalpath(striplen):
962 def evalpath(striplen):
962 score = 0
963 score = 0
963 for s in srcs:
964 for s in srcs:
964 t = os.path.join(dest, s[0][striplen:])
965 t = os.path.join(dest, s[0][striplen:])
965 if os.path.exists(t):
966 if os.path.exists(t):
966 score += 1
967 score += 1
967 return score
968 return score
968
969
969 striplen = len(abspfx)
970 striplen = len(abspfx)
970 if striplen:
971 if striplen:
971 striplen += len(os.sep)
972 striplen += len(os.sep)
972 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
973 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
973 score = evalpath(striplen)
974 score = evalpath(striplen)
974 striplen1 = len(os.path.split(abspfx)[0])
975 striplen1 = len(os.path.split(abspfx)[0])
975 if striplen1:
976 if striplen1:
976 striplen1 += len(os.sep)
977 striplen1 += len(os.sep)
977 if evalpath(striplen1) > score:
978 if evalpath(striplen1) > score:
978 striplen = striplen1
979 striplen = striplen1
979 res = lambda p: os.path.join(dest, p[striplen:])
980 res = lambda p: os.path.join(dest, p[striplen:])
980 else:
981 else:
981 # a file
982 # a file
982 if destdirexists:
983 if destdirexists:
983 res = lambda p: os.path.join(dest, os.path.basename(p))
984 res = lambda p: os.path.join(dest, os.path.basename(p))
984 else:
985 else:
985 res = lambda p: dest
986 res = lambda p: dest
986 return res
987 return res
987
988
988
989
989 pats = list(pats)
990 pats = list(pats)
990 if not pats:
991 if not pats:
991 raise util.Abort(_('no source or destination specified'))
992 raise util.Abort(_('no source or destination specified'))
992 if len(pats) == 1:
993 if len(pats) == 1:
993 raise util.Abort(_('no destination specified'))
994 raise util.Abort(_('no destination specified'))
994 dest = pats.pop()
995 dest = pats.pop()
995 destdirexists = os.path.isdir(dest)
996 destdirexists = os.path.isdir(dest)
996 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
997 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
997 raise util.Abort(_('with multiple sources, destination must be an '
998 raise util.Abort(_('with multiple sources, destination must be an '
998 'existing directory'))
999 'existing directory'))
999 if opts['after']:
1000 if opts['after']:
1000 tfn = targetpathafterfn
1001 tfn = targetpathafterfn
1001 else:
1002 else:
1002 tfn = targetpathfn
1003 tfn = targetpathfn
1003 copylist = []
1004 copylist = []
1004 for pat in pats:
1005 for pat in pats:
1005 srcs = []
1006 srcs = []
1006 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1007 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1007 origsrc = okaytocopy(abssrc, relsrc, exact)
1008 origsrc = okaytocopy(abssrc, relsrc, exact)
1008 if origsrc:
1009 if origsrc:
1009 srcs.append((origsrc, abssrc, relsrc, exact))
1010 srcs.append((origsrc, abssrc, relsrc, exact))
1010 if not srcs:
1011 if not srcs:
1011 continue
1012 continue
1012 copylist.append((tfn(pat, dest, srcs), srcs))
1013 copylist.append((tfn(pat, dest, srcs), srcs))
1013 if not copylist:
1014 if not copylist:
1014 raise util.Abort(_('no files to copy'))
1015 raise util.Abort(_('no files to copy'))
1015
1016
1016 for targetpath, srcs in copylist:
1017 for targetpath, srcs in copylist:
1017 for origsrc, abssrc, relsrc, exact in srcs:
1018 for origsrc, abssrc, relsrc, exact in srcs:
1018 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1019 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1019
1020
1020 if errors:
1021 if errors:
1021 ui.warn(_('(consider using --after)\n'))
1022 ui.warn(_('(consider using --after)\n'))
1022 return errors, copied
1023 return errors, copied
1023
1024
1024 def copy(ui, repo, *pats, **opts):
1025 def copy(ui, repo, *pats, **opts):
1025 """mark files as copied for the next commit
1026 """mark files as copied for the next commit
1026
1027
1027 Mark dest as having copies of source files. If dest is a
1028 Mark dest as having copies of source files. If dest is a
1028 directory, copies are put in that directory. If dest is a file,
1029 directory, copies are put in that directory. If dest is a file,
1029 there can only be one source.
1030 there can only be one source.
1030
1031
1031 By default, this command copies the contents of files as they
1032 By default, this command copies the contents of files as they
1032 stand in the working directory. If invoked with --after, the
1033 stand in the working directory. If invoked with --after, the
1033 operation is recorded, but no copying is performed.
1034 operation is recorded, but no copying is performed.
1034
1035
1035 This command takes effect in the next commit.
1036 This command takes effect in the next commit.
1036
1037
1037 NOTE: This command should be treated as experimental. While it
1038 NOTE: This command should be treated as experimental. While it
1038 should properly record copied files, this information is not yet
1039 should properly record copied files, this information is not yet
1039 fully used by merge, nor fully reported by log.
1040 fully used by merge, nor fully reported by log.
1040 """
1041 """
1041 wlock = repo.wlock(0)
1042 wlock = repo.wlock(0)
1042 errs, copied = docopy(ui, repo, pats, opts, wlock)
1043 errs, copied = docopy(ui, repo, pats, opts, wlock)
1043 return errs
1044 return errs
1044
1045
1045 def debugancestor(ui, index, rev1, rev2):
1046 def debugancestor(ui, index, rev1, rev2):
1046 """find the ancestor revision of two revisions in a given index"""
1047 """find the ancestor revision of two revisions in a given index"""
1047 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1048 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1048 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1049 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1049 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1050 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1050
1051
1051 def debugcomplete(ui, cmd='', **opts):
1052 def debugcomplete(ui, cmd='', **opts):
1052 """returns the completion list associated with the given command"""
1053 """returns the completion list associated with the given command"""
1053
1054
1054 if opts['options']:
1055 if opts['options']:
1055 options = []
1056 options = []
1056 otables = [globalopts]
1057 otables = [globalopts]
1057 if cmd:
1058 if cmd:
1058 aliases, entry = findcmd(ui, cmd)
1059 aliases, entry = findcmd(ui, cmd)
1059 otables.append(entry[1])
1060 otables.append(entry[1])
1060 for t in otables:
1061 for t in otables:
1061 for o in t:
1062 for o in t:
1062 if o[0]:
1063 if o[0]:
1063 options.append('-%s' % o[0])
1064 options.append('-%s' % o[0])
1064 options.append('--%s' % o[1])
1065 options.append('--%s' % o[1])
1065 ui.write("%s\n" % "\n".join(options))
1066 ui.write("%s\n" % "\n".join(options))
1066 return
1067 return
1067
1068
1068 clist = findpossible(ui, cmd).keys()
1069 clist = findpossible(ui, cmd).keys()
1069 clist.sort()
1070 clist.sort()
1070 ui.write("%s\n" % "\n".join(clist))
1071 ui.write("%s\n" % "\n".join(clist))
1071
1072
1072 def debugrebuildstate(ui, repo, rev=None):
1073 def debugrebuildstate(ui, repo, rev=None):
1073 """rebuild the dirstate as it would look like for the given revision"""
1074 """rebuild the dirstate as it would look like for the given revision"""
1074 if not rev:
1075 if not rev:
1075 rev = repo.changelog.tip()
1076 rev = repo.changelog.tip()
1076 else:
1077 else:
1077 rev = repo.lookup(rev)
1078 rev = repo.lookup(rev)
1078 change = repo.changelog.read(rev)
1079 change = repo.changelog.read(rev)
1079 n = change[0]
1080 n = change[0]
1080 files = repo.manifest.read(n)
1081 files = repo.manifest.read(n)
1081 wlock = repo.wlock()
1082 wlock = repo.wlock()
1082 repo.dirstate.rebuild(rev, files)
1083 repo.dirstate.rebuild(rev, files)
1083
1084
1084 def debugcheckstate(ui, repo):
1085 def debugcheckstate(ui, repo):
1085 """validate the correctness of the current dirstate"""
1086 """validate the correctness of the current dirstate"""
1086 parent1, parent2 = repo.dirstate.parents()
1087 parent1, parent2 = repo.dirstate.parents()
1087 repo.dirstate.read()
1088 repo.dirstate.read()
1088 dc = repo.dirstate.map
1089 dc = repo.dirstate.map
1089 keys = dc.keys()
1090 keys = dc.keys()
1090 keys.sort()
1091 keys.sort()
1091 m1n = repo.changelog.read(parent1)[0]
1092 m1n = repo.changelog.read(parent1)[0]
1092 m2n = repo.changelog.read(parent2)[0]
1093 m2n = repo.changelog.read(parent2)[0]
1093 m1 = repo.manifest.read(m1n)
1094 m1 = repo.manifest.read(m1n)
1094 m2 = repo.manifest.read(m2n)
1095 m2 = repo.manifest.read(m2n)
1095 errors = 0
1096 errors = 0
1096 for f in dc:
1097 for f in dc:
1097 state = repo.dirstate.state(f)
1098 state = repo.dirstate.state(f)
1098 if state in "nr" and f not in m1:
1099 if state in "nr" and f not in m1:
1099 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1100 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1100 errors += 1
1101 errors += 1
1101 if state in "a" and f in m1:
1102 if state in "a" and f in m1:
1102 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1103 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1103 errors += 1
1104 errors += 1
1104 if state in "m" and f not in m1 and f not in m2:
1105 if state in "m" and f not in m1 and f not in m2:
1105 ui.warn(_("%s in state %s, but not in either manifest\n") %
1106 ui.warn(_("%s in state %s, but not in either manifest\n") %
1106 (f, state))
1107 (f, state))
1107 errors += 1
1108 errors += 1
1108 for f in m1:
1109 for f in m1:
1109 state = repo.dirstate.state(f)
1110 state = repo.dirstate.state(f)
1110 if state not in "nrm":
1111 if state not in "nrm":
1111 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1112 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1112 errors += 1
1113 errors += 1
1113 if errors:
1114 if errors:
1114 error = _(".hg/dirstate inconsistent with current parent's manifest")
1115 error = _(".hg/dirstate inconsistent with current parent's manifest")
1115 raise util.Abort(error)
1116 raise util.Abort(error)
1116
1117
1117 def debugconfig(ui, repo, *values):
1118 def debugconfig(ui, repo, *values):
1118 """show combined config settings from all hgrc files
1119 """show combined config settings from all hgrc files
1119
1120
1120 With no args, print names and values of all config items.
1121 With no args, print names and values of all config items.
1121
1122
1122 With one arg of the form section.name, print just the value of
1123 With one arg of the form section.name, print just the value of
1123 that config item.
1124 that config item.
1124
1125
1125 With multiple args, print names and values of all config items
1126 With multiple args, print names and values of all config items
1126 with matching section names."""
1127 with matching section names."""
1127
1128
1128 if values:
1129 if values:
1129 if len([v for v in values if '.' in v]) > 1:
1130 if len([v for v in values if '.' in v]) > 1:
1130 raise util.Abort(_('only one config item permitted'))
1131 raise util.Abort(_('only one config item permitted'))
1131 for section, name, value in ui.walkconfig():
1132 for section, name, value in ui.walkconfig():
1132 sectname = section + '.' + name
1133 sectname = section + '.' + name
1133 if values:
1134 if values:
1134 for v in values:
1135 for v in values:
1135 if v == section:
1136 if v == section:
1136 ui.write('%s=%s\n' % (sectname, value))
1137 ui.write('%s=%s\n' % (sectname, value))
1137 elif v == sectname:
1138 elif v == sectname:
1138 ui.write(value, '\n')
1139 ui.write(value, '\n')
1139 else:
1140 else:
1140 ui.write('%s=%s\n' % (sectname, value))
1141 ui.write('%s=%s\n' % (sectname, value))
1141
1142
1142 def debugsetparents(ui, repo, rev1, rev2=None):
1143 def debugsetparents(ui, repo, rev1, rev2=None):
1143 """manually set the parents of the current working directory
1144 """manually set the parents of the current working directory
1144
1145
1145 This is useful for writing repository conversion tools, but should
1146 This is useful for writing repository conversion tools, but should
1146 be used with care.
1147 be used with care.
1147 """
1148 """
1148
1149
1149 if not rev2:
1150 if not rev2:
1150 rev2 = hex(nullid)
1151 rev2 = hex(nullid)
1151
1152
1152 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1153 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1153
1154
1154 def debugstate(ui, repo):
1155 def debugstate(ui, repo):
1155 """show the contents of the current dirstate"""
1156 """show the contents of the current dirstate"""
1156 repo.dirstate.read()
1157 repo.dirstate.read()
1157 dc = repo.dirstate.map
1158 dc = repo.dirstate.map
1158 keys = dc.keys()
1159 keys = dc.keys()
1159 keys.sort()
1160 keys.sort()
1160 for file_ in keys:
1161 for file_ in keys:
1161 ui.write("%c %3o %10d %s %s\n"
1162 ui.write("%c %3o %10d %s %s\n"
1162 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1163 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1163 time.strftime("%x %X",
1164 time.strftime("%x %X",
1164 time.localtime(dc[file_][3])), file_))
1165 time.localtime(dc[file_][3])), file_))
1165 for f in repo.dirstate.copies():
1166 for f in repo.dirstate.copies():
1166 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1167 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1167
1168
1168 def debugdata(ui, file_, rev):
1169 def debugdata(ui, file_, rev):
1169 """dump the contents of an data file revision"""
1170 """dump the contents of an data file revision"""
1170 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1171 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1171 file_[:-2] + ".i", file_, 0)
1172 file_[:-2] + ".i", file_, 0)
1172 try:
1173 try:
1173 ui.write(r.revision(r.lookup(rev)))
1174 ui.write(r.revision(r.lookup(rev)))
1174 except KeyError:
1175 except KeyError:
1175 raise util.Abort(_('invalid revision identifier %s') % rev)
1176 raise util.Abort(_('invalid revision identifier %s') % rev)
1176
1177
1177 def debugindex(ui, file_):
1178 def debugindex(ui, file_):
1178 """dump the contents of an index file"""
1179 """dump the contents of an index file"""
1179 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1180 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1180 ui.write(" rev offset length base linkrev" +
1181 ui.write(" rev offset length base linkrev" +
1181 " nodeid p1 p2\n")
1182 " nodeid p1 p2\n")
1182 for i in range(r.count()):
1183 for i in range(r.count()):
1183 node = r.node(i)
1184 node = r.node(i)
1184 pp = r.parents(node)
1185 pp = r.parents(node)
1185 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1186 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1186 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1187 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1187 short(node), short(pp[0]), short(pp[1])))
1188 short(node), short(pp[0]), short(pp[1])))
1188
1189
1189 def debugindexdot(ui, file_):
1190 def debugindexdot(ui, file_):
1190 """dump an index DAG as a .dot file"""
1191 """dump an index DAG as a .dot file"""
1191 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1192 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1192 ui.write("digraph G {\n")
1193 ui.write("digraph G {\n")
1193 for i in range(r.count()):
1194 for i in range(r.count()):
1194 node = r.node(i)
1195 node = r.node(i)
1195 pp = r.parents(node)
1196 pp = r.parents(node)
1196 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1197 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1197 if pp[1] != nullid:
1198 if pp[1] != nullid:
1198 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1199 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1199 ui.write("}\n")
1200 ui.write("}\n")
1200
1201
1201 def debugrename(ui, repo, file, rev=None):
1202 def debugrename(ui, repo, file, rev=None):
1202 """dump rename information"""
1203 """dump rename information"""
1203 r = repo.file(relpath(repo, [file])[0])
1204 r = repo.file(relpath(repo, [file])[0])
1204 if rev:
1205 if rev:
1205 try:
1206 try:
1206 # assume all revision numbers are for changesets
1207 # assume all revision numbers are for changesets
1207 n = repo.lookup(rev)
1208 n = repo.lookup(rev)
1208 change = repo.changelog.read(n)
1209 change = repo.changelog.read(n)
1209 m = repo.manifest.read(change[0])
1210 m = repo.manifest.read(change[0])
1210 n = m[relpath(repo, [file])[0]]
1211 n = m[relpath(repo, [file])[0]]
1211 except (hg.RepoError, KeyError):
1212 except (hg.RepoError, KeyError):
1212 n = r.lookup(rev)
1213 n = r.lookup(rev)
1213 else:
1214 else:
1214 n = r.tip()
1215 n = r.tip()
1215 m = r.renamed(n)
1216 m = r.renamed(n)
1216 if m:
1217 if m:
1217 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1218 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1218 else:
1219 else:
1219 ui.write(_("not renamed\n"))
1220 ui.write(_("not renamed\n"))
1220
1221
1221 def debugwalk(ui, repo, *pats, **opts):
1222 def debugwalk(ui, repo, *pats, **opts):
1222 """show how files match on given patterns"""
1223 """show how files match on given patterns"""
1223 items = list(cmdutil.walk(repo, pats, opts))
1224 items = list(cmdutil.walk(repo, pats, opts))
1224 if not items:
1225 if not items:
1225 return
1226 return
1226 fmt = '%%s %%-%ds %%-%ds %%s' % (
1227 fmt = '%%s %%-%ds %%-%ds %%s' % (
1227 max([len(abs) for (src, abs, rel, exact) in items]),
1228 max([len(abs) for (src, abs, rel, exact) in items]),
1228 max([len(rel) for (src, abs, rel, exact) in items]))
1229 max([len(rel) for (src, abs, rel, exact) in items]))
1229 for src, abs, rel, exact in items:
1230 for src, abs, rel, exact in items:
1230 line = fmt % (src, abs, rel, exact and 'exact' or '')
1231 line = fmt % (src, abs, rel, exact and 'exact' or '')
1231 ui.write("%s\n" % line.rstrip())
1232 ui.write("%s\n" % line.rstrip())
1232
1233
1233 def diff(ui, repo, *pats, **opts):
1234 def diff(ui, repo, *pats, **opts):
1234 """diff repository (or selected files)
1235 """diff repository (or selected files)
1235
1236
1236 Show differences between revisions for the specified files.
1237 Show differences between revisions for the specified files.
1237
1238
1238 Differences between files are shown using the unified diff format.
1239 Differences between files are shown using the unified diff format.
1239
1240
1240 When two revision arguments are given, then changes are shown
1241 When two revision arguments are given, then changes are shown
1241 between those revisions. If only one revision is specified then
1242 between those revisions. If only one revision is specified then
1242 that revision is compared to the working directory, and, when no
1243 that revision is compared to the working directory, and, when no
1243 revisions are specified, the working directory files are compared
1244 revisions are specified, the working directory files are compared
1244 to its parent.
1245 to its parent.
1245
1246
1246 Without the -a option, diff will avoid generating diffs of files
1247 Without the -a option, diff will avoid generating diffs of files
1247 it detects as binary. With -a, diff will generate a diff anyway,
1248 it detects as binary. With -a, diff will generate a diff anyway,
1248 probably with undesirable results.
1249 probably with undesirable results.
1249 """
1250 """
1250 node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
1251 node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
1251
1252
1252 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1253 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1253
1254
1254 patch.diff(repo, node1, node2, fns, match=matchfn,
1255 patch.diff(repo, node1, node2, fns, match=matchfn,
1255 opts=patch.diffopts(ui, opts))
1256 opts=patch.diffopts(ui, opts))
1256
1257
1257 def export(ui, repo, *changesets, **opts):
1258 def export(ui, repo, *changesets, **opts):
1258 """dump the header and diffs for one or more changesets
1259 """dump the header and diffs for one or more changesets
1259
1260
1260 Print the changeset header and diffs for one or more revisions.
1261 Print the changeset header and diffs for one or more revisions.
1261
1262
1262 The information shown in the changeset header is: author,
1263 The information shown in the changeset header is: author,
1263 changeset hash, parent and commit comment.
1264 changeset hash, parent and commit comment.
1264
1265
1265 Output may be to a file, in which case the name of the file is
1266 Output may be to a file, in which case the name of the file is
1266 given using a format string. The formatting rules are as follows:
1267 given using a format string. The formatting rules are as follows:
1267
1268
1268 %% literal "%" character
1269 %% literal "%" character
1269 %H changeset hash (40 bytes of hexadecimal)
1270 %H changeset hash (40 bytes of hexadecimal)
1270 %N number of patches being generated
1271 %N number of patches being generated
1271 %R changeset revision number
1272 %R changeset revision number
1272 %b basename of the exporting repository
1273 %b basename of the exporting repository
1273 %h short-form changeset hash (12 bytes of hexadecimal)
1274 %h short-form changeset hash (12 bytes of hexadecimal)
1274 %n zero-padded sequence number, starting at 1
1275 %n zero-padded sequence number, starting at 1
1275 %r zero-padded changeset revision number
1276 %r zero-padded changeset revision number
1276
1277
1277 Without the -a option, export will avoid generating diffs of files
1278 Without the -a option, export will avoid generating diffs of files
1278 it detects as binary. With -a, export will generate a diff anyway,
1279 it detects as binary. With -a, export will generate a diff anyway,
1279 probably with undesirable results.
1280 probably with undesirable results.
1280
1281
1281 With the --switch-parent option, the diff will be against the second
1282 With the --switch-parent option, the diff will be against the second
1282 parent. It can be useful to review a merge.
1283 parent. It can be useful to review a merge.
1283 """
1284 """
1284 if not changesets:
1285 if not changesets:
1285 raise util.Abort(_("export requires at least one changeset"))
1286 raise util.Abort(_("export requires at least one changeset"))
1286 revs = list(cmdutil.revrange(ui, repo, changesets))
1287 revs = list(cmdutil.revrange(ui, repo, changesets))
1287 if len(revs) > 1:
1288 if len(revs) > 1:
1288 ui.note(_('exporting patches:\n'))
1289 ui.note(_('exporting patches:\n'))
1289 else:
1290 else:
1290 ui.note(_('exporting patch:\n'))
1291 ui.note(_('exporting patch:\n'))
1291 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1292 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1292 switch_parent=opts['switch_parent'],
1293 switch_parent=opts['switch_parent'],
1293 opts=patch.diffopts(ui, opts))
1294 opts=patch.diffopts(ui, opts))
1294
1295
1295 def forget(ui, repo, *pats, **opts):
1296 def forget(ui, repo, *pats, **opts):
1296 """don't add the specified files on the next commit (DEPRECATED)
1297 """don't add the specified files on the next commit (DEPRECATED)
1297
1298
1298 (DEPRECATED)
1299 (DEPRECATED)
1299 Undo an 'hg add' scheduled for the next commit.
1300 Undo an 'hg add' scheduled for the next commit.
1300
1301
1301 This command is now deprecated and will be removed in a future
1302 This command is now deprecated and will be removed in a future
1302 release. Please use revert instead.
1303 release. Please use revert instead.
1303 """
1304 """
1304 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1305 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1305 forget = []
1306 forget = []
1306 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1307 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1307 if repo.dirstate.state(abs) == 'a':
1308 if repo.dirstate.state(abs) == 'a':
1308 forget.append(abs)
1309 forget.append(abs)
1309 if ui.verbose or not exact:
1310 if ui.verbose or not exact:
1310 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1311 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1311 repo.forget(forget)
1312 repo.forget(forget)
1312
1313
1313 def grep(ui, repo, pattern, *pats, **opts):
1314 def grep(ui, repo, pattern, *pats, **opts):
1314 """search for a pattern in specified files and revisions
1315 """search for a pattern in specified files and revisions
1315
1316
1316 Search revisions of files for a regular expression.
1317 Search revisions of files for a regular expression.
1317
1318
1318 This command behaves differently than Unix grep. It only accepts
1319 This command behaves differently than Unix grep. It only accepts
1319 Python/Perl regexps. It searches repository history, not the
1320 Python/Perl regexps. It searches repository history, not the
1320 working directory. It always prints the revision number in which
1321 working directory. It always prints the revision number in which
1321 a match appears.
1322 a match appears.
1322
1323
1323 By default, grep only prints output for the first revision of a
1324 By default, grep only prints output for the first revision of a
1324 file in which it finds a match. To get it to print every revision
1325 file in which it finds a match. To get it to print every revision
1325 that contains a change in match status ("-" for a match that
1326 that contains a change in match status ("-" for a match that
1326 becomes a non-match, or "+" for a non-match that becomes a match),
1327 becomes a non-match, or "+" for a non-match that becomes a match),
1327 use the --all flag.
1328 use the --all flag.
1328 """
1329 """
1329 reflags = 0
1330 reflags = 0
1330 if opts['ignore_case']:
1331 if opts['ignore_case']:
1331 reflags |= re.I
1332 reflags |= re.I
1332 regexp = re.compile(pattern, reflags)
1333 regexp = re.compile(pattern, reflags)
1333 sep, eol = ':', '\n'
1334 sep, eol = ':', '\n'
1334 if opts['print0']:
1335 if opts['print0']:
1335 sep = eol = '\0'
1336 sep = eol = '\0'
1336
1337
1337 fcache = {}
1338 fcache = {}
1338 def getfile(fn):
1339 def getfile(fn):
1339 if fn not in fcache:
1340 if fn not in fcache:
1340 fcache[fn] = repo.file(fn)
1341 fcache[fn] = repo.file(fn)
1341 return fcache[fn]
1342 return fcache[fn]
1342
1343
1343 def matchlines(body):
1344 def matchlines(body):
1344 begin = 0
1345 begin = 0
1345 linenum = 0
1346 linenum = 0
1346 while True:
1347 while True:
1347 match = regexp.search(body, begin)
1348 match = regexp.search(body, begin)
1348 if not match:
1349 if not match:
1349 break
1350 break
1350 mstart, mend = match.span()
1351 mstart, mend = match.span()
1351 linenum += body.count('\n', begin, mstart) + 1
1352 linenum += body.count('\n', begin, mstart) + 1
1352 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1353 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1353 lend = body.find('\n', mend)
1354 lend = body.find('\n', mend)
1354 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1355 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1355 begin = lend + 1
1356 begin = lend + 1
1356
1357
1357 class linestate(object):
1358 class linestate(object):
1358 def __init__(self, line, linenum, colstart, colend):
1359 def __init__(self, line, linenum, colstart, colend):
1359 self.line = line
1360 self.line = line
1360 self.linenum = linenum
1361 self.linenum = linenum
1361 self.colstart = colstart
1362 self.colstart = colstart
1362 self.colend = colend
1363 self.colend = colend
1363
1364
1364 def __eq__(self, other):
1365 def __eq__(self, other):
1365 return self.line == other.line
1366 return self.line == other.line
1366
1367
1367 matches = {}
1368 matches = {}
1368 copies = {}
1369 copies = {}
1369 def grepbody(fn, rev, body):
1370 def grepbody(fn, rev, body):
1370 matches[rev].setdefault(fn, [])
1371 matches[rev].setdefault(fn, [])
1371 m = matches[rev][fn]
1372 m = matches[rev][fn]
1372 for lnum, cstart, cend, line in matchlines(body):
1373 for lnum, cstart, cend, line in matchlines(body):
1373 s = linestate(line, lnum, cstart, cend)
1374 s = linestate(line, lnum, cstart, cend)
1374 m.append(s)
1375 m.append(s)
1375
1376
1376 def difflinestates(a, b):
1377 def difflinestates(a, b):
1377 sm = difflib.SequenceMatcher(None, a, b)
1378 sm = difflib.SequenceMatcher(None, a, b)
1378 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1379 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1379 if tag == 'insert':
1380 if tag == 'insert':
1380 for i in range(blo, bhi):
1381 for i in range(blo, bhi):
1381 yield ('+', b[i])
1382 yield ('+', b[i])
1382 elif tag == 'delete':
1383 elif tag == 'delete':
1383 for i in range(alo, ahi):
1384 for i in range(alo, ahi):
1384 yield ('-', a[i])
1385 yield ('-', a[i])
1385 elif tag == 'replace':
1386 elif tag == 'replace':
1386 for i in range(alo, ahi):
1387 for i in range(alo, ahi):
1387 yield ('-', a[i])
1388 yield ('-', a[i])
1388 for i in range(blo, bhi):
1389 for i in range(blo, bhi):
1389 yield ('+', b[i])
1390 yield ('+', b[i])
1390
1391
1391 prev = {}
1392 prev = {}
1392 ucache = {}
1393 ucache = {}
1393 def display(fn, rev, states, prevstates):
1394 def display(fn, rev, states, prevstates):
1394 counts = {'-': 0, '+': 0}
1395 counts = {'-': 0, '+': 0}
1395 filerevmatches = {}
1396 filerevmatches = {}
1396 if incrementing or not opts['all']:
1397 if incrementing or not opts['all']:
1397 a, b = prevstates, states
1398 a, b = prevstates, states
1398 else:
1399 else:
1399 a, b = states, prevstates
1400 a, b = states, prevstates
1400 for change, l in difflinestates(a, b):
1401 for change, l in difflinestates(a, b):
1401 if incrementing or not opts['all']:
1402 if incrementing or not opts['all']:
1402 r = rev
1403 r = rev
1403 else:
1404 else:
1404 r = prev[fn]
1405 r = prev[fn]
1405 cols = [fn, str(r)]
1406 cols = [fn, str(r)]
1406 if opts['line_number']:
1407 if opts['line_number']:
1407 cols.append(str(l.linenum))
1408 cols.append(str(l.linenum))
1408 if opts['all']:
1409 if opts['all']:
1409 cols.append(change)
1410 cols.append(change)
1410 if opts['user']:
1411 if opts['user']:
1411 cols.append(trimuser(ui, getchange(r)[1], rev,
1412 cols.append(trimuser(ui, getchange(r)[1], rev,
1412 ucache))
1413 ucache))
1413 if opts['files_with_matches']:
1414 if opts['files_with_matches']:
1414 c = (fn, rev)
1415 c = (fn, rev)
1415 if c in filerevmatches:
1416 if c in filerevmatches:
1416 continue
1417 continue
1417 filerevmatches[c] = 1
1418 filerevmatches[c] = 1
1418 else:
1419 else:
1419 cols.append(l.line)
1420 cols.append(l.line)
1420 ui.write(sep.join(cols), eol)
1421 ui.write(sep.join(cols), eol)
1421 counts[change] += 1
1422 counts[change] += 1
1422 return counts['+'], counts['-']
1423 return counts['+'], counts['-']
1423
1424
1424 fstate = {}
1425 fstate = {}
1425 skip = {}
1426 skip = {}
1426 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1427 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1427 count = 0
1428 count = 0
1428 incrementing = False
1429 incrementing = False
1429 follow = opts.get('follow')
1430 follow = opts.get('follow')
1430 for st, rev, fns in changeiter:
1431 for st, rev, fns in changeiter:
1431 if st == 'window':
1432 if st == 'window':
1432 incrementing = rev
1433 incrementing = rev
1433 matches.clear()
1434 matches.clear()
1434 elif st == 'add':
1435 elif st == 'add':
1435 change = repo.changelog.read(repo.lookup(str(rev)))
1436 change = repo.changelog.read(repo.lookup(str(rev)))
1436 mf = repo.manifest.read(change[0])
1437 mf = repo.manifest.read(change[0])
1437 matches[rev] = {}
1438 matches[rev] = {}
1438 for fn in fns:
1439 for fn in fns:
1439 if fn in skip:
1440 if fn in skip:
1440 continue
1441 continue
1441 fstate.setdefault(fn, {})
1442 fstate.setdefault(fn, {})
1442 try:
1443 try:
1443 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1444 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1444 if follow:
1445 if follow:
1445 copied = getfile(fn).renamed(mf[fn])
1446 copied = getfile(fn).renamed(mf[fn])
1446 if copied:
1447 if copied:
1447 copies.setdefault(rev, {})[fn] = copied[0]
1448 copies.setdefault(rev, {})[fn] = copied[0]
1448 except KeyError:
1449 except KeyError:
1449 pass
1450 pass
1450 elif st == 'iter':
1451 elif st == 'iter':
1451 states = matches[rev].items()
1452 states = matches[rev].items()
1452 states.sort()
1453 states.sort()
1453 for fn, m in states:
1454 for fn, m in states:
1454 copy = copies.get(rev, {}).get(fn)
1455 copy = copies.get(rev, {}).get(fn)
1455 if fn in skip:
1456 if fn in skip:
1456 if copy:
1457 if copy:
1457 skip[copy] = True
1458 skip[copy] = True
1458 continue
1459 continue
1459 if incrementing or not opts['all'] or fstate[fn]:
1460 if incrementing or not opts['all'] or fstate[fn]:
1460 pos, neg = display(fn, rev, m, fstate[fn])
1461 pos, neg = display(fn, rev, m, fstate[fn])
1461 count += pos + neg
1462 count += pos + neg
1462 if pos and not opts['all']:
1463 if pos and not opts['all']:
1463 skip[fn] = True
1464 skip[fn] = True
1464 if copy:
1465 if copy:
1465 skip[copy] = True
1466 skip[copy] = True
1466 fstate[fn] = m
1467 fstate[fn] = m
1467 if copy:
1468 if copy:
1468 fstate[copy] = m
1469 fstate[copy] = m
1469 prev[fn] = rev
1470 prev[fn] = rev
1470
1471
1471 if not incrementing:
1472 if not incrementing:
1472 fstate = fstate.items()
1473 fstate = fstate.items()
1473 fstate.sort()
1474 fstate.sort()
1474 for fn, state in fstate:
1475 for fn, state in fstate:
1475 if fn in skip:
1476 if fn in skip:
1476 continue
1477 continue
1477 if fn not in copies.get(prev[fn], {}):
1478 if fn not in copies.get(prev[fn], {}):
1478 display(fn, rev, {}, state)
1479 display(fn, rev, {}, state)
1479 return (count == 0 and 1) or 0
1480 return (count == 0 and 1) or 0
1480
1481
1481 def heads(ui, repo, **opts):
1482 def heads(ui, repo, **opts):
1482 """show current repository heads
1483 """show current repository heads
1483
1484
1484 Show all repository head changesets.
1485 Show all repository head changesets.
1485
1486
1486 Repository "heads" are changesets that don't have children
1487 Repository "heads" are changesets that don't have children
1487 changesets. They are where development generally takes place and
1488 changesets. They are where development generally takes place and
1488 are the usual targets for update and merge operations.
1489 are the usual targets for update and merge operations.
1489 """
1490 """
1490 if opts['rev']:
1491 if opts['rev']:
1491 heads = repo.heads(repo.lookup(opts['rev']))
1492 heads = repo.heads(repo.lookup(opts['rev']))
1492 else:
1493 else:
1493 heads = repo.heads()
1494 heads = repo.heads()
1494 br = None
1495 br = None
1495 if opts['branches']:
1496 if opts['branches']:
1496 br = repo.branchlookup(heads)
1497 br = repo.branchlookup(heads)
1497 displayer = show_changeset(ui, repo, opts)
1498 displayer = show_changeset(ui, repo, opts)
1498 for n in heads:
1499 for n in heads:
1499 displayer.show(changenode=n, brinfo=br)
1500 displayer.show(changenode=n, brinfo=br)
1500
1501
1501 def identify(ui, repo):
1502 def identify(ui, repo):
1502 """print information about the working copy
1503 """print information about the working copy
1503
1504
1504 Print a short summary of the current state of the repo.
1505 Print a short summary of the current state of the repo.
1505
1506
1506 This summary identifies the repository state using one or two parent
1507 This summary identifies the repository state using one or two parent
1507 hash identifiers, followed by a "+" if there are uncommitted changes
1508 hash identifiers, followed by a "+" if there are uncommitted changes
1508 in the working directory, followed by a list of tags for this revision.
1509 in the working directory, followed by a list of tags for this revision.
1509 """
1510 """
1510 parents = [p for p in repo.dirstate.parents() if p != nullid]
1511 parents = [p for p in repo.dirstate.parents() if p != nullid]
1511 if not parents:
1512 if not parents:
1512 ui.write(_("unknown\n"))
1513 ui.write(_("unknown\n"))
1513 return
1514 return
1514
1515
1515 hexfunc = ui.debugflag and hex or short
1516 hexfunc = ui.debugflag and hex or short
1516 modified, added, removed, deleted = repo.status()[:4]
1517 modified, added, removed, deleted = repo.status()[:4]
1517 output = ["%s%s" %
1518 output = ["%s%s" %
1518 ('+'.join([hexfunc(parent) for parent in parents]),
1519 ('+'.join([hexfunc(parent) for parent in parents]),
1519 (modified or added or removed or deleted) and "+" or "")]
1520 (modified or added or removed or deleted) and "+" or "")]
1520
1521
1521 if not ui.quiet:
1522 if not ui.quiet:
1522 # multiple tags for a single parent separated by '/'
1523 # multiple tags for a single parent separated by '/'
1523 parenttags = ['/'.join(tags)
1524 parenttags = ['/'.join(tags)
1524 for tags in map(repo.nodetags, parents) if tags]
1525 for tags in map(repo.nodetags, parents) if tags]
1525 # tags for multiple parents separated by ' + '
1526 # tags for multiple parents separated by ' + '
1526 if parenttags:
1527 if parenttags:
1527 output.append(' + '.join(parenttags))
1528 output.append(' + '.join(parenttags))
1528
1529
1529 ui.write("%s\n" % ' '.join(output))
1530 ui.write("%s\n" % ' '.join(output))
1530
1531
1531 def import_(ui, repo, patch1, *patches, **opts):
1532 def import_(ui, repo, patch1, *patches, **opts):
1532 """import an ordered set of patches
1533 """import an ordered set of patches
1533
1534
1534 Import a list of patches and commit them individually.
1535 Import a list of patches and commit them individually.
1535
1536
1536 If there are outstanding changes in the working directory, import
1537 If there are outstanding changes in the working directory, import
1537 will abort unless given the -f flag.
1538 will abort unless given the -f flag.
1538
1539
1539 You can import a patch straight from a mail message. Even patches
1540 You can import a patch straight from a mail message. Even patches
1540 as attachments work (body part must be type text/plain or
1541 as attachments work (body part must be type text/plain or
1541 text/x-patch to be used). From and Subject headers of email
1542 text/x-patch to be used). From and Subject headers of email
1542 message are used as default committer and commit message. All
1543 message are used as default committer and commit message. All
1543 text/plain body parts before first diff are added to commit
1544 text/plain body parts before first diff are added to commit
1544 message.
1545 message.
1545
1546
1546 If imported patch was generated by hg export, user and description
1547 If imported patch was generated by hg export, user and description
1547 from patch override values from message headers and body. Values
1548 from patch override values from message headers and body. Values
1548 given on command line with -m and -u override these.
1549 given on command line with -m and -u override these.
1549
1550
1550 To read a patch from standard input, use patch name "-".
1551 To read a patch from standard input, use patch name "-".
1551 """
1552 """
1552 patches = (patch1,) + patches
1553 patches = (patch1,) + patches
1553
1554
1554 if not opts['force']:
1555 if not opts['force']:
1555 bail_if_changed(repo)
1556 bail_if_changed(repo)
1556
1557
1557 d = opts["base"]
1558 d = opts["base"]
1558 strip = opts["strip"]
1559 strip = opts["strip"]
1559
1560
1560 wlock = repo.wlock()
1561 wlock = repo.wlock()
1561 lock = repo.lock()
1562 lock = repo.lock()
1562
1563
1563 for p in patches:
1564 for p in patches:
1564 pf = os.path.join(d, p)
1565 pf = os.path.join(d, p)
1565
1566
1566 if pf == '-':
1567 if pf == '-':
1567 ui.status(_("applying patch from stdin\n"))
1568 ui.status(_("applying patch from stdin\n"))
1568 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1569 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1569 else:
1570 else:
1570 ui.status(_("applying %s\n") % p)
1571 ui.status(_("applying %s\n") % p)
1571 tmpname, message, user, date = patch.extract(ui, file(pf))
1572 tmpname, message, user, date = patch.extract(ui, file(pf))
1572
1573
1573 if tmpname is None:
1574 if tmpname is None:
1574 raise util.Abort(_('no diffs found'))
1575 raise util.Abort(_('no diffs found'))
1575
1576
1576 try:
1577 try:
1577 if opts['message']:
1578 if opts['message']:
1578 # pickup the cmdline msg
1579 # pickup the cmdline msg
1579 message = opts['message']
1580 message = opts['message']
1580 elif message:
1581 elif message:
1581 # pickup the patch msg
1582 # pickup the patch msg
1582 message = message.strip()
1583 message = message.strip()
1583 else:
1584 else:
1584 # launch the editor
1585 # launch the editor
1585 message = None
1586 message = None
1586 ui.debug(_('message:\n%s\n') % message)
1587 ui.debug(_('message:\n%s\n') % message)
1587
1588
1588 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1589 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1589 files = patch.updatedir(ui, repo, files, wlock=wlock)
1590 files = patch.updatedir(ui, repo, files, wlock=wlock)
1590 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1591 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1591 finally:
1592 finally:
1592 os.unlink(tmpname)
1593 os.unlink(tmpname)
1593
1594
1594 def incoming(ui, repo, source="default", **opts):
1595 def incoming(ui, repo, source="default", **opts):
1595 """show new changesets found in source
1596 """show new changesets found in source
1596
1597
1597 Show new changesets found in the specified path/URL or the default
1598 Show new changesets found in the specified path/URL or the default
1598 pull location. These are the changesets that would be pulled if a pull
1599 pull location. These are the changesets that would be pulled if a pull
1599 was requested.
1600 was requested.
1600
1601
1601 For remote repository, using --bundle avoids downloading the changesets
1602 For remote repository, using --bundle avoids downloading the changesets
1602 twice if the incoming is followed by a pull.
1603 twice if the incoming is followed by a pull.
1603
1604
1604 See pull for valid source format details.
1605 See pull for valid source format details.
1605 """
1606 """
1606 source = ui.expandpath(source)
1607 source = ui.expandpath(source)
1607 setremoteconfig(ui, opts)
1608 setremoteconfig(ui, opts)
1608
1609
1609 other = hg.repository(ui, source)
1610 other = hg.repository(ui, source)
1610 incoming = repo.findincoming(other, force=opts["force"])
1611 incoming = repo.findincoming(other, force=opts["force"])
1611 if not incoming:
1612 if not incoming:
1612 ui.status(_("no changes found\n"))
1613 ui.status(_("no changes found\n"))
1613 return
1614 return
1614
1615
1615 cleanup = None
1616 cleanup = None
1616 try:
1617 try:
1617 fname = opts["bundle"]
1618 fname = opts["bundle"]
1618 if fname or not other.local():
1619 if fname or not other.local():
1619 # create a bundle (uncompressed if other repo is not local)
1620 # create a bundle (uncompressed if other repo is not local)
1620 cg = other.changegroup(incoming, "incoming")
1621 cg = other.changegroup(incoming, "incoming")
1621 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1622 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1622 # keep written bundle?
1623 # keep written bundle?
1623 if opts["bundle"]:
1624 if opts["bundle"]:
1624 cleanup = None
1625 cleanup = None
1625 if not other.local():
1626 if not other.local():
1626 # use the created uncompressed bundlerepo
1627 # use the created uncompressed bundlerepo
1627 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1628 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1628
1629
1629 revs = None
1630 revs = None
1630 if opts['rev']:
1631 if opts['rev']:
1631 revs = [other.lookup(rev) for rev in opts['rev']]
1632 revs = [other.lookup(rev) for rev in opts['rev']]
1632 o = other.changelog.nodesbetween(incoming, revs)[0]
1633 o = other.changelog.nodesbetween(incoming, revs)[0]
1633 if opts['newest_first']:
1634 if opts['newest_first']:
1634 o.reverse()
1635 o.reverse()
1635 displayer = show_changeset(ui, other, opts)
1636 displayer = show_changeset(ui, other, opts)
1636 for n in o:
1637 for n in o:
1637 parents = [p for p in other.changelog.parents(n) if p != nullid]
1638 parents = [p for p in other.changelog.parents(n) if p != nullid]
1638 if opts['no_merges'] and len(parents) == 2:
1639 if opts['no_merges'] and len(parents) == 2:
1639 continue
1640 continue
1640 displayer.show(changenode=n)
1641 displayer.show(changenode=n)
1641 if opts['patch']:
1642 if opts['patch']:
1642 prev = (parents and parents[0]) or nullid
1643 prev = (parents and parents[0]) or nullid
1643 patch.diff(other, prev, n, fp=repo.ui)
1644 patch.diff(other, prev, n, fp=repo.ui)
1644 ui.write("\n")
1645 ui.write("\n")
1645 finally:
1646 finally:
1646 if hasattr(other, 'close'):
1647 if hasattr(other, 'close'):
1647 other.close()
1648 other.close()
1648 if cleanup:
1649 if cleanup:
1649 os.unlink(cleanup)
1650 os.unlink(cleanup)
1650
1651
1651 def init(ui, dest=".", **opts):
1652 def init(ui, dest=".", **opts):
1652 """create a new repository in the given directory
1653 """create a new repository in the given directory
1653
1654
1654 Initialize a new repository in the given directory. If the given
1655 Initialize a new repository in the given directory. If the given
1655 directory does not exist, it is created.
1656 directory does not exist, it is created.
1656
1657
1657 If no directory is given, the current directory is used.
1658 If no directory is given, the current directory is used.
1658
1659
1659 It is possible to specify an ssh:// URL as the destination.
1660 It is possible to specify an ssh:// URL as the destination.
1660 Look at the help text for the pull command for important details
1661 Look at the help text for the pull command for important details
1661 about ssh:// URLs.
1662 about ssh:// URLs.
1662 """
1663 """
1663 setremoteconfig(ui, opts)
1664 setremoteconfig(ui, opts)
1664 hg.repository(ui, dest, create=1)
1665 hg.repository(ui, dest, create=1)
1665
1666
1666 def locate(ui, repo, *pats, **opts):
1667 def locate(ui, repo, *pats, **opts):
1667 """locate files matching specific patterns
1668 """locate files matching specific patterns
1668
1669
1669 Print all files under Mercurial control whose names match the
1670 Print all files under Mercurial control whose names match the
1670 given patterns.
1671 given patterns.
1671
1672
1672 This command searches the current directory and its
1673 This command searches the current directory and its
1673 subdirectories. To search an entire repository, move to the root
1674 subdirectories. To search an entire repository, move to the root
1674 of the repository.
1675 of the repository.
1675
1676
1676 If no patterns are given to match, this command prints all file
1677 If no patterns are given to match, this command prints all file
1677 names.
1678 names.
1678
1679
1679 If you want to feed the output of this command into the "xargs"
1680 If you want to feed the output of this command into the "xargs"
1680 command, use the "-0" option to both this command and "xargs".
1681 command, use the "-0" option to both this command and "xargs".
1681 This will avoid the problem of "xargs" treating single filenames
1682 This will avoid the problem of "xargs" treating single filenames
1682 that contain white space as multiple filenames.
1683 that contain white space as multiple filenames.
1683 """
1684 """
1684 end = opts['print0'] and '\0' or '\n'
1685 end = opts['print0'] and '\0' or '\n'
1685 rev = opts['rev']
1686 rev = opts['rev']
1686 if rev:
1687 if rev:
1687 node = repo.lookup(rev)
1688 node = repo.lookup(rev)
1688 else:
1689 else:
1689 node = None
1690 node = None
1690
1691
1691 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1692 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1692 head='(?:.*/|)'):
1693 head='(?:.*/|)'):
1693 if not node and repo.dirstate.state(abs) == '?':
1694 if not node and repo.dirstate.state(abs) == '?':
1694 continue
1695 continue
1695 if opts['fullpath']:
1696 if opts['fullpath']:
1696 ui.write(os.path.join(repo.root, abs), end)
1697 ui.write(os.path.join(repo.root, abs), end)
1697 else:
1698 else:
1698 ui.write(((pats and rel) or abs), end)
1699 ui.write(((pats and rel) or abs), end)
1699
1700
1700 def log(ui, repo, *pats, **opts):
1701 def log(ui, repo, *pats, **opts):
1701 """show revision history of entire repository or files
1702 """show revision history of entire repository or files
1702
1703
1703 Print the revision history of the specified files or the entire
1704 Print the revision history of the specified files or the entire
1704 project.
1705 project.
1705
1706
1706 File history is shown without following rename or copy history of
1707 File history is shown without following rename or copy history of
1707 files. Use -f/--follow with a file name to follow history across
1708 files. Use -f/--follow with a file name to follow history across
1708 renames and copies. --follow without a file name will only show
1709 renames and copies. --follow without a file name will only show
1709 ancestors or descendants of the starting revision. --follow-first
1710 ancestors or descendants of the starting revision. --follow-first
1710 only follows the first parent of merge revisions.
1711 only follows the first parent of merge revisions.
1711
1712
1712 If no revision range is specified, the default is tip:0 unless
1713 If no revision range is specified, the default is tip:0 unless
1713 --follow is set, in which case the working directory parent is
1714 --follow is set, in which case the working directory parent is
1714 used as the starting revision.
1715 used as the starting revision.
1715
1716
1716 By default this command outputs: changeset id and hash, tags,
1717 By default this command outputs: changeset id and hash, tags,
1717 non-trivial parents, user, date and time, and a summary for each
1718 non-trivial parents, user, date and time, and a summary for each
1718 commit. When the -v/--verbose switch is used, the list of changed
1719 commit. When the -v/--verbose switch is used, the list of changed
1719 files and full commit message is shown.
1720 files and full commit message is shown.
1720 """
1721 """
1721 class dui(object):
1722 class dui(object):
1722 # Implement and delegate some ui protocol. Save hunks of
1723 # Implement and delegate some ui protocol. Save hunks of
1723 # output for later display in the desired order.
1724 # output for later display in the desired order.
1724 def __init__(self, ui):
1725 def __init__(self, ui):
1725 self.ui = ui
1726 self.ui = ui
1726 self.hunk = {}
1727 self.hunk = {}
1727 self.header = {}
1728 self.header = {}
1728 def bump(self, rev):
1729 def bump(self, rev):
1729 self.rev = rev
1730 self.rev = rev
1730 self.hunk[rev] = []
1731 self.hunk[rev] = []
1731 self.header[rev] = []
1732 self.header[rev] = []
1732 def note(self, *args):
1733 def note(self, *args):
1733 if self.verbose:
1734 if self.verbose:
1734 self.write(*args)
1735 self.write(*args)
1735 def status(self, *args):
1736 def status(self, *args):
1736 if not self.quiet:
1737 if not self.quiet:
1737 self.write(*args)
1738 self.write(*args)
1738 def write(self, *args):
1739 def write(self, *args):
1739 self.hunk[self.rev].append(args)
1740 self.hunk[self.rev].append(args)
1740 def write_header(self, *args):
1741 def write_header(self, *args):
1741 self.header[self.rev].append(args)
1742 self.header[self.rev].append(args)
1742 def debug(self, *args):
1743 def debug(self, *args):
1743 if self.debugflag:
1744 if self.debugflag:
1744 self.write(*args)
1745 self.write(*args)
1745 def __getattr__(self, key):
1746 def __getattr__(self, key):
1746 return getattr(self.ui, key)
1747 return getattr(self.ui, key)
1747
1748
1748 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1749 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1749
1750
1750 if opts['limit']:
1751 if opts['limit']:
1751 try:
1752 try:
1752 limit = int(opts['limit'])
1753 limit = int(opts['limit'])
1753 except ValueError:
1754 except ValueError:
1754 raise util.Abort(_('limit must be a positive integer'))
1755 raise util.Abort(_('limit must be a positive integer'))
1755 if limit <= 0: raise util.Abort(_('limit must be positive'))
1756 if limit <= 0: raise util.Abort(_('limit must be positive'))
1756 else:
1757 else:
1757 limit = sys.maxint
1758 limit = sys.maxint
1758 count = 0
1759 count = 0
1759
1760
1760 displayer = show_changeset(ui, repo, opts)
1761 displayer = show_changeset(ui, repo, opts)
1761 for st, rev, fns in changeiter:
1762 for st, rev, fns in changeiter:
1762 if st == 'window':
1763 if st == 'window':
1763 du = dui(ui)
1764 du = dui(ui)
1764 displayer.ui = du
1765 displayer.ui = du
1765 elif st == 'add':
1766 elif st == 'add':
1766 du.bump(rev)
1767 du.bump(rev)
1767 changenode = repo.changelog.node(rev)
1768 changenode = repo.changelog.node(rev)
1768 parents = [p for p in repo.changelog.parents(changenode)
1769 parents = [p for p in repo.changelog.parents(changenode)
1769 if p != nullid]
1770 if p != nullid]
1770 if opts['no_merges'] and len(parents) == 2:
1771 if opts['no_merges'] and len(parents) == 2:
1771 continue
1772 continue
1772 if opts['only_merges'] and len(parents) != 2:
1773 if opts['only_merges'] and len(parents) != 2:
1773 continue
1774 continue
1774
1775
1775 if opts['keyword']:
1776 if opts['keyword']:
1776 changes = getchange(rev)
1777 changes = getchange(rev)
1777 miss = 0
1778 miss = 0
1778 for k in [kw.lower() for kw in opts['keyword']]:
1779 for k in [kw.lower() for kw in opts['keyword']]:
1779 if not (k in changes[1].lower() or
1780 if not (k in changes[1].lower() or
1780 k in changes[4].lower() or
1781 k in changes[4].lower() or
1781 k in " ".join(changes[3][:20]).lower()):
1782 k in " ".join(changes[3][:20]).lower()):
1782 miss = 1
1783 miss = 1
1783 break
1784 break
1784 if miss:
1785 if miss:
1785 continue
1786 continue
1786
1787
1787 br = None
1788 br = None
1788 if opts['branches']:
1789 if opts['branches']:
1789 br = repo.branchlookup([repo.changelog.node(rev)])
1790 br = repo.branchlookup([repo.changelog.node(rev)])
1790
1791
1791 displayer.show(rev, brinfo=br)
1792 displayer.show(rev, brinfo=br)
1792 if opts['patch']:
1793 if opts['patch']:
1793 prev = (parents and parents[0]) or nullid
1794 prev = (parents and parents[0]) or nullid
1794 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1795 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1795 du.write("\n\n")
1796 du.write("\n\n")
1796 elif st == 'iter':
1797 elif st == 'iter':
1797 if count == limit: break
1798 if count == limit: break
1798 if du.header[rev]:
1799 if du.header[rev]:
1799 for args in du.header[rev]:
1800 for args in du.header[rev]:
1800 ui.write_header(*args)
1801 ui.write_header(*args)
1801 if du.hunk[rev]:
1802 if du.hunk[rev]:
1802 count += 1
1803 count += 1
1803 for args in du.hunk[rev]:
1804 for args in du.hunk[rev]:
1804 ui.write(*args)
1805 ui.write(*args)
1805
1806
1806 def manifest(ui, repo, rev=None):
1807 def manifest(ui, repo, rev=None):
1807 """output the latest or given revision of the project manifest
1808 """output the latest or given revision of the project manifest
1808
1809
1809 Print a list of version controlled files for the given revision.
1810 Print a list of version controlled files for the given revision.
1810
1811
1811 The manifest is the list of files being version controlled. If no revision
1812 The manifest is the list of files being version controlled. If no revision
1812 is given then the tip is used.
1813 is given then the tip is used.
1813 """
1814 """
1814 if rev:
1815 if rev:
1815 try:
1816 try:
1816 # assume all revision numbers are for changesets
1817 # assume all revision numbers are for changesets
1817 n = repo.lookup(rev)
1818 n = repo.lookup(rev)
1818 change = repo.changelog.read(n)
1819 change = repo.changelog.read(n)
1819 n = change[0]
1820 n = change[0]
1820 except hg.RepoError:
1821 except hg.RepoError:
1821 n = repo.manifest.lookup(rev)
1822 n = repo.manifest.lookup(rev)
1822 else:
1823 else:
1823 n = repo.manifest.tip()
1824 n = repo.manifest.tip()
1824 m = repo.manifest.read(n)
1825 m = repo.manifest.read(n)
1825 files = m.keys()
1826 files = m.keys()
1826 files.sort()
1827 files.sort()
1827
1828
1828 for f in files:
1829 for f in files:
1829 ui.write("%40s %3s %s\n" % (hex(m[f]),
1830 ui.write("%40s %3s %s\n" % (hex(m[f]),
1830 m.execf(f) and "755" or "644", f))
1831 m.execf(f) and "755" or "644", f))
1831
1832
1832 def merge(ui, repo, node=None, force=None, branch=None):
1833 def merge(ui, repo, node=None, force=None, branch=None):
1833 """Merge working directory with another revision
1834 """Merge working directory with another revision
1834
1835
1835 Merge the contents of the current working directory and the
1836 Merge the contents of the current working directory and the
1836 requested revision. Files that changed between either parent are
1837 requested revision. Files that changed between either parent are
1837 marked as changed for the next commit and a commit must be
1838 marked as changed for the next commit and a commit must be
1838 performed before any further updates are allowed.
1839 performed before any further updates are allowed.
1839
1840
1840 If no revision is specified, the working directory's parent is a
1841 If no revision is specified, the working directory's parent is a
1841 head revision, and the repository contains exactly one other head,
1842 head revision, and the repository contains exactly one other head,
1842 the other head is merged with by default. Otherwise, an explicit
1843 the other head is merged with by default. Otherwise, an explicit
1843 revision to merge with must be provided.
1844 revision to merge with must be provided.
1844 """
1845 """
1845
1846
1846 if node or branch:
1847 if node or branch:
1847 node = _lookup(repo, node, branch)
1848 node = _lookup(repo, node, branch)
1848 else:
1849 else:
1849 heads = repo.heads()
1850 heads = repo.heads()
1850 if len(heads) > 2:
1851 if len(heads) > 2:
1851 raise util.Abort(_('repo has %d heads - '
1852 raise util.Abort(_('repo has %d heads - '
1852 'please merge with an explicit rev') %
1853 'please merge with an explicit rev') %
1853 len(heads))
1854 len(heads))
1854 if len(heads) == 1:
1855 if len(heads) == 1:
1855 raise util.Abort(_('there is nothing to merge - '
1856 raise util.Abort(_('there is nothing to merge - '
1856 'use "hg update" instead'))
1857 'use "hg update" instead'))
1857 parent = repo.dirstate.parents()[0]
1858 parent = repo.dirstate.parents()[0]
1858 if parent not in heads:
1859 if parent not in heads:
1859 raise util.Abort(_('working dir not at a head rev - '
1860 raise util.Abort(_('working dir not at a head rev - '
1860 'use "hg update" or merge with an explicit rev'))
1861 'use "hg update" or merge with an explicit rev'))
1861 node = parent == heads[0] and heads[-1] or heads[0]
1862 node = parent == heads[0] and heads[-1] or heads[0]
1862 return hg.merge(repo, node, force=force)
1863 return hg.merge(repo, node, force=force)
1863
1864
1864 def outgoing(ui, repo, dest=None, **opts):
1865 def outgoing(ui, repo, dest=None, **opts):
1865 """show changesets not found in destination
1866 """show changesets not found in destination
1866
1867
1867 Show changesets not found in the specified destination repository or
1868 Show changesets not found in the specified destination repository or
1868 the default push location. These are the changesets that would be pushed
1869 the default push location. These are the changesets that would be pushed
1869 if a push was requested.
1870 if a push was requested.
1870
1871
1871 See pull for valid destination format details.
1872 See pull for valid destination format details.
1872 """
1873 """
1873 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1874 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1874 setremoteconfig(ui, opts)
1875 setremoteconfig(ui, opts)
1875 revs = None
1876 revs = None
1876 if opts['rev']:
1877 if opts['rev']:
1877 revs = [repo.lookup(rev) for rev in opts['rev']]
1878 revs = [repo.lookup(rev) for rev in opts['rev']]
1878
1879
1879 other = hg.repository(ui, dest)
1880 other = hg.repository(ui, dest)
1880 o = repo.findoutgoing(other, force=opts['force'])
1881 o = repo.findoutgoing(other, force=opts['force'])
1881 if not o:
1882 if not o:
1882 ui.status(_("no changes found\n"))
1883 ui.status(_("no changes found\n"))
1883 return
1884 return
1884 o = repo.changelog.nodesbetween(o, revs)[0]
1885 o = repo.changelog.nodesbetween(o, revs)[0]
1885 if opts['newest_first']:
1886 if opts['newest_first']:
1886 o.reverse()
1887 o.reverse()
1887 displayer = show_changeset(ui, repo, opts)
1888 displayer = show_changeset(ui, repo, opts)
1888 for n in o:
1889 for n in o:
1889 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1890 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1890 if opts['no_merges'] and len(parents) == 2:
1891 if opts['no_merges'] and len(parents) == 2:
1891 continue
1892 continue
1892 displayer.show(changenode=n)
1893 displayer.show(changenode=n)
1893 if opts['patch']:
1894 if opts['patch']:
1894 prev = (parents and parents[0]) or nullid
1895 prev = (parents and parents[0]) or nullid
1895 patch.diff(repo, prev, n)
1896 patch.diff(repo, prev, n)
1896 ui.write("\n")
1897 ui.write("\n")
1897
1898
1898 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1899 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1899 """show the parents of the working dir or revision
1900 """show the parents of the working dir or revision
1900
1901
1901 Print the working directory's parent revisions.
1902 Print the working directory's parent revisions.
1902 """
1903 """
1903 # legacy
1904 # legacy
1904 if file_ and not rev:
1905 if file_ and not rev:
1905 try:
1906 try:
1906 rev = repo.lookup(file_)
1907 rev = repo.lookup(file_)
1907 file_ = None
1908 file_ = None
1908 except hg.RepoError:
1909 except hg.RepoError:
1909 pass
1910 pass
1910 else:
1911 else:
1911 ui.warn(_("'hg parent REV' is deprecated, "
1912 ui.warn(_("'hg parent REV' is deprecated, "
1912 "please use 'hg parents -r REV instead\n"))
1913 "please use 'hg parents -r REV instead\n"))
1913
1914
1914 if rev:
1915 if rev:
1915 if file_:
1916 if file_:
1916 ctx = repo.filectx(file_, changeid=rev)
1917 ctx = repo.filectx(file_, changeid=rev)
1917 else:
1918 else:
1918 ctx = repo.changectx(rev)
1919 ctx = repo.changectx(rev)
1919 p = [cp.node() for cp in ctx.parents()]
1920 p = [cp.node() for cp in ctx.parents()]
1920 else:
1921 else:
1921 p = repo.dirstate.parents()
1922 p = repo.dirstate.parents()
1922
1923
1923 br = None
1924 br = None
1924 if branches is not None:
1925 if branches is not None:
1925 br = repo.branchlookup(p)
1926 br = repo.branchlookup(p)
1926 displayer = show_changeset(ui, repo, opts)
1927 displayer = show_changeset(ui, repo, opts)
1927 for n in p:
1928 for n in p:
1928 if n != nullid:
1929 if n != nullid:
1929 displayer.show(changenode=n, brinfo=br)
1930 displayer.show(changenode=n, brinfo=br)
1930
1931
1931 def paths(ui, repo, search=None):
1932 def paths(ui, repo, search=None):
1932 """show definition of symbolic path names
1933 """show definition of symbolic path names
1933
1934
1934 Show definition of symbolic path name NAME. If no name is given, show
1935 Show definition of symbolic path name NAME. If no name is given, show
1935 definition of available names.
1936 definition of available names.
1936
1937
1937 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1938 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1938 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1939 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1939 """
1940 """
1940 if search:
1941 if search:
1941 for name, path in ui.configitems("paths"):
1942 for name, path in ui.configitems("paths"):
1942 if name == search:
1943 if name == search:
1943 ui.write("%s\n" % path)
1944 ui.write("%s\n" % path)
1944 return
1945 return
1945 ui.warn(_("not found!\n"))
1946 ui.warn(_("not found!\n"))
1946 return 1
1947 return 1
1947 else:
1948 else:
1948 for name, path in ui.configitems("paths"):
1949 for name, path in ui.configitems("paths"):
1949 ui.write("%s = %s\n" % (name, path))
1950 ui.write("%s = %s\n" % (name, path))
1950
1951
1951 def postincoming(ui, repo, modheads, optupdate):
1952 def postincoming(ui, repo, modheads, optupdate):
1952 if modheads == 0:
1953 if modheads == 0:
1953 return
1954 return
1954 if optupdate:
1955 if optupdate:
1955 if modheads == 1:
1956 if modheads == 1:
1956 return hg.update(repo, repo.changelog.tip()) # update
1957 return hg.update(repo, repo.changelog.tip()) # update
1957 else:
1958 else:
1958 ui.status(_("not updating, since new heads added\n"))
1959 ui.status(_("not updating, since new heads added\n"))
1959 if modheads > 1:
1960 if modheads > 1:
1960 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1961 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1961 else:
1962 else:
1962 ui.status(_("(run 'hg update' to get a working copy)\n"))
1963 ui.status(_("(run 'hg update' to get a working copy)\n"))
1963
1964
1964 def pull(ui, repo, source="default", **opts):
1965 def pull(ui, repo, source="default", **opts):
1965 """pull changes from the specified source
1966 """pull changes from the specified source
1966
1967
1967 Pull changes from a remote repository to a local one.
1968 Pull changes from a remote repository to a local one.
1968
1969
1969 This finds all changes from the repository at the specified path
1970 This finds all changes from the repository at the specified path
1970 or URL and adds them to the local repository. By default, this
1971 or URL and adds them to the local repository. By default, this
1971 does not update the copy of the project in the working directory.
1972 does not update the copy of the project in the working directory.
1972
1973
1973 Valid URLs are of the form:
1974 Valid URLs are of the form:
1974
1975
1975 local/filesystem/path
1976 local/filesystem/path
1976 http://[user@]host[:port]/[path]
1977 http://[user@]host[:port]/[path]
1977 https://[user@]host[:port]/[path]
1978 https://[user@]host[:port]/[path]
1978 ssh://[user@]host[:port]/[path]
1979 ssh://[user@]host[:port]/[path]
1979
1980
1980 Some notes about using SSH with Mercurial:
1981 Some notes about using SSH with Mercurial:
1981 - SSH requires an accessible shell account on the destination machine
1982 - SSH requires an accessible shell account on the destination machine
1982 and a copy of hg in the remote path or specified with as remotecmd.
1983 and a copy of hg in the remote path or specified with as remotecmd.
1983 - path is relative to the remote user's home directory by default.
1984 - path is relative to the remote user's home directory by default.
1984 Use an extra slash at the start of a path to specify an absolute path:
1985 Use an extra slash at the start of a path to specify an absolute path:
1985 ssh://example.com//tmp/repository
1986 ssh://example.com//tmp/repository
1986 - Mercurial doesn't use its own compression via SSH; the right thing
1987 - Mercurial doesn't use its own compression via SSH; the right thing
1987 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
1988 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
1988 Host *.mylocalnetwork.example.com
1989 Host *.mylocalnetwork.example.com
1989 Compression off
1990 Compression off
1990 Host *
1991 Host *
1991 Compression on
1992 Compression on
1992 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1993 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1993 with the --ssh command line option.
1994 with the --ssh command line option.
1994 """
1995 """
1995 source = ui.expandpath(source)
1996 source = ui.expandpath(source)
1996 setremoteconfig(ui, opts)
1997 setremoteconfig(ui, opts)
1997
1998
1998 other = hg.repository(ui, source)
1999 other = hg.repository(ui, source)
1999 ui.status(_('pulling from %s\n') % (source))
2000 ui.status(_('pulling from %s\n') % (source))
2000 revs = None
2001 revs = None
2001 if opts['rev'] and not other.local():
2002 if opts['rev'] and not other.local():
2002 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2003 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2003 elif opts['rev']:
2004 elif opts['rev']:
2004 revs = [other.lookup(rev) for rev in opts['rev']]
2005 revs = [other.lookup(rev) for rev in opts['rev']]
2005 modheads = repo.pull(other, heads=revs, force=opts['force'])
2006 modheads = repo.pull(other, heads=revs, force=opts['force'])
2006 return postincoming(ui, repo, modheads, opts['update'])
2007 return postincoming(ui, repo, modheads, opts['update'])
2007
2008
2008 def push(ui, repo, dest=None, **opts):
2009 def push(ui, repo, dest=None, **opts):
2009 """push changes to the specified destination
2010 """push changes to the specified destination
2010
2011
2011 Push changes from the local repository to the given destination.
2012 Push changes from the local repository to the given destination.
2012
2013
2013 This is the symmetrical operation for pull. It helps to move
2014 This is the symmetrical operation for pull. It helps to move
2014 changes from the current repository to a different one. If the
2015 changes from the current repository to a different one. If the
2015 destination is local this is identical to a pull in that directory
2016 destination is local this is identical to a pull in that directory
2016 from the current one.
2017 from the current one.
2017
2018
2018 By default, push will refuse to run if it detects the result would
2019 By default, push will refuse to run if it detects the result would
2019 increase the number of remote heads. This generally indicates the
2020 increase the number of remote heads. This generally indicates the
2020 the client has forgotten to sync and merge before pushing.
2021 the client has forgotten to sync and merge before pushing.
2021
2022
2022 Valid URLs are of the form:
2023 Valid URLs are of the form:
2023
2024
2024 local/filesystem/path
2025 local/filesystem/path
2025 ssh://[user@]host[:port]/[path]
2026 ssh://[user@]host[:port]/[path]
2026
2027
2027 Look at the help text for the pull command for important details
2028 Look at the help text for the pull command for important details
2028 about ssh:// URLs.
2029 about ssh:// URLs.
2029
2030
2030 Pushing to http:// and https:// URLs is possible, too, if this
2031 Pushing to http:// and https:// URLs is possible, too, if this
2031 feature is enabled on the remote Mercurial server.
2032 feature is enabled on the remote Mercurial server.
2032 """
2033 """
2033 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2034 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2034 setremoteconfig(ui, opts)
2035 setremoteconfig(ui, opts)
2035
2036
2036 other = hg.repository(ui, dest)
2037 other = hg.repository(ui, dest)
2037 ui.status('pushing to %s\n' % (dest))
2038 ui.status('pushing to %s\n' % (dest))
2038 revs = None
2039 revs = None
2039 if opts['rev']:
2040 if opts['rev']:
2040 revs = [repo.lookup(rev) for rev in opts['rev']]
2041 revs = [repo.lookup(rev) for rev in opts['rev']]
2041 r = repo.push(other, opts['force'], revs=revs)
2042 r = repo.push(other, opts['force'], revs=revs)
2042 return r == 0
2043 return r == 0
2043
2044
2044 def rawcommit(ui, repo, *flist, **rc):
2045 def rawcommit(ui, repo, *flist, **rc):
2045 """raw commit interface (DEPRECATED)
2046 """raw commit interface (DEPRECATED)
2046
2047
2047 (DEPRECATED)
2048 (DEPRECATED)
2048 Lowlevel commit, for use in helper scripts.
2049 Lowlevel commit, for use in helper scripts.
2049
2050
2050 This command is not intended to be used by normal users, as it is
2051 This command is not intended to be used by normal users, as it is
2051 primarily useful for importing from other SCMs.
2052 primarily useful for importing from other SCMs.
2052
2053
2053 This command is now deprecated and will be removed in a future
2054 This command is now deprecated and will be removed in a future
2054 release, please use debugsetparents and commit instead.
2055 release, please use debugsetparents and commit instead.
2055 """
2056 """
2056
2057
2057 ui.warn(_("(the rawcommit command is deprecated)\n"))
2058 ui.warn(_("(the rawcommit command is deprecated)\n"))
2058
2059
2059 message = rc['message']
2060 message = rc['message']
2060 if not message and rc['logfile']:
2061 if not message and rc['logfile']:
2061 try:
2062 try:
2062 message = open(rc['logfile']).read()
2063 message = open(rc['logfile']).read()
2063 except IOError:
2064 except IOError:
2064 pass
2065 pass
2065 if not message and not rc['logfile']:
2066 if not message and not rc['logfile']:
2066 raise util.Abort(_("missing commit message"))
2067 raise util.Abort(_("missing commit message"))
2067
2068
2068 files = relpath(repo, list(flist))
2069 files = relpath(repo, list(flist))
2069 if rc['files']:
2070 if rc['files']:
2070 files += open(rc['files']).read().splitlines()
2071 files += open(rc['files']).read().splitlines()
2071
2072
2072 rc['parent'] = map(repo.lookup, rc['parent'])
2073 rc['parent'] = map(repo.lookup, rc['parent'])
2073
2074
2074 try:
2075 try:
2075 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2076 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2076 except ValueError, inst:
2077 except ValueError, inst:
2077 raise util.Abort(str(inst))
2078 raise util.Abort(str(inst))
2078
2079
2079 def recover(ui, repo):
2080 def recover(ui, repo):
2080 """roll back an interrupted transaction
2081 """roll back an interrupted transaction
2081
2082
2082 Recover from an interrupted commit or pull.
2083 Recover from an interrupted commit or pull.
2083
2084
2084 This command tries to fix the repository status after an interrupted
2085 This command tries to fix the repository status after an interrupted
2085 operation. It should only be necessary when Mercurial suggests it.
2086 operation. It should only be necessary when Mercurial suggests it.
2086 """
2087 """
2087 if repo.recover():
2088 if repo.recover():
2088 return hg.verify(repo)
2089 return hg.verify(repo)
2089 return 1
2090 return 1
2090
2091
2091 def remove(ui, repo, *pats, **opts):
2092 def remove(ui, repo, *pats, **opts):
2092 """remove the specified files on the next commit
2093 """remove the specified files on the next commit
2093
2094
2094 Schedule the indicated files for removal from the repository.
2095 Schedule the indicated files for removal from the repository.
2095
2096
2096 This command schedules the files to be removed at the next commit.
2097 This command schedules the files to be removed at the next commit.
2097 This only removes files from the current branch, not from the
2098 This only removes files from the current branch, not from the
2098 entire project history. If the files still exist in the working
2099 entire project history. If the files still exist in the working
2099 directory, they will be deleted from it. If invoked with --after,
2100 directory, they will be deleted from it. If invoked with --after,
2100 files that have been manually deleted are marked as removed.
2101 files that have been manually deleted are marked as removed.
2101
2102
2102 Modified files and added files are not removed by default. To
2103 Modified files and added files are not removed by default. To
2103 remove them, use the -f/--force option.
2104 remove them, use the -f/--force option.
2104 """
2105 """
2105 names = []
2106 names = []
2106 if not opts['after'] and not pats:
2107 if not opts['after'] and not pats:
2107 raise util.Abort(_('no files specified'))
2108 raise util.Abort(_('no files specified'))
2108 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2109 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2109 exact = dict.fromkeys(files)
2110 exact = dict.fromkeys(files)
2110 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2111 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2111 modified, added, removed, deleted, unknown = mardu
2112 modified, added, removed, deleted, unknown = mardu
2112 remove, forget = [], []
2113 remove, forget = [], []
2113 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2114 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2114 reason = None
2115 reason = None
2115 if abs not in deleted and opts['after']:
2116 if abs not in deleted and opts['after']:
2116 reason = _('is still present')
2117 reason = _('is still present')
2117 elif abs in modified and not opts['force']:
2118 elif abs in modified and not opts['force']:
2118 reason = _('is modified (use -f to force removal)')
2119 reason = _('is modified (use -f to force removal)')
2119 elif abs in added:
2120 elif abs in added:
2120 if opts['force']:
2121 if opts['force']:
2121 forget.append(abs)
2122 forget.append(abs)
2122 continue
2123 continue
2123 reason = _('has been marked for add (use -f to force removal)')
2124 reason = _('has been marked for add (use -f to force removal)')
2124 elif abs in unknown:
2125 elif abs in unknown:
2125 reason = _('is not managed')
2126 reason = _('is not managed')
2126 elif abs in removed:
2127 elif abs in removed:
2127 continue
2128 continue
2128 if reason:
2129 if reason:
2129 if exact:
2130 if exact:
2130 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2131 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2131 else:
2132 else:
2132 if ui.verbose or not exact:
2133 if ui.verbose or not exact:
2133 ui.status(_('removing %s\n') % rel)
2134 ui.status(_('removing %s\n') % rel)
2134 remove.append(abs)
2135 remove.append(abs)
2135 repo.forget(forget)
2136 repo.forget(forget)
2136 repo.remove(remove, unlink=not opts['after'])
2137 repo.remove(remove, unlink=not opts['after'])
2137
2138
2138 def rename(ui, repo, *pats, **opts):
2139 def rename(ui, repo, *pats, **opts):
2139 """rename files; equivalent of copy + remove
2140 """rename files; equivalent of copy + remove
2140
2141
2141 Mark dest as copies of sources; mark sources for deletion. If
2142 Mark dest as copies of sources; mark sources for deletion. If
2142 dest is a directory, copies are put in that directory. If dest is
2143 dest is a directory, copies are put in that directory. If dest is
2143 a file, there can only be one source.
2144 a file, there can only be one source.
2144
2145
2145 By default, this command copies the contents of files as they
2146 By default, this command copies the contents of files as they
2146 stand in the working directory. If invoked with --after, the
2147 stand in the working directory. If invoked with --after, the
2147 operation is recorded, but no copying is performed.
2148 operation is recorded, but no copying is performed.
2148
2149
2149 This command takes effect in the next commit.
2150 This command takes effect in the next commit.
2150
2151
2151 NOTE: This command should be treated as experimental. While it
2152 NOTE: This command should be treated as experimental. While it
2152 should properly record rename files, this information is not yet
2153 should properly record rename files, this information is not yet
2153 fully used by merge, nor fully reported by log.
2154 fully used by merge, nor fully reported by log.
2154 """
2155 """
2155 wlock = repo.wlock(0)
2156 wlock = repo.wlock(0)
2156 errs, copied = docopy(ui, repo, pats, opts, wlock)
2157 errs, copied = docopy(ui, repo, pats, opts, wlock)
2157 names = []
2158 names = []
2158 for abs, rel, exact in copied:
2159 for abs, rel, exact in copied:
2159 if ui.verbose or not exact:
2160 if ui.verbose or not exact:
2160 ui.status(_('removing %s\n') % rel)
2161 ui.status(_('removing %s\n') % rel)
2161 names.append(abs)
2162 names.append(abs)
2162 if not opts.get('dry_run'):
2163 if not opts.get('dry_run'):
2163 repo.remove(names, True, wlock)
2164 repo.remove(names, True, wlock)
2164 return errs
2165 return errs
2165
2166
2166 def revert(ui, repo, *pats, **opts):
2167 def revert(ui, repo, *pats, **opts):
2167 """revert files or dirs to their states as of some revision
2168 """revert files or dirs to their states as of some revision
2168
2169
2169 With no revision specified, revert the named files or directories
2170 With no revision specified, revert the named files or directories
2170 to the contents they had in the parent of the working directory.
2171 to the contents they had in the parent of the working directory.
2171 This restores the contents of the affected files to an unmodified
2172 This restores the contents of the affected files to an unmodified
2172 state. If the working directory has two parents, you must
2173 state. If the working directory has two parents, you must
2173 explicitly specify the revision to revert to.
2174 explicitly specify the revision to revert to.
2174
2175
2175 Modified files are saved with a .orig suffix before reverting.
2176 Modified files are saved with a .orig suffix before reverting.
2176 To disable these backups, use --no-backup.
2177 To disable these backups, use --no-backup.
2177
2178
2178 Using the -r option, revert the given files or directories to their
2179 Using the -r option, revert the given files or directories to their
2179 contents as of a specific revision. This can be helpful to "roll
2180 contents as of a specific revision. This can be helpful to "roll
2180 back" some or all of a change that should not have been committed.
2181 back" some or all of a change that should not have been committed.
2181
2182
2182 Revert modifies the working directory. It does not commit any
2183 Revert modifies the working directory. It does not commit any
2183 changes, or change the parent of the working directory. If you
2184 changes, or change the parent of the working directory. If you
2184 revert to a revision other than the parent of the working
2185 revert to a revision other than the parent of the working
2185 directory, the reverted files will thus appear modified
2186 directory, the reverted files will thus appear modified
2186 afterwards.
2187 afterwards.
2187
2188
2188 If a file has been deleted, it is recreated. If the executable
2189 If a file has been deleted, it is recreated. If the executable
2189 mode of a file was changed, it is reset.
2190 mode of a file was changed, it is reset.
2190
2191
2191 If names are given, all files matching the names are reverted.
2192 If names are given, all files matching the names are reverted.
2192
2193
2193 If no arguments are given, no files are reverted.
2194 If no arguments are given, no files are reverted.
2194 """
2195 """
2195
2196
2196 if not pats and not opts['all']:
2197 if not pats and not opts['all']:
2197 raise util.Abort(_('no files or directories specified; '
2198 raise util.Abort(_('no files or directories specified; '
2198 'use --all to revert the whole repo'))
2199 'use --all to revert the whole repo'))
2199
2200
2200 parent, p2 = repo.dirstate.parents()
2201 parent, p2 = repo.dirstate.parents()
2201 if not opts['rev'] and p2 != nullid:
2202 if not opts['rev'] and p2 != nullid:
2202 raise util.Abort(_('uncommitted merge - please provide a '
2203 raise util.Abort(_('uncommitted merge - please provide a '
2203 'specific revision'))
2204 'specific revision'))
2204 node = repo.changectx(opts['rev']).node()
2205 node = repo.changectx(opts['rev']).node()
2205 mf = repo.manifest.read(repo.changelog.read(node)[0])
2206 mf = repo.manifest.read(repo.changelog.read(node)[0])
2206 if node == parent:
2207 if node == parent:
2207 pmf = mf
2208 pmf = mf
2208 else:
2209 else:
2209 pmf = None
2210 pmf = None
2210
2211
2211 wlock = repo.wlock()
2212 wlock = repo.wlock()
2212
2213
2213 # need all matching names in dirstate and manifest of target rev,
2214 # need all matching names in dirstate and manifest of target rev,
2214 # so have to walk both. do not print errors if files exist in one
2215 # so have to walk both. do not print errors if files exist in one
2215 # but not other.
2216 # but not other.
2216
2217
2217 names = {}
2218 names = {}
2218 target_only = {}
2219 target_only = {}
2219
2220
2220 # walk dirstate.
2221 # walk dirstate.
2221
2222
2222 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2223 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2223 badmatch=mf.has_key):
2224 badmatch=mf.has_key):
2224 names[abs] = (rel, exact)
2225 names[abs] = (rel, exact)
2225 if src == 'b':
2226 if src == 'b':
2226 target_only[abs] = True
2227 target_only[abs] = True
2227
2228
2228 # walk target manifest.
2229 # walk target manifest.
2229
2230
2230 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2231 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2231 badmatch=names.has_key):
2232 badmatch=names.has_key):
2232 if abs in names: continue
2233 if abs in names: continue
2233 names[abs] = (rel, exact)
2234 names[abs] = (rel, exact)
2234 target_only[abs] = True
2235 target_only[abs] = True
2235
2236
2236 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2237 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2237 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2238 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2238
2239
2239 revert = ([], _('reverting %s\n'))
2240 revert = ([], _('reverting %s\n'))
2240 add = ([], _('adding %s\n'))
2241 add = ([], _('adding %s\n'))
2241 remove = ([], _('removing %s\n'))
2242 remove = ([], _('removing %s\n'))
2242 forget = ([], _('forgetting %s\n'))
2243 forget = ([], _('forgetting %s\n'))
2243 undelete = ([], _('undeleting %s\n'))
2244 undelete = ([], _('undeleting %s\n'))
2244 update = {}
2245 update = {}
2245
2246
2246 disptable = (
2247 disptable = (
2247 # dispatch table:
2248 # dispatch table:
2248 # file state
2249 # file state
2249 # action if in target manifest
2250 # action if in target manifest
2250 # action if not in target manifest
2251 # action if not in target manifest
2251 # make backup if in target manifest
2252 # make backup if in target manifest
2252 # make backup if not in target manifest
2253 # make backup if not in target manifest
2253 (modified, revert, remove, True, True),
2254 (modified, revert, remove, True, True),
2254 (added, revert, forget, True, False),
2255 (added, revert, forget, True, False),
2255 (removed, undelete, None, False, False),
2256 (removed, undelete, None, False, False),
2256 (deleted, revert, remove, False, False),
2257 (deleted, revert, remove, False, False),
2257 (unknown, add, None, True, False),
2258 (unknown, add, None, True, False),
2258 (target_only, add, None, False, False),
2259 (target_only, add, None, False, False),
2259 )
2260 )
2260
2261
2261 entries = names.items()
2262 entries = names.items()
2262 entries.sort()
2263 entries.sort()
2263
2264
2264 for abs, (rel, exact) in entries:
2265 for abs, (rel, exact) in entries:
2265 mfentry = mf.get(abs)
2266 mfentry = mf.get(abs)
2266 def handle(xlist, dobackup):
2267 def handle(xlist, dobackup):
2267 xlist[0].append(abs)
2268 xlist[0].append(abs)
2268 update[abs] = 1
2269 update[abs] = 1
2269 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2270 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2270 bakname = "%s.orig" % rel
2271 bakname = "%s.orig" % rel
2271 ui.note(_('saving current version of %s as %s\n') %
2272 ui.note(_('saving current version of %s as %s\n') %
2272 (rel, bakname))
2273 (rel, bakname))
2273 if not opts.get('dry_run'):
2274 if not opts.get('dry_run'):
2274 shutil.copyfile(rel, bakname)
2275 shutil.copyfile(rel, bakname)
2275 shutil.copymode(rel, bakname)
2276 shutil.copymode(rel, bakname)
2276 if ui.verbose or not exact:
2277 if ui.verbose or not exact:
2277 ui.status(xlist[1] % rel)
2278 ui.status(xlist[1] % rel)
2278 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2279 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2279 if abs not in table: continue
2280 if abs not in table: continue
2280 # file has changed in dirstate
2281 # file has changed in dirstate
2281 if mfentry:
2282 if mfentry:
2282 handle(hitlist, backuphit)
2283 handle(hitlist, backuphit)
2283 elif misslist is not None:
2284 elif misslist is not None:
2284 handle(misslist, backupmiss)
2285 handle(misslist, backupmiss)
2285 else:
2286 else:
2286 if exact: ui.warn(_('file not managed: %s\n' % rel))
2287 if exact: ui.warn(_('file not managed: %s\n' % rel))
2287 break
2288 break
2288 else:
2289 else:
2289 # file has not changed in dirstate
2290 # file has not changed in dirstate
2290 if node == parent:
2291 if node == parent:
2291 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2292 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2292 continue
2293 continue
2293 if pmf is None:
2294 if pmf is None:
2294 # only need parent manifest in this unlikely case,
2295 # only need parent manifest in this unlikely case,
2295 # so do not read by default
2296 # so do not read by default
2296 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2297 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2297 if abs in pmf:
2298 if abs in pmf:
2298 if mfentry:
2299 if mfentry:
2299 # if version of file is same in parent and target
2300 # if version of file is same in parent and target
2300 # manifests, do nothing
2301 # manifests, do nothing
2301 if pmf[abs] != mfentry:
2302 if pmf[abs] != mfentry:
2302 handle(revert, False)
2303 handle(revert, False)
2303 else:
2304 else:
2304 handle(remove, False)
2305 handle(remove, False)
2305
2306
2306 if not opts.get('dry_run'):
2307 if not opts.get('dry_run'):
2307 repo.dirstate.forget(forget[0])
2308 repo.dirstate.forget(forget[0])
2308 r = hg.revert(repo, node, update.has_key, wlock)
2309 r = hg.revert(repo, node, update.has_key, wlock)
2309 repo.dirstate.update(add[0], 'a')
2310 repo.dirstate.update(add[0], 'a')
2310 repo.dirstate.update(undelete[0], 'n')
2311 repo.dirstate.update(undelete[0], 'n')
2311 repo.dirstate.update(remove[0], 'r')
2312 repo.dirstate.update(remove[0], 'r')
2312 return r
2313 return r
2313
2314
2314 def rollback(ui, repo):
2315 def rollback(ui, repo):
2315 """roll back the last transaction in this repository
2316 """roll back the last transaction in this repository
2316
2317
2317 Roll back the last transaction in this repository, restoring the
2318 Roll back the last transaction in this repository, restoring the
2318 project to its state prior to the transaction.
2319 project to its state prior to the transaction.
2319
2320
2320 Transactions are used to encapsulate the effects of all commands
2321 Transactions are used to encapsulate the effects of all commands
2321 that create new changesets or propagate existing changesets into a
2322 that create new changesets or propagate existing changesets into a
2322 repository. For example, the following commands are transactional,
2323 repository. For example, the following commands are transactional,
2323 and their effects can be rolled back:
2324 and their effects can be rolled back:
2324
2325
2325 commit
2326 commit
2326 import
2327 import
2327 pull
2328 pull
2328 push (with this repository as destination)
2329 push (with this repository as destination)
2329 unbundle
2330 unbundle
2330
2331
2331 This command should be used with care. There is only one level of
2332 This command should be used with care. There is only one level of
2332 rollback, and there is no way to undo a rollback.
2333 rollback, and there is no way to undo a rollback.
2333
2334
2334 This command is not intended for use on public repositories. Once
2335 This command is not intended for use on public repositories. Once
2335 changes are visible for pull by other users, rolling a transaction
2336 changes are visible for pull by other users, rolling a transaction
2336 back locally is ineffective (someone else may already have pulled
2337 back locally is ineffective (someone else may already have pulled
2337 the changes). Furthermore, a race is possible with readers of the
2338 the changes). Furthermore, a race is possible with readers of the
2338 repository; for example an in-progress pull from the repository
2339 repository; for example an in-progress pull from the repository
2339 may fail if a rollback is performed.
2340 may fail if a rollback is performed.
2340 """
2341 """
2341 repo.rollback()
2342 repo.rollback()
2342
2343
2343 def root(ui, repo):
2344 def root(ui, repo):
2344 """print the root (top) of the current working dir
2345 """print the root (top) of the current working dir
2345
2346
2346 Print the root directory of the current repository.
2347 Print the root directory of the current repository.
2347 """
2348 """
2348 ui.write(repo.root + "\n")
2349 ui.write(repo.root + "\n")
2349
2350
2350 def serve(ui, repo, **opts):
2351 def serve(ui, repo, **opts):
2351 """export the repository via HTTP
2352 """export the repository via HTTP
2352
2353
2353 Start a local HTTP repository browser and pull server.
2354 Start a local HTTP repository browser and pull server.
2354
2355
2355 By default, the server logs accesses to stdout and errors to
2356 By default, the server logs accesses to stdout and errors to
2356 stderr. Use the "-A" and "-E" options to log to files.
2357 stderr. Use the "-A" and "-E" options to log to files.
2357 """
2358 """
2358
2359
2359 if opts["stdio"]:
2360 if opts["stdio"]:
2360 if repo is None:
2361 if repo is None:
2361 raise hg.RepoError(_("There is no Mercurial repository here"
2362 raise hg.RepoError(_("There is no Mercurial repository here"
2362 " (.hg not found)"))
2363 " (.hg not found)"))
2363 s = sshserver.sshserver(ui, repo)
2364 s = sshserver.sshserver(ui, repo)
2364 s.serve_forever()
2365 s.serve_forever()
2365
2366
2366 optlist = ("name templates style address port ipv6"
2367 optlist = ("name templates style address port ipv6"
2367 " accesslog errorlog webdir_conf")
2368 " accesslog errorlog webdir_conf")
2368 for o in optlist.split():
2369 for o in optlist.split():
2369 if opts[o]:
2370 if opts[o]:
2370 ui.setconfig("web", o, opts[o])
2371 ui.setconfig("web", o, opts[o])
2371
2372
2372 if repo is None and not ui.config("web", "webdir_conf"):
2373 if repo is None and not ui.config("web", "webdir_conf"):
2373 raise hg.RepoError(_("There is no Mercurial repository here"
2374 raise hg.RepoError(_("There is no Mercurial repository here"
2374 " (.hg not found)"))
2375 " (.hg not found)"))
2375
2376
2376 if opts['daemon'] and not opts['daemon_pipefds']:
2377 if opts['daemon'] and not opts['daemon_pipefds']:
2377 rfd, wfd = os.pipe()
2378 rfd, wfd = os.pipe()
2378 args = sys.argv[:]
2379 args = sys.argv[:]
2379 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2380 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2380 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2381 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2381 args[0], args)
2382 args[0], args)
2382 os.close(wfd)
2383 os.close(wfd)
2383 os.read(rfd, 1)
2384 os.read(rfd, 1)
2384 os._exit(0)
2385 os._exit(0)
2385
2386
2386 try:
2387 try:
2387 httpd = hgweb.server.create_server(ui, repo)
2388 httpd = hgweb.server.create_server(ui, repo)
2388 except socket.error, inst:
2389 except socket.error, inst:
2389 raise util.Abort(_('cannot start server: %s') % inst.args[1])
2390 raise util.Abort(_('cannot start server: %s') % inst.args[1])
2390
2391
2391 if ui.verbose:
2392 if ui.verbose:
2392 addr, port = httpd.socket.getsockname()
2393 addr, port = httpd.socket.getsockname()
2393 if addr == '0.0.0.0':
2394 if addr == '0.0.0.0':
2394 addr = socket.gethostname()
2395 addr = socket.gethostname()
2395 else:
2396 else:
2396 try:
2397 try:
2397 addr = socket.gethostbyaddr(addr)[0]
2398 addr = socket.gethostbyaddr(addr)[0]
2398 except socket.error:
2399 except socket.error:
2399 pass
2400 pass
2400 if port != 80:
2401 if port != 80:
2401 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2402 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2402 else:
2403 else:
2403 ui.status(_('listening at http://%s/\n') % addr)
2404 ui.status(_('listening at http://%s/\n') % addr)
2404
2405
2405 if opts['pid_file']:
2406 if opts['pid_file']:
2406 fp = open(opts['pid_file'], 'w')
2407 fp = open(opts['pid_file'], 'w')
2407 fp.write(str(os.getpid()) + '\n')
2408 fp.write(str(os.getpid()) + '\n')
2408 fp.close()
2409 fp.close()
2409
2410
2410 if opts['daemon_pipefds']:
2411 if opts['daemon_pipefds']:
2411 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2412 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2412 os.close(rfd)
2413 os.close(rfd)
2413 os.write(wfd, 'y')
2414 os.write(wfd, 'y')
2414 os.close(wfd)
2415 os.close(wfd)
2415 sys.stdout.flush()
2416 sys.stdout.flush()
2416 sys.stderr.flush()
2417 sys.stderr.flush()
2417 fd = os.open(util.nulldev, os.O_RDWR)
2418 fd = os.open(util.nulldev, os.O_RDWR)
2418 if fd != 0: os.dup2(fd, 0)
2419 if fd != 0: os.dup2(fd, 0)
2419 if fd != 1: os.dup2(fd, 1)
2420 if fd != 1: os.dup2(fd, 1)
2420 if fd != 2: os.dup2(fd, 2)
2421 if fd != 2: os.dup2(fd, 2)
2421 if fd not in (0, 1, 2): os.close(fd)
2422 if fd not in (0, 1, 2): os.close(fd)
2422
2423
2423 httpd.serve_forever()
2424 httpd.serve_forever()
2424
2425
2425 def status(ui, repo, *pats, **opts):
2426 def status(ui, repo, *pats, **opts):
2426 """show changed files in the working directory
2427 """show changed files in the working directory
2427
2428
2428 Show status of files in the repository. If names are given, only
2429 Show status of files in the repository. If names are given, only
2429 files that match are shown. Files that are clean or ignored, are
2430 files that match are shown. Files that are clean or ignored, are
2430 not listed unless -c (clean), -i (ignored) or -A is given.
2431 not listed unless -c (clean), -i (ignored) or -A is given.
2431
2432
2432 The codes used to show the status of files are:
2433 The codes used to show the status of files are:
2433 M = modified
2434 M = modified
2434 A = added
2435 A = added
2435 R = removed
2436 R = removed
2436 C = clean
2437 C = clean
2437 ! = deleted, but still tracked
2438 ! = deleted, but still tracked
2438 ? = not tracked
2439 ? = not tracked
2439 I = ignored (not shown by default)
2440 I = ignored (not shown by default)
2440 = the previous added file was copied from here
2441 = the previous added file was copied from here
2441 """
2442 """
2442
2443
2443 all = opts['all']
2444 all = opts['all']
2444
2445
2445 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2446 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2446 cwd = (pats and repo.getcwd()) or ''
2447 cwd = (pats and repo.getcwd()) or ''
2447 modified, added, removed, deleted, unknown, ignored, clean = [
2448 modified, added, removed, deleted, unknown, ignored, clean = [
2448 [util.pathto(cwd, x) for x in n]
2449 [util.pathto(cwd, x) for x in n]
2449 for n in repo.status(files=files, match=matchfn,
2450 for n in repo.status(files=files, match=matchfn,
2450 list_ignored=all or opts['ignored'],
2451 list_ignored=all or opts['ignored'],
2451 list_clean=all or opts['clean'])]
2452 list_clean=all or opts['clean'])]
2452
2453
2453 changetypes = (('modified', 'M', modified),
2454 changetypes = (('modified', 'M', modified),
2454 ('added', 'A', added),
2455 ('added', 'A', added),
2455 ('removed', 'R', removed),
2456 ('removed', 'R', removed),
2456 ('deleted', '!', deleted),
2457 ('deleted', '!', deleted),
2457 ('unknown', '?', unknown),
2458 ('unknown', '?', unknown),
2458 ('ignored', 'I', ignored))
2459 ('ignored', 'I', ignored))
2459
2460
2460 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2461 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2461
2462
2462 end = opts['print0'] and '\0' or '\n'
2463 end = opts['print0'] and '\0' or '\n'
2463
2464
2464 for opt, char, changes in ([ct for ct in explicit_changetypes
2465 for opt, char, changes in ([ct for ct in explicit_changetypes
2465 if all or opts[ct[0]]]
2466 if all or opts[ct[0]]]
2466 or changetypes):
2467 or changetypes):
2467 if opts['no_status']:
2468 if opts['no_status']:
2468 format = "%%s%s" % end
2469 format = "%%s%s" % end
2469 else:
2470 else:
2470 format = "%s %%s%s" % (char, end)
2471 format = "%s %%s%s" % (char, end)
2471
2472
2472 for f in changes:
2473 for f in changes:
2473 ui.write(format % f)
2474 ui.write(format % f)
2474 if ((all or opts.get('copies')) and not opts.get('no_status')
2475 if ((all or opts.get('copies')) and not opts.get('no_status')
2475 and opt == 'added'):
2476 and opt == 'added'):
2476 copied = repo.dirstate.copied(f)
2477 copied = repo.dirstate.copied(f)
2477 if copied:
2478 if copied:
2478 ui.write(' %s%s' % (copied, end))
2479 ui.write(' %s%s' % (copied, end))
2479
2480
2480 def tag(ui, repo, name, rev_=None, **opts):
2481 def tag(ui, repo, name, rev_=None, **opts):
2481 """add a tag for the current tip or a given revision
2482 """add a tag for the current tip or a given revision
2482
2483
2483 Name a particular revision using <name>.
2484 Name a particular revision using <name>.
2484
2485
2485 Tags are used to name particular revisions of the repository and are
2486 Tags are used to name particular revisions of the repository and are
2486 very useful to compare different revision, to go back to significant
2487 very useful to compare different revision, to go back to significant
2487 earlier versions or to mark branch points as releases, etc.
2488 earlier versions or to mark branch points as releases, etc.
2488
2489
2489 If no revision is given, the parent of the working directory is used.
2490 If no revision is given, the parent of the working directory is used.
2490
2491
2491 To facilitate version control, distribution, and merging of tags,
2492 To facilitate version control, distribution, and merging of tags,
2492 they are stored as a file named ".hgtags" which is managed
2493 they are stored as a file named ".hgtags" which is managed
2493 similarly to other project files and can be hand-edited if
2494 similarly to other project files and can be hand-edited if
2494 necessary. The file '.hg/localtags' is used for local tags (not
2495 necessary. The file '.hg/localtags' is used for local tags (not
2495 shared among repositories).
2496 shared among repositories).
2496 """
2497 """
2497 if name in ['tip', '.']:
2498 if name in ['tip', '.']:
2498 raise util.Abort(_("the name '%s' is reserved") % name)
2499 raise util.Abort(_("the name '%s' is reserved") % name)
2499 if rev_ is not None:
2500 if rev_ is not None:
2500 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2501 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2501 "please use 'hg tag [-r REV] NAME' instead\n"))
2502 "please use 'hg tag [-r REV] NAME' instead\n"))
2502 if opts['rev']:
2503 if opts['rev']:
2503 raise util.Abort(_("use only one form to specify the revision"))
2504 raise util.Abort(_("use only one form to specify the revision"))
2504 if opts['rev']:
2505 if opts['rev']:
2505 rev_ = opts['rev']
2506 rev_ = opts['rev']
2506 if not rev_ and repo.dirstate.parents()[1] != nullid:
2507 if not rev_ and repo.dirstate.parents()[1] != nullid:
2507 raise util.Abort(_('uncommitted merge - please provide a '
2508 raise util.Abort(_('uncommitted merge - please provide a '
2508 'specific revision'))
2509 'specific revision'))
2509 r = repo.changectx(rev_).node()
2510 r = repo.changectx(rev_).node()
2510
2511
2511 message = opts['message']
2512 message = opts['message']
2512 if not message:
2513 if not message:
2513 message = _('Added tag %s for changeset %s') % (name, short(r))
2514 message = _('Added tag %s for changeset %s') % (name, short(r))
2514
2515
2515 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2516 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2516
2517
2517 def tags(ui, repo):
2518 def tags(ui, repo):
2518 """list repository tags
2519 """list repository tags
2519
2520
2520 List the repository tags.
2521 List the repository tags.
2521
2522
2522 This lists both regular and local tags.
2523 This lists both regular and local tags.
2523 """
2524 """
2524
2525
2525 l = repo.tagslist()
2526 l = repo.tagslist()
2526 l.reverse()
2527 l.reverse()
2527 hexfunc = ui.debugflag and hex or short
2528 hexfunc = ui.debugflag and hex or short
2528 for t, n in l:
2529 for t, n in l:
2529 try:
2530 try:
2530 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2531 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2531 except KeyError:
2532 except KeyError:
2532 r = " ?:?"
2533 r = " ?:?"
2533 if ui.quiet:
2534 if ui.quiet:
2534 ui.write("%s\n" % t)
2535 ui.write("%s\n" % t)
2535 else:
2536 else:
2536 ui.write("%-30s %s\n" % (t, r))
2537 ui.write("%-30s %s\n" % (t, r))
2537
2538
2538 def tip(ui, repo, **opts):
2539 def tip(ui, repo, **opts):
2539 """show the tip revision
2540 """show the tip revision
2540
2541
2541 Show the tip revision.
2542 Show the tip revision.
2542 """
2543 """
2543 n = repo.changelog.tip()
2544 n = repo.changelog.tip()
2544 br = None
2545 br = None
2545 if opts['branches']:
2546 if opts['branches']:
2546 br = repo.branchlookup([n])
2547 br = repo.branchlookup([n])
2547 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2548 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2548 if opts['patch']:
2549 if opts['patch']:
2549 patch.diff(repo, repo.changelog.parents(n)[0], n)
2550 patch.diff(repo, repo.changelog.parents(n)[0], n)
2550
2551
2551 def unbundle(ui, repo, fname, **opts):
2552 def unbundle(ui, repo, fname, **opts):
2552 """apply a changegroup file
2553 """apply a changegroup file
2553
2554
2554 Apply a compressed changegroup file generated by the bundle
2555 Apply a compressed changegroup file generated by the bundle
2555 command.
2556 command.
2556 """
2557 """
2557 f = urllib.urlopen(fname)
2558 f = urllib.urlopen(fname)
2558
2559
2559 header = f.read(6)
2560 header = f.read(6)
2560 if not header.startswith("HG"):
2561 if not header.startswith("HG"):
2561 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2562 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2562 elif not header.startswith("HG10"):
2563 elif not header.startswith("HG10"):
2563 raise util.Abort(_("%s: unknown bundle version") % fname)
2564 raise util.Abort(_("%s: unknown bundle version") % fname)
2564 elif header == "HG10BZ":
2565 elif header == "HG10BZ":
2565 def generator(f):
2566 def generator(f):
2566 zd = bz2.BZ2Decompressor()
2567 zd = bz2.BZ2Decompressor()
2567 zd.decompress("BZ")
2568 zd.decompress("BZ")
2568 for chunk in f:
2569 for chunk in f:
2569 yield zd.decompress(chunk)
2570 yield zd.decompress(chunk)
2570 elif header == "HG10UN":
2571 elif header == "HG10UN":
2571 def generator(f):
2572 def generator(f):
2572 for chunk in f:
2573 for chunk in f:
2573 yield chunk
2574 yield chunk
2574 else:
2575 else:
2575 raise util.Abort(_("%s: unknown bundle compression type")
2576 raise util.Abort(_("%s: unknown bundle compression type")
2576 % fname)
2577 % fname)
2577 gen = generator(util.filechunkiter(f, 4096))
2578 gen = generator(util.filechunkiter(f, 4096))
2578 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2579 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2579 'bundle:' + fname)
2580 'bundle:' + fname)
2580 return postincoming(ui, repo, modheads, opts['update'])
2581 return postincoming(ui, repo, modheads, opts['update'])
2581
2582
2582 def undo(ui, repo):
2583 def undo(ui, repo):
2583 """undo the last commit or pull (DEPRECATED)
2584 """undo the last commit or pull (DEPRECATED)
2584
2585
2585 (DEPRECATED)
2586 (DEPRECATED)
2586 This command is now deprecated and will be removed in a future
2587 This command is now deprecated and will be removed in a future
2587 release. Please use the rollback command instead. For usage
2588 release. Please use the rollback command instead. For usage
2588 instructions, see the rollback command.
2589 instructions, see the rollback command.
2589 """
2590 """
2590 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2591 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2591 repo.rollback()
2592 repo.rollback()
2592
2593
2593 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2594 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2594 branch=None):
2595 branch=None):
2595 """update or merge working directory
2596 """update or merge working directory
2596
2597
2597 Update the working directory to the specified revision.
2598 Update the working directory to the specified revision.
2598
2599
2599 If there are no outstanding changes in the working directory and
2600 If there are no outstanding changes in the working directory and
2600 there is a linear relationship between the current version and the
2601 there is a linear relationship between the current version and the
2601 requested version, the result is the requested version.
2602 requested version, the result is the requested version.
2602
2603
2603 To merge the working directory with another revision, use the
2604 To merge the working directory with another revision, use the
2604 merge command.
2605 merge command.
2605
2606
2606 By default, update will refuse to run if doing so would require
2607 By default, update will refuse to run if doing so would require
2607 merging or discarding local changes.
2608 merging or discarding local changes.
2608 """
2609 """
2609 node = _lookup(repo, node, branch)
2610 node = _lookup(repo, node, branch)
2610 if merge:
2611 if merge:
2611 ui.warn(_('(the -m/--merge option is deprecated; '
2612 ui.warn(_('(the -m/--merge option is deprecated; '
2612 'use the merge command instead)\n'))
2613 'use the merge command instead)\n'))
2613 return hg.merge(repo, node, force=force)
2614 return hg.merge(repo, node, force=force)
2614 elif clean:
2615 elif clean:
2615 return hg.clean(repo, node)
2616 return hg.clean(repo, node)
2616 else:
2617 else:
2617 return hg.update(repo, node)
2618 return hg.update(repo, node)
2618
2619
2619 def _lookup(repo, node, branch=None):
2620 def _lookup(repo, node, branch=None):
2620 if branch:
2621 if branch:
2621 br = repo.branchlookup(branch=branch)
2622 br = repo.branchlookup(branch=branch)
2622 found = []
2623 found = []
2623 for x in br:
2624 for x in br:
2624 if branch in br[x]:
2625 if branch in br[x]:
2625 found.append(x)
2626 found.append(x)
2626 if len(found) > 1:
2627 if len(found) > 1:
2627 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2628 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2628 for x in found:
2629 for x in found:
2629 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
2630 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
2630 raise util.Abort("")
2631 raise util.Abort("")
2631 if len(found) == 1:
2632 if len(found) == 1:
2632 node = found[0]
2633 node = found[0]
2633 repo.ui.warn(_("Using head %s for branch %s\n")
2634 repo.ui.warn(_("Using head %s for branch %s\n")
2634 % (short(node), branch))
2635 % (short(node), branch))
2635 else:
2636 else:
2636 raise util.Abort(_("branch %s not found") % branch)
2637 raise util.Abort(_("branch %s not found") % branch)
2637 else:
2638 else:
2638 node = node and repo.lookup(node) or repo.changelog.tip()
2639 node = node and repo.lookup(node) or repo.changelog.tip()
2639 return node
2640 return node
2640
2641
2641 def verify(ui, repo):
2642 def verify(ui, repo):
2642 """verify the integrity of the repository
2643 """verify the integrity of the repository
2643
2644
2644 Verify the integrity of the current repository.
2645 Verify the integrity of the current repository.
2645
2646
2646 This will perform an extensive check of the repository's
2647 This will perform an extensive check of the repository's
2647 integrity, validating the hashes and checksums of each entry in
2648 integrity, validating the hashes and checksums of each entry in
2648 the changelog, manifest, and tracked files, as well as the
2649 the changelog, manifest, and tracked files, as well as the
2649 integrity of their crosslinks and indices.
2650 integrity of their crosslinks and indices.
2650 """
2651 """
2651 return hg.verify(repo)
2652 return hg.verify(repo)
2652
2653
2653 # Command options and aliases are listed here, alphabetically
2654 # Command options and aliases are listed here, alphabetically
2654
2655
2655 table = {
2656 table = {
2656 "^add":
2657 "^add":
2657 (add,
2658 (add,
2658 [('I', 'include', [], _('include names matching the given patterns')),
2659 [('I', 'include', [], _('include names matching the given patterns')),
2659 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2660 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2660 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2661 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2661 _('hg add [OPTION]... [FILE]...')),
2662 _('hg add [OPTION]... [FILE]...')),
2662 "addremove":
2663 "addremove":
2663 (addremove,
2664 (addremove,
2664 [('I', 'include', [], _('include names matching the given patterns')),
2665 [('I', 'include', [], _('include names matching the given patterns')),
2665 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2666 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2666 ('n', 'dry-run', None,
2667 ('n', 'dry-run', None,
2667 _('do not perform actions, just print output')),
2668 _('do not perform actions, just print output')),
2668 ('s', 'similarity', '',
2669 ('s', 'similarity', '',
2669 _('guess renamed files by similarity (0<=s<=1)'))],
2670 _('guess renamed files by similarity (0<=s<=1)'))],
2670 _('hg addremove [OPTION]... [FILE]...')),
2671 _('hg addremove [OPTION]... [FILE]...')),
2671 "^annotate":
2672 "^annotate":
2672 (annotate,
2673 (annotate,
2673 [('r', 'rev', '', _('annotate the specified revision')),
2674 [('r', 'rev', '', _('annotate the specified revision')),
2675 ('f', 'follow', None, _('follow file copies and renames')),
2674 ('a', 'text', None, _('treat all files as text')),
2676 ('a', 'text', None, _('treat all files as text')),
2675 ('u', 'user', None, _('list the author')),
2677 ('u', 'user', None, _('list the author')),
2676 ('d', 'date', None, _('list the date')),
2678 ('d', 'date', None, _('list the date')),
2677 ('n', 'number', None, _('list the revision number (default)')),
2679 ('n', 'number', None, _('list the revision number (default)')),
2678 ('c', 'changeset', None, _('list the changeset')),
2680 ('c', 'changeset', None, _('list the changeset')),
2679 ('I', 'include', [], _('include names matching the given patterns')),
2681 ('I', 'include', [], _('include names matching the given patterns')),
2680 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2682 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2681 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2683 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2682 "archive":
2684 "archive":
2683 (archive,
2685 (archive,
2684 [('', 'no-decode', None, _('do not pass files through decoders')),
2686 [('', 'no-decode', None, _('do not pass files through decoders')),
2685 ('p', 'prefix', '', _('directory prefix for files in archive')),
2687 ('p', 'prefix', '', _('directory prefix for files in archive')),
2686 ('r', 'rev', '', _('revision to distribute')),
2688 ('r', 'rev', '', _('revision to distribute')),
2687 ('t', 'type', '', _('type of distribution to create')),
2689 ('t', 'type', '', _('type of distribution to create')),
2688 ('I', 'include', [], _('include names matching the given patterns')),
2690 ('I', 'include', [], _('include names matching the given patterns')),
2689 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2691 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2690 _('hg archive [OPTION]... DEST')),
2692 _('hg archive [OPTION]... DEST')),
2691 "backout":
2693 "backout":
2692 (backout,
2694 (backout,
2693 [('', 'merge', None,
2695 [('', 'merge', None,
2694 _('merge with old dirstate parent after backout')),
2696 _('merge with old dirstate parent after backout')),
2695 ('m', 'message', '', _('use <text> as commit message')),
2697 ('m', 'message', '', _('use <text> as commit message')),
2696 ('l', 'logfile', '', _('read commit message from <file>')),
2698 ('l', 'logfile', '', _('read commit message from <file>')),
2697 ('d', 'date', '', _('record datecode as commit date')),
2699 ('d', 'date', '', _('record datecode as commit date')),
2698 ('', 'parent', '', _('parent to choose when backing out merge')),
2700 ('', 'parent', '', _('parent to choose when backing out merge')),
2699 ('u', 'user', '', _('record user as committer')),
2701 ('u', 'user', '', _('record user as committer')),
2700 ('I', 'include', [], _('include names matching the given patterns')),
2702 ('I', 'include', [], _('include names matching the given patterns')),
2701 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2703 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2702 _('hg backout [OPTION]... REV')),
2704 _('hg backout [OPTION]... REV')),
2703 "bundle":
2705 "bundle":
2704 (bundle,
2706 (bundle,
2705 [('f', 'force', None,
2707 [('f', 'force', None,
2706 _('run even when remote repository is unrelated'))],
2708 _('run even when remote repository is unrelated'))],
2707 _('hg bundle FILE DEST')),
2709 _('hg bundle FILE DEST')),
2708 "cat":
2710 "cat":
2709 (cat,
2711 (cat,
2710 [('o', 'output', '', _('print output to file with formatted name')),
2712 [('o', 'output', '', _('print output to file with formatted name')),
2711 ('r', 'rev', '', _('print the given revision')),
2713 ('r', 'rev', '', _('print the given revision')),
2712 ('I', 'include', [], _('include names matching the given patterns')),
2714 ('I', 'include', [], _('include names matching the given patterns')),
2713 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2715 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2714 _('hg cat [OPTION]... FILE...')),
2716 _('hg cat [OPTION]... FILE...')),
2715 "^clone":
2717 "^clone":
2716 (clone,
2718 (clone,
2717 [('U', 'noupdate', None, _('do not update the new working directory')),
2719 [('U', 'noupdate', None, _('do not update the new working directory')),
2718 ('r', 'rev', [],
2720 ('r', 'rev', [],
2719 _('a changeset you would like to have after cloning')),
2721 _('a changeset you would like to have after cloning')),
2720 ('', 'pull', None, _('use pull protocol to copy metadata')),
2722 ('', 'pull', None, _('use pull protocol to copy metadata')),
2721 ('', 'uncompressed', None,
2723 ('', 'uncompressed', None,
2722 _('use uncompressed transfer (fast over LAN)')),
2724 _('use uncompressed transfer (fast over LAN)')),
2723 ('e', 'ssh', '', _('specify ssh command to use')),
2725 ('e', 'ssh', '', _('specify ssh command to use')),
2724 ('', 'remotecmd', '',
2726 ('', 'remotecmd', '',
2725 _('specify hg command to run on the remote side'))],
2727 _('specify hg command to run on the remote side'))],
2726 _('hg clone [OPTION]... SOURCE [DEST]')),
2728 _('hg clone [OPTION]... SOURCE [DEST]')),
2727 "^commit|ci":
2729 "^commit|ci":
2728 (commit,
2730 (commit,
2729 [('A', 'addremove', None,
2731 [('A', 'addremove', None,
2730 _('mark new/missing files as added/removed before committing')),
2732 _('mark new/missing files as added/removed before committing')),
2731 ('m', 'message', '', _('use <text> as commit message')),
2733 ('m', 'message', '', _('use <text> as commit message')),
2732 ('l', 'logfile', '', _('read the commit message from <file>')),
2734 ('l', 'logfile', '', _('read the commit message from <file>')),
2733 ('d', 'date', '', _('record datecode as commit date')),
2735 ('d', 'date', '', _('record datecode as commit date')),
2734 ('u', 'user', '', _('record user as commiter')),
2736 ('u', 'user', '', _('record user as commiter')),
2735 ('I', 'include', [], _('include names matching the given patterns')),
2737 ('I', 'include', [], _('include names matching the given patterns')),
2736 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2738 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2737 _('hg commit [OPTION]... [FILE]...')),
2739 _('hg commit [OPTION]... [FILE]...')),
2738 "copy|cp":
2740 "copy|cp":
2739 (copy,
2741 (copy,
2740 [('A', 'after', None, _('record a copy that has already occurred')),
2742 [('A', 'after', None, _('record a copy that has already occurred')),
2741 ('f', 'force', None,
2743 ('f', 'force', None,
2742 _('forcibly copy over an existing managed file')),
2744 _('forcibly copy over an existing managed file')),
2743 ('I', 'include', [], _('include names matching the given patterns')),
2745 ('I', 'include', [], _('include names matching the given patterns')),
2744 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2746 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2745 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2747 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2746 _('hg copy [OPTION]... [SOURCE]... DEST')),
2748 _('hg copy [OPTION]... [SOURCE]... DEST')),
2747 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2749 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2748 "debugcomplete":
2750 "debugcomplete":
2749 (debugcomplete,
2751 (debugcomplete,
2750 [('o', 'options', None, _('show the command options'))],
2752 [('o', 'options', None, _('show the command options'))],
2751 _('debugcomplete [-o] CMD')),
2753 _('debugcomplete [-o] CMD')),
2752 "debugrebuildstate":
2754 "debugrebuildstate":
2753 (debugrebuildstate,
2755 (debugrebuildstate,
2754 [('r', 'rev', '', _('revision to rebuild to'))],
2756 [('r', 'rev', '', _('revision to rebuild to'))],
2755 _('debugrebuildstate [-r REV] [REV]')),
2757 _('debugrebuildstate [-r REV] [REV]')),
2756 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2758 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2757 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2759 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2758 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2760 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2759 "debugstate": (debugstate, [], _('debugstate')),
2761 "debugstate": (debugstate, [], _('debugstate')),
2760 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2762 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2761 "debugindex": (debugindex, [], _('debugindex FILE')),
2763 "debugindex": (debugindex, [], _('debugindex FILE')),
2762 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2764 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2763 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2765 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2764 "debugwalk":
2766 "debugwalk":
2765 (debugwalk,
2767 (debugwalk,
2766 [('I', 'include', [], _('include names matching the given patterns')),
2768 [('I', 'include', [], _('include names matching the given patterns')),
2767 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2769 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2768 _('debugwalk [OPTION]... [FILE]...')),
2770 _('debugwalk [OPTION]... [FILE]...')),
2769 "^diff":
2771 "^diff":
2770 (diff,
2772 (diff,
2771 [('r', 'rev', [], _('revision')),
2773 [('r', 'rev', [], _('revision')),
2772 ('a', 'text', None, _('treat all files as text')),
2774 ('a', 'text', None, _('treat all files as text')),
2773 ('p', 'show-function', None,
2775 ('p', 'show-function', None,
2774 _('show which function each change is in')),
2776 _('show which function each change is in')),
2775 ('g', 'git', None, _('use git extended diff format')),
2777 ('g', 'git', None, _('use git extended diff format')),
2776 ('w', 'ignore-all-space', None,
2778 ('w', 'ignore-all-space', None,
2777 _('ignore white space when comparing lines')),
2779 _('ignore white space when comparing lines')),
2778 ('b', 'ignore-space-change', None,
2780 ('b', 'ignore-space-change', None,
2779 _('ignore changes in the amount of white space')),
2781 _('ignore changes in the amount of white space')),
2780 ('B', 'ignore-blank-lines', None,
2782 ('B', 'ignore-blank-lines', None,
2781 _('ignore changes whose lines are all blank')),
2783 _('ignore changes whose lines are all blank')),
2782 ('I', 'include', [], _('include names matching the given patterns')),
2784 ('I', 'include', [], _('include names matching the given patterns')),
2783 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2785 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2784 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2786 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2785 "^export":
2787 "^export":
2786 (export,
2788 (export,
2787 [('o', 'output', '', _('print output to file with formatted name')),
2789 [('o', 'output', '', _('print output to file with formatted name')),
2788 ('a', 'text', None, _('treat all files as text')),
2790 ('a', 'text', None, _('treat all files as text')),
2789 ('g', 'git', None, _('use git extended diff format')),
2791 ('g', 'git', None, _('use git extended diff format')),
2790 ('', 'switch-parent', None, _('diff against the second parent'))],
2792 ('', 'switch-parent', None, _('diff against the second parent'))],
2791 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2793 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2792 "debugforget|forget":
2794 "debugforget|forget":
2793 (forget,
2795 (forget,
2794 [('I', 'include', [], _('include names matching the given patterns')),
2796 [('I', 'include', [], _('include names matching the given patterns')),
2795 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2797 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2796 _('hg forget [OPTION]... FILE...')),
2798 _('hg forget [OPTION]... FILE...')),
2797 "grep":
2799 "grep":
2798 (grep,
2800 (grep,
2799 [('0', 'print0', None, _('end fields with NUL')),
2801 [('0', 'print0', None, _('end fields with NUL')),
2800 ('', 'all', None, _('print all revisions that match')),
2802 ('', 'all', None, _('print all revisions that match')),
2801 ('f', 'follow', None,
2803 ('f', 'follow', None,
2802 _('follow changeset history, or file history across copies and renames')),
2804 _('follow changeset history, or file history across copies and renames')),
2803 ('i', 'ignore-case', None, _('ignore case when matching')),
2805 ('i', 'ignore-case', None, _('ignore case when matching')),
2804 ('l', 'files-with-matches', None,
2806 ('l', 'files-with-matches', None,
2805 _('print only filenames and revs that match')),
2807 _('print only filenames and revs that match')),
2806 ('n', 'line-number', None, _('print matching line numbers')),
2808 ('n', 'line-number', None, _('print matching line numbers')),
2807 ('r', 'rev', [], _('search in given revision range')),
2809 ('r', 'rev', [], _('search in given revision range')),
2808 ('u', 'user', None, _('print user who committed change')),
2810 ('u', 'user', None, _('print user who committed change')),
2809 ('I', 'include', [], _('include names matching the given patterns')),
2811 ('I', 'include', [], _('include names matching the given patterns')),
2810 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2812 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2811 _('hg grep [OPTION]... PATTERN [FILE]...')),
2813 _('hg grep [OPTION]... PATTERN [FILE]...')),
2812 "heads":
2814 "heads":
2813 (heads,
2815 (heads,
2814 [('b', 'branches', None, _('show branches')),
2816 [('b', 'branches', None, _('show branches')),
2815 ('', 'style', '', _('display using template map file')),
2817 ('', 'style', '', _('display using template map file')),
2816 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2818 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2817 ('', 'template', '', _('display with template'))],
2819 ('', 'template', '', _('display with template'))],
2818 _('hg heads [-b] [-r <rev>]')),
2820 _('hg heads [-b] [-r <rev>]')),
2819 "help": (help_, [], _('hg help [COMMAND]')),
2821 "help": (help_, [], _('hg help [COMMAND]')),
2820 "identify|id": (identify, [], _('hg identify')),
2822 "identify|id": (identify, [], _('hg identify')),
2821 "import|patch":
2823 "import|patch":
2822 (import_,
2824 (import_,
2823 [('p', 'strip', 1,
2825 [('p', 'strip', 1,
2824 _('directory strip option for patch. This has the same\n'
2826 _('directory strip option for patch. This has the same\n'
2825 'meaning as the corresponding patch option')),
2827 'meaning as the corresponding patch option')),
2826 ('m', 'message', '', _('use <text> as commit message')),
2828 ('m', 'message', '', _('use <text> as commit message')),
2827 ('b', 'base', '', _('base path')),
2829 ('b', 'base', '', _('base path')),
2828 ('f', 'force', None,
2830 ('f', 'force', None,
2829 _('skip check for outstanding uncommitted changes'))],
2831 _('skip check for outstanding uncommitted changes'))],
2830 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
2832 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
2831 "incoming|in": (incoming,
2833 "incoming|in": (incoming,
2832 [('M', 'no-merges', None, _('do not show merges')),
2834 [('M', 'no-merges', None, _('do not show merges')),
2833 ('f', 'force', None,
2835 ('f', 'force', None,
2834 _('run even when remote repository is unrelated')),
2836 _('run even when remote repository is unrelated')),
2835 ('', 'style', '', _('display using template map file')),
2837 ('', 'style', '', _('display using template map file')),
2836 ('n', 'newest-first', None, _('show newest record first')),
2838 ('n', 'newest-first', None, _('show newest record first')),
2837 ('', 'bundle', '', _('file to store the bundles into')),
2839 ('', 'bundle', '', _('file to store the bundles into')),
2838 ('p', 'patch', None, _('show patch')),
2840 ('p', 'patch', None, _('show patch')),
2839 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2841 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2840 ('', 'template', '', _('display with template')),
2842 ('', 'template', '', _('display with template')),
2841 ('e', 'ssh', '', _('specify ssh command to use')),
2843 ('e', 'ssh', '', _('specify ssh command to use')),
2842 ('', 'remotecmd', '',
2844 ('', 'remotecmd', '',
2843 _('specify hg command to run on the remote side'))],
2845 _('specify hg command to run on the remote side'))],
2844 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2846 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2845 ' [--bundle FILENAME] [SOURCE]')),
2847 ' [--bundle FILENAME] [SOURCE]')),
2846 "^init":
2848 "^init":
2847 (init,
2849 (init,
2848 [('e', 'ssh', '', _('specify ssh command to use')),
2850 [('e', 'ssh', '', _('specify ssh command to use')),
2849 ('', 'remotecmd', '',
2851 ('', 'remotecmd', '',
2850 _('specify hg command to run on the remote side'))],
2852 _('specify hg command to run on the remote side'))],
2851 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2853 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2852 "locate":
2854 "locate":
2853 (locate,
2855 (locate,
2854 [('r', 'rev', '', _('search the repository as it stood at rev')),
2856 [('r', 'rev', '', _('search the repository as it stood at rev')),
2855 ('0', 'print0', None,
2857 ('0', 'print0', None,
2856 _('end filenames with NUL, for use with xargs')),
2858 _('end filenames with NUL, for use with xargs')),
2857 ('f', 'fullpath', None,
2859 ('f', 'fullpath', None,
2858 _('print complete paths from the filesystem root')),
2860 _('print complete paths from the filesystem root')),
2859 ('I', 'include', [], _('include names matching the given patterns')),
2861 ('I', 'include', [], _('include names matching the given patterns')),
2860 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2862 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2861 _('hg locate [OPTION]... [PATTERN]...')),
2863 _('hg locate [OPTION]... [PATTERN]...')),
2862 "^log|history":
2864 "^log|history":
2863 (log,
2865 (log,
2864 [('b', 'branches', None, _('show branches')),
2866 [('b', 'branches', None, _('show branches')),
2865 ('f', 'follow', None,
2867 ('f', 'follow', None,
2866 _('follow changeset history, or file history across copies and renames')),
2868 _('follow changeset history, or file history across copies and renames')),
2867 ('', 'follow-first', None,
2869 ('', 'follow-first', None,
2868 _('only follow the first parent of merge changesets')),
2870 _('only follow the first parent of merge changesets')),
2869 ('k', 'keyword', [], _('search for a keyword')),
2871 ('k', 'keyword', [], _('search for a keyword')),
2870 ('l', 'limit', '', _('limit number of changes displayed')),
2872 ('l', 'limit', '', _('limit number of changes displayed')),
2871 ('r', 'rev', [], _('show the specified revision or range')),
2873 ('r', 'rev', [], _('show the specified revision or range')),
2872 ('M', 'no-merges', None, _('do not show merges')),
2874 ('M', 'no-merges', None, _('do not show merges')),
2873 ('', 'style', '', _('display using template map file')),
2875 ('', 'style', '', _('display using template map file')),
2874 ('m', 'only-merges', None, _('show only merges')),
2876 ('m', 'only-merges', None, _('show only merges')),
2875 ('p', 'patch', None, _('show patch')),
2877 ('p', 'patch', None, _('show patch')),
2876 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2878 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2877 ('', 'template', '', _('display with template')),
2879 ('', 'template', '', _('display with template')),
2878 ('I', 'include', [], _('include names matching the given patterns')),
2880 ('I', 'include', [], _('include names matching the given patterns')),
2879 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2881 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2880 _('hg log [OPTION]... [FILE]')),
2882 _('hg log [OPTION]... [FILE]')),
2881 "manifest": (manifest, [], _('hg manifest [REV]')),
2883 "manifest": (manifest, [], _('hg manifest [REV]')),
2882 "merge":
2884 "merge":
2883 (merge,
2885 (merge,
2884 [('b', 'branch', '', _('merge with head of a specific branch')),
2886 [('b', 'branch', '', _('merge with head of a specific branch')),
2885 ('f', 'force', None, _('force a merge with outstanding changes'))],
2887 ('f', 'force', None, _('force a merge with outstanding changes'))],
2886 _('hg merge [-b TAG] [-f] [REV]')),
2888 _('hg merge [-b TAG] [-f] [REV]')),
2887 "outgoing|out": (outgoing,
2889 "outgoing|out": (outgoing,
2888 [('M', 'no-merges', None, _('do not show merges')),
2890 [('M', 'no-merges', None, _('do not show merges')),
2889 ('f', 'force', None,
2891 ('f', 'force', None,
2890 _('run even when remote repository is unrelated')),
2892 _('run even when remote repository is unrelated')),
2891 ('p', 'patch', None, _('show patch')),
2893 ('p', 'patch', None, _('show patch')),
2892 ('', 'style', '', _('display using template map file')),
2894 ('', 'style', '', _('display using template map file')),
2893 ('r', 'rev', [], _('a specific revision you would like to push')),
2895 ('r', 'rev', [], _('a specific revision you would like to push')),
2894 ('n', 'newest-first', None, _('show newest record first')),
2896 ('n', 'newest-first', None, _('show newest record first')),
2895 ('', 'template', '', _('display with template')),
2897 ('', 'template', '', _('display with template')),
2896 ('e', 'ssh', '', _('specify ssh command to use')),
2898 ('e', 'ssh', '', _('specify ssh command to use')),
2897 ('', 'remotecmd', '',
2899 ('', 'remotecmd', '',
2898 _('specify hg command to run on the remote side'))],
2900 _('specify hg command to run on the remote side'))],
2899 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2901 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2900 "^parents":
2902 "^parents":
2901 (parents,
2903 (parents,
2902 [('b', 'branches', None, _('show branches')),
2904 [('b', 'branches', None, _('show branches')),
2903 ('r', 'rev', '', _('show parents from the specified rev')),
2905 ('r', 'rev', '', _('show parents from the specified rev')),
2904 ('', 'style', '', _('display using template map file')),
2906 ('', 'style', '', _('display using template map file')),
2905 ('', 'template', '', _('display with template'))],
2907 ('', 'template', '', _('display with template'))],
2906 _('hg parents [-b] [-r REV] [FILE]')),
2908 _('hg parents [-b] [-r REV] [FILE]')),
2907 "paths": (paths, [], _('hg paths [NAME]')),
2909 "paths": (paths, [], _('hg paths [NAME]')),
2908 "^pull":
2910 "^pull":
2909 (pull,
2911 (pull,
2910 [('u', 'update', None,
2912 [('u', 'update', None,
2911 _('update the working directory to tip after pull')),
2913 _('update the working directory to tip after pull')),
2912 ('e', 'ssh', '', _('specify ssh command to use')),
2914 ('e', 'ssh', '', _('specify ssh command to use')),
2913 ('f', 'force', None,
2915 ('f', 'force', None,
2914 _('run even when remote repository is unrelated')),
2916 _('run even when remote repository is unrelated')),
2915 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2917 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2916 ('', 'remotecmd', '',
2918 ('', 'remotecmd', '',
2917 _('specify hg command to run on the remote side'))],
2919 _('specify hg command to run on the remote side'))],
2918 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2920 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2919 "^push":
2921 "^push":
2920 (push,
2922 (push,
2921 [('f', 'force', None, _('force push')),
2923 [('f', 'force', None, _('force push')),
2922 ('e', 'ssh', '', _('specify ssh command to use')),
2924 ('e', 'ssh', '', _('specify ssh command to use')),
2923 ('r', 'rev', [], _('a specific revision you would like to push')),
2925 ('r', 'rev', [], _('a specific revision you would like to push')),
2924 ('', 'remotecmd', '',
2926 ('', 'remotecmd', '',
2925 _('specify hg command to run on the remote side'))],
2927 _('specify hg command to run on the remote side'))],
2926 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2928 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2927 "debugrawcommit|rawcommit":
2929 "debugrawcommit|rawcommit":
2928 (rawcommit,
2930 (rawcommit,
2929 [('p', 'parent', [], _('parent')),
2931 [('p', 'parent', [], _('parent')),
2930 ('d', 'date', '', _('date code')),
2932 ('d', 'date', '', _('date code')),
2931 ('u', 'user', '', _('user')),
2933 ('u', 'user', '', _('user')),
2932 ('F', 'files', '', _('file list')),
2934 ('F', 'files', '', _('file list')),
2933 ('m', 'message', '', _('commit message')),
2935 ('m', 'message', '', _('commit message')),
2934 ('l', 'logfile', '', _('commit message file'))],
2936 ('l', 'logfile', '', _('commit message file'))],
2935 _('hg debugrawcommit [OPTION]... [FILE]...')),
2937 _('hg debugrawcommit [OPTION]... [FILE]...')),
2936 "recover": (recover, [], _('hg recover')),
2938 "recover": (recover, [], _('hg recover')),
2937 "^remove|rm":
2939 "^remove|rm":
2938 (remove,
2940 (remove,
2939 [('A', 'after', None, _('record remove that has already occurred')),
2941 [('A', 'after', None, _('record remove that has already occurred')),
2940 ('f', 'force', None, _('remove file even if modified')),
2942 ('f', 'force', None, _('remove file even if modified')),
2941 ('I', 'include', [], _('include names matching the given patterns')),
2943 ('I', 'include', [], _('include names matching the given patterns')),
2942 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2944 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2943 _('hg remove [OPTION]... FILE...')),
2945 _('hg remove [OPTION]... FILE...')),
2944 "rename|mv":
2946 "rename|mv":
2945 (rename,
2947 (rename,
2946 [('A', 'after', None, _('record a rename that has already occurred')),
2948 [('A', 'after', None, _('record a rename that has already occurred')),
2947 ('f', 'force', None,
2949 ('f', 'force', None,
2948 _('forcibly copy over an existing managed file')),
2950 _('forcibly copy over an existing managed file')),
2949 ('I', 'include', [], _('include names matching the given patterns')),
2951 ('I', 'include', [], _('include names matching the given patterns')),
2950 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2952 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2951 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2953 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2952 _('hg rename [OPTION]... SOURCE... DEST')),
2954 _('hg rename [OPTION]... SOURCE... DEST')),
2953 "^revert":
2955 "^revert":
2954 (revert,
2956 (revert,
2955 [('a', 'all', None, _('revert all changes when no arguments given')),
2957 [('a', 'all', None, _('revert all changes when no arguments given')),
2956 ('r', 'rev', '', _('revision to revert to')),
2958 ('r', 'rev', '', _('revision to revert to')),
2957 ('', 'no-backup', None, _('do not save backup copies of files')),
2959 ('', 'no-backup', None, _('do not save backup copies of files')),
2958 ('I', 'include', [], _('include names matching given patterns')),
2960 ('I', 'include', [], _('include names matching given patterns')),
2959 ('X', 'exclude', [], _('exclude names matching given patterns')),
2961 ('X', 'exclude', [], _('exclude names matching given patterns')),
2960 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2962 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2961 _('hg revert [-r REV] [NAME]...')),
2963 _('hg revert [-r REV] [NAME]...')),
2962 "rollback": (rollback, [], _('hg rollback')),
2964 "rollback": (rollback, [], _('hg rollback')),
2963 "root": (root, [], _('hg root')),
2965 "root": (root, [], _('hg root')),
2964 "^serve":
2966 "^serve":
2965 (serve,
2967 (serve,
2966 [('A', 'accesslog', '', _('name of access log file to write to')),
2968 [('A', 'accesslog', '', _('name of access log file to write to')),
2967 ('d', 'daemon', None, _('run server in background')),
2969 ('d', 'daemon', None, _('run server in background')),
2968 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2970 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2969 ('E', 'errorlog', '', _('name of error log file to write to')),
2971 ('E', 'errorlog', '', _('name of error log file to write to')),
2970 ('p', 'port', 0, _('port to use (default: 8000)')),
2972 ('p', 'port', 0, _('port to use (default: 8000)')),
2971 ('a', 'address', '', _('address to use')),
2973 ('a', 'address', '', _('address to use')),
2972 ('n', 'name', '',
2974 ('n', 'name', '',
2973 _('name to show in web pages (default: working dir)')),
2975 _('name to show in web pages (default: working dir)')),
2974 ('', 'webdir-conf', '', _('name of the webdir config file'
2976 ('', 'webdir-conf', '', _('name of the webdir config file'
2975 ' (serve more than one repo)')),
2977 ' (serve more than one repo)')),
2976 ('', 'pid-file', '', _('name of file to write process ID to')),
2978 ('', 'pid-file', '', _('name of file to write process ID to')),
2977 ('', 'stdio', None, _('for remote clients')),
2979 ('', 'stdio', None, _('for remote clients')),
2978 ('t', 'templates', '', _('web templates to use')),
2980 ('t', 'templates', '', _('web templates to use')),
2979 ('', 'style', '', _('template style to use')),
2981 ('', 'style', '', _('template style to use')),
2980 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2982 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2981 _('hg serve [OPTION]...')),
2983 _('hg serve [OPTION]...')),
2982 "^status|st":
2984 "^status|st":
2983 (status,
2985 (status,
2984 [('A', 'all', None, _('show status of all files')),
2986 [('A', 'all', None, _('show status of all files')),
2985 ('m', 'modified', None, _('show only modified files')),
2987 ('m', 'modified', None, _('show only modified files')),
2986 ('a', 'added', None, _('show only added files')),
2988 ('a', 'added', None, _('show only added files')),
2987 ('r', 'removed', None, _('show only removed files')),
2989 ('r', 'removed', None, _('show only removed files')),
2988 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2990 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2989 ('c', 'clean', None, _('show only files without changes')),
2991 ('c', 'clean', None, _('show only files without changes')),
2990 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2992 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2991 ('i', 'ignored', None, _('show ignored files')),
2993 ('i', 'ignored', None, _('show ignored files')),
2992 ('n', 'no-status', None, _('hide status prefix')),
2994 ('n', 'no-status', None, _('hide status prefix')),
2993 ('C', 'copies', None, _('show source of copied files')),
2995 ('C', 'copies', None, _('show source of copied files')),
2994 ('0', 'print0', None,
2996 ('0', 'print0', None,
2995 _('end filenames with NUL, for use with xargs')),
2997 _('end filenames with NUL, for use with xargs')),
2996 ('I', 'include', [], _('include names matching the given patterns')),
2998 ('I', 'include', [], _('include names matching the given patterns')),
2997 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2999 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2998 _('hg status [OPTION]... [FILE]...')),
3000 _('hg status [OPTION]... [FILE]...')),
2999 "tag":
3001 "tag":
3000 (tag,
3002 (tag,
3001 [('l', 'local', None, _('make the tag local')),
3003 [('l', 'local', None, _('make the tag local')),
3002 ('m', 'message', '', _('message for tag commit log entry')),
3004 ('m', 'message', '', _('message for tag commit log entry')),
3003 ('d', 'date', '', _('record datecode as commit date')),
3005 ('d', 'date', '', _('record datecode as commit date')),
3004 ('u', 'user', '', _('record user as commiter')),
3006 ('u', 'user', '', _('record user as commiter')),
3005 ('r', 'rev', '', _('revision to tag'))],
3007 ('r', 'rev', '', _('revision to tag'))],
3006 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3008 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3007 "tags": (tags, [], _('hg tags')),
3009 "tags": (tags, [], _('hg tags')),
3008 "tip":
3010 "tip":
3009 (tip,
3011 (tip,
3010 [('b', 'branches', None, _('show branches')),
3012 [('b', 'branches', None, _('show branches')),
3011 ('', 'style', '', _('display using template map file')),
3013 ('', 'style', '', _('display using template map file')),
3012 ('p', 'patch', None, _('show patch')),
3014 ('p', 'patch', None, _('show patch')),
3013 ('', 'template', '', _('display with template'))],
3015 ('', 'template', '', _('display with template'))],
3014 _('hg tip [-b] [-p]')),
3016 _('hg tip [-b] [-p]')),
3015 "unbundle":
3017 "unbundle":
3016 (unbundle,
3018 (unbundle,
3017 [('u', 'update', None,
3019 [('u', 'update', None,
3018 _('update the working directory to tip after unbundle'))],
3020 _('update the working directory to tip after unbundle'))],
3019 _('hg unbundle [-u] FILE')),
3021 _('hg unbundle [-u] FILE')),
3020 "debugundo|undo": (undo, [], _('hg undo')),
3022 "debugundo|undo": (undo, [], _('hg undo')),
3021 "^update|up|checkout|co":
3023 "^update|up|checkout|co":
3022 (update,
3024 (update,
3023 [('b', 'branch', '', _('checkout the head of a specific branch')),
3025 [('b', 'branch', '', _('checkout the head of a specific branch')),
3024 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3026 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3025 ('C', 'clean', None, _('overwrite locally modified files')),
3027 ('C', 'clean', None, _('overwrite locally modified files')),
3026 ('f', 'force', None, _('force a merge with outstanding changes'))],
3028 ('f', 'force', None, _('force a merge with outstanding changes'))],
3027 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3029 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3028 "verify": (verify, [], _('hg verify')),
3030 "verify": (verify, [], _('hg verify')),
3029 "version": (show_version, [], _('hg version')),
3031 "version": (show_version, [], _('hg version')),
3030 }
3032 }
3031
3033
3032 globalopts = [
3034 globalopts = [
3033 ('R', 'repository', '',
3035 ('R', 'repository', '',
3034 _('repository root directory or symbolic path name')),
3036 _('repository root directory or symbolic path name')),
3035 ('', 'cwd', '', _('change working directory')),
3037 ('', 'cwd', '', _('change working directory')),
3036 ('y', 'noninteractive', None,
3038 ('y', 'noninteractive', None,
3037 _('do not prompt, assume \'yes\' for any required answers')),
3039 _('do not prompt, assume \'yes\' for any required answers')),
3038 ('q', 'quiet', None, _('suppress output')),
3040 ('q', 'quiet', None, _('suppress output')),
3039 ('v', 'verbose', None, _('enable additional output')),
3041 ('v', 'verbose', None, _('enable additional output')),
3040 ('', 'config', [], _('set/override config option')),
3042 ('', 'config', [], _('set/override config option')),
3041 ('', 'debug', None, _('enable debugging output')),
3043 ('', 'debug', None, _('enable debugging output')),
3042 ('', 'debugger', None, _('start debugger')),
3044 ('', 'debugger', None, _('start debugger')),
3043 ('', 'lsprof', None, _('print improved command execution profile')),
3045 ('', 'lsprof', None, _('print improved command execution profile')),
3044 ('', 'traceback', None, _('print traceback on exception')),
3046 ('', 'traceback', None, _('print traceback on exception')),
3045 ('', 'time', None, _('time how long the command takes')),
3047 ('', 'time', None, _('time how long the command takes')),
3046 ('', 'profile', None, _('print command execution profile')),
3048 ('', 'profile', None, _('print command execution profile')),
3047 ('', 'version', None, _('output version information and exit')),
3049 ('', 'version', None, _('output version information and exit')),
3048 ('h', 'help', None, _('display help and exit')),
3050 ('h', 'help', None, _('display help and exit')),
3049 ]
3051 ]
3050
3052
3051 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3053 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3052 " debugindex debugindexdot")
3054 " debugindex debugindexdot")
3053 optionalrepo = ("paths serve debugconfig")
3055 optionalrepo = ("paths serve debugconfig")
3054
3056
3055 def findpossible(ui, cmd):
3057 def findpossible(ui, cmd):
3056 """
3058 """
3057 Return cmd -> (aliases, command table entry)
3059 Return cmd -> (aliases, command table entry)
3058 for each matching command.
3060 for each matching command.
3059 Return debug commands (or their aliases) only if no normal command matches.
3061 Return debug commands (or their aliases) only if no normal command matches.
3060 """
3062 """
3061 choice = {}
3063 choice = {}
3062 debugchoice = {}
3064 debugchoice = {}
3063 for e in table.keys():
3065 for e in table.keys():
3064 aliases = e.lstrip("^").split("|")
3066 aliases = e.lstrip("^").split("|")
3065 found = None
3067 found = None
3066 if cmd in aliases:
3068 if cmd in aliases:
3067 found = cmd
3069 found = cmd
3068 elif not ui.config("ui", "strict"):
3070 elif not ui.config("ui", "strict"):
3069 for a in aliases:
3071 for a in aliases:
3070 if a.startswith(cmd):
3072 if a.startswith(cmd):
3071 found = a
3073 found = a
3072 break
3074 break
3073 if found is not None:
3075 if found is not None:
3074 if aliases[0].startswith("debug"):
3076 if aliases[0].startswith("debug"):
3075 debugchoice[found] = (aliases, table[e])
3077 debugchoice[found] = (aliases, table[e])
3076 else:
3078 else:
3077 choice[found] = (aliases, table[e])
3079 choice[found] = (aliases, table[e])
3078
3080
3079 if not choice and debugchoice:
3081 if not choice and debugchoice:
3080 choice = debugchoice
3082 choice = debugchoice
3081
3083
3082 return choice
3084 return choice
3083
3085
3084 def findcmd(ui, cmd):
3086 def findcmd(ui, cmd):
3085 """Return (aliases, command table entry) for command string."""
3087 """Return (aliases, command table entry) for command string."""
3086 choice = findpossible(ui, cmd)
3088 choice = findpossible(ui, cmd)
3087
3089
3088 if choice.has_key(cmd):
3090 if choice.has_key(cmd):
3089 return choice[cmd]
3091 return choice[cmd]
3090
3092
3091 if len(choice) > 1:
3093 if len(choice) > 1:
3092 clist = choice.keys()
3094 clist = choice.keys()
3093 clist.sort()
3095 clist.sort()
3094 raise AmbiguousCommand(cmd, clist)
3096 raise AmbiguousCommand(cmd, clist)
3095
3097
3096 if choice:
3098 if choice:
3097 return choice.values()[0]
3099 return choice.values()[0]
3098
3100
3099 raise UnknownCommand(cmd)
3101 raise UnknownCommand(cmd)
3100
3102
3101 def catchterm(*args):
3103 def catchterm(*args):
3102 raise util.SignalInterrupt
3104 raise util.SignalInterrupt
3103
3105
3104 def run():
3106 def run():
3105 sys.exit(dispatch(sys.argv[1:]))
3107 sys.exit(dispatch(sys.argv[1:]))
3106
3108
3107 class ParseError(Exception):
3109 class ParseError(Exception):
3108 """Exception raised on errors in parsing the command line."""
3110 """Exception raised on errors in parsing the command line."""
3109
3111
3110 def parse(ui, args):
3112 def parse(ui, args):
3111 options = {}
3113 options = {}
3112 cmdoptions = {}
3114 cmdoptions = {}
3113
3115
3114 try:
3116 try:
3115 args = fancyopts.fancyopts(args, globalopts, options)
3117 args = fancyopts.fancyopts(args, globalopts, options)
3116 except fancyopts.getopt.GetoptError, inst:
3118 except fancyopts.getopt.GetoptError, inst:
3117 raise ParseError(None, inst)
3119 raise ParseError(None, inst)
3118
3120
3119 if args:
3121 if args:
3120 cmd, args = args[0], args[1:]
3122 cmd, args = args[0], args[1:]
3121 aliases, i = findcmd(ui, cmd)
3123 aliases, i = findcmd(ui, cmd)
3122 cmd = aliases[0]
3124 cmd = aliases[0]
3123 defaults = ui.config("defaults", cmd)
3125 defaults = ui.config("defaults", cmd)
3124 if defaults:
3126 if defaults:
3125 args = shlex.split(defaults) + args
3127 args = shlex.split(defaults) + args
3126 c = list(i[1])
3128 c = list(i[1])
3127 else:
3129 else:
3128 cmd = None
3130 cmd = None
3129 c = []
3131 c = []
3130
3132
3131 # combine global options into local
3133 # combine global options into local
3132 for o in globalopts:
3134 for o in globalopts:
3133 c.append((o[0], o[1], options[o[1]], o[3]))
3135 c.append((o[0], o[1], options[o[1]], o[3]))
3134
3136
3135 try:
3137 try:
3136 args = fancyopts.fancyopts(args, c, cmdoptions)
3138 args = fancyopts.fancyopts(args, c, cmdoptions)
3137 except fancyopts.getopt.GetoptError, inst:
3139 except fancyopts.getopt.GetoptError, inst:
3138 raise ParseError(cmd, inst)
3140 raise ParseError(cmd, inst)
3139
3141
3140 # separate global options back out
3142 # separate global options back out
3141 for o in globalopts:
3143 for o in globalopts:
3142 n = o[1]
3144 n = o[1]
3143 options[n] = cmdoptions[n]
3145 options[n] = cmdoptions[n]
3144 del cmdoptions[n]
3146 del cmdoptions[n]
3145
3147
3146 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3148 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3147
3149
3148 external = {}
3150 external = {}
3149
3151
3150 def findext(name):
3152 def findext(name):
3151 '''return module with given extension name'''
3153 '''return module with given extension name'''
3152 try:
3154 try:
3153 return sys.modules[external[name]]
3155 return sys.modules[external[name]]
3154 except KeyError:
3156 except KeyError:
3155 for k, v in external.iteritems():
3157 for k, v in external.iteritems():
3156 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3158 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3157 return sys.modules[v]
3159 return sys.modules[v]
3158 raise KeyError(name)
3160 raise KeyError(name)
3159
3161
3160 def load_extensions(ui):
3162 def load_extensions(ui):
3161 added = []
3163 added = []
3162 for ext_name, load_from_name in ui.extensions():
3164 for ext_name, load_from_name in ui.extensions():
3163 if ext_name in external:
3165 if ext_name in external:
3164 continue
3166 continue
3165 try:
3167 try:
3166 if load_from_name:
3168 if load_from_name:
3167 # the module will be loaded in sys.modules
3169 # the module will be loaded in sys.modules
3168 # choose an unique name so that it doesn't
3170 # choose an unique name so that it doesn't
3169 # conflicts with other modules
3171 # conflicts with other modules
3170 module_name = "hgext_%s" % ext_name.replace('.', '_')
3172 module_name = "hgext_%s" % ext_name.replace('.', '_')
3171 mod = imp.load_source(module_name, load_from_name)
3173 mod = imp.load_source(module_name, load_from_name)
3172 else:
3174 else:
3173 def importh(name):
3175 def importh(name):
3174 mod = __import__(name)
3176 mod = __import__(name)
3175 components = name.split('.')
3177 components = name.split('.')
3176 for comp in components[1:]:
3178 for comp in components[1:]:
3177 mod = getattr(mod, comp)
3179 mod = getattr(mod, comp)
3178 return mod
3180 return mod
3179 try:
3181 try:
3180 mod = importh("hgext.%s" % ext_name)
3182 mod = importh("hgext.%s" % ext_name)
3181 except ImportError:
3183 except ImportError:
3182 mod = importh(ext_name)
3184 mod = importh(ext_name)
3183 external[ext_name] = mod.__name__
3185 external[ext_name] = mod.__name__
3184 added.append((mod, ext_name))
3186 added.append((mod, ext_name))
3185 except (util.SignalInterrupt, KeyboardInterrupt):
3187 except (util.SignalInterrupt, KeyboardInterrupt):
3186 raise
3188 raise
3187 except Exception, inst:
3189 except Exception, inst:
3188 ui.warn(_("*** failed to import extension %s: %s\n") %
3190 ui.warn(_("*** failed to import extension %s: %s\n") %
3189 (ext_name, inst))
3191 (ext_name, inst))
3190 if ui.print_exc():
3192 if ui.print_exc():
3191 return 1
3193 return 1
3192
3194
3193 for mod, name in added:
3195 for mod, name in added:
3194 uisetup = getattr(mod, 'uisetup', None)
3196 uisetup = getattr(mod, 'uisetup', None)
3195 if uisetup:
3197 if uisetup:
3196 uisetup(ui)
3198 uisetup(ui)
3197 cmdtable = getattr(mod, 'cmdtable', {})
3199 cmdtable = getattr(mod, 'cmdtable', {})
3198 for t in cmdtable:
3200 for t in cmdtable:
3199 if t in table:
3201 if t in table:
3200 ui.warn(_("module %s overrides %s\n") % (name, t))
3202 ui.warn(_("module %s overrides %s\n") % (name, t))
3201 table.update(cmdtable)
3203 table.update(cmdtable)
3202
3204
3203 def dispatch(args):
3205 def dispatch(args):
3204 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3206 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3205 num = getattr(signal, name, None)
3207 num = getattr(signal, name, None)
3206 if num: signal.signal(num, catchterm)
3208 if num: signal.signal(num, catchterm)
3207
3209
3208 try:
3210 try:
3209 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3211 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3210 except util.Abort, inst:
3212 except util.Abort, inst:
3211 sys.stderr.write(_("abort: %s\n") % inst)
3213 sys.stderr.write(_("abort: %s\n") % inst)
3212 return -1
3214 return -1
3213
3215
3214 load_extensions(u)
3216 load_extensions(u)
3215 u.addreadhook(load_extensions)
3217 u.addreadhook(load_extensions)
3216
3218
3217 try:
3219 try:
3218 cmd, func, args, options, cmdoptions = parse(u, args)
3220 cmd, func, args, options, cmdoptions = parse(u, args)
3219 if options["time"]:
3221 if options["time"]:
3220 def get_times():
3222 def get_times():
3221 t = os.times()
3223 t = os.times()
3222 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3224 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3223 t = (t[0], t[1], t[2], t[3], time.clock())
3225 t = (t[0], t[1], t[2], t[3], time.clock())
3224 return t
3226 return t
3225 s = get_times()
3227 s = get_times()
3226 def print_time():
3228 def print_time():
3227 t = get_times()
3229 t = get_times()
3228 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3230 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3229 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3231 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3230 atexit.register(print_time)
3232 atexit.register(print_time)
3231
3233
3232 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3234 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3233 not options["noninteractive"], options["traceback"],
3235 not options["noninteractive"], options["traceback"],
3234 options["config"])
3236 options["config"])
3235
3237
3236 # enter the debugger before command execution
3238 # enter the debugger before command execution
3237 if options['debugger']:
3239 if options['debugger']:
3238 pdb.set_trace()
3240 pdb.set_trace()
3239
3241
3240 try:
3242 try:
3241 if options['cwd']:
3243 if options['cwd']:
3242 try:
3244 try:
3243 os.chdir(options['cwd'])
3245 os.chdir(options['cwd'])
3244 except OSError, inst:
3246 except OSError, inst:
3245 raise util.Abort('%s: %s' %
3247 raise util.Abort('%s: %s' %
3246 (options['cwd'], inst.strerror))
3248 (options['cwd'], inst.strerror))
3247
3249
3248 path = u.expandpath(options["repository"]) or ""
3250 path = u.expandpath(options["repository"]) or ""
3249 repo = path and hg.repository(u, path=path) or None
3251 repo = path and hg.repository(u, path=path) or None
3250
3252
3251 if options['help']:
3253 if options['help']:
3252 return help_(u, cmd, options['version'])
3254 return help_(u, cmd, options['version'])
3253 elif options['version']:
3255 elif options['version']:
3254 return show_version(u)
3256 return show_version(u)
3255 elif not cmd:
3257 elif not cmd:
3256 return help_(u, 'shortlist')
3258 return help_(u, 'shortlist')
3257
3259
3258 if cmd not in norepo.split():
3260 if cmd not in norepo.split():
3259 try:
3261 try:
3260 if not repo:
3262 if not repo:
3261 repo = hg.repository(u, path=path)
3263 repo = hg.repository(u, path=path)
3262 u = repo.ui
3264 u = repo.ui
3263 for name in external.itervalues():
3265 for name in external.itervalues():
3264 mod = sys.modules[name]
3266 mod = sys.modules[name]
3265 if hasattr(mod, 'reposetup'):
3267 if hasattr(mod, 'reposetup'):
3266 mod.reposetup(u, repo)
3268 mod.reposetup(u, repo)
3267 hg.repo_setup_hooks.append(mod.reposetup)
3269 hg.repo_setup_hooks.append(mod.reposetup)
3268 except hg.RepoError:
3270 except hg.RepoError:
3269 if cmd not in optionalrepo.split():
3271 if cmd not in optionalrepo.split():
3270 raise
3272 raise
3271 d = lambda: func(u, repo, *args, **cmdoptions)
3273 d = lambda: func(u, repo, *args, **cmdoptions)
3272 else:
3274 else:
3273 d = lambda: func(u, *args, **cmdoptions)
3275 d = lambda: func(u, *args, **cmdoptions)
3274
3276
3275 # reupdate the options, repo/.hg/hgrc may have changed them
3277 # reupdate the options, repo/.hg/hgrc may have changed them
3276 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3278 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3277 not options["noninteractive"], options["traceback"],
3279 not options["noninteractive"], options["traceback"],
3278 options["config"])
3280 options["config"])
3279
3281
3280 try:
3282 try:
3281 if options['profile']:
3283 if options['profile']:
3282 import hotshot, hotshot.stats
3284 import hotshot, hotshot.stats
3283 prof = hotshot.Profile("hg.prof")
3285 prof = hotshot.Profile("hg.prof")
3284 try:
3286 try:
3285 try:
3287 try:
3286 return prof.runcall(d)
3288 return prof.runcall(d)
3287 except:
3289 except:
3288 try:
3290 try:
3289 u.warn(_('exception raised - generating '
3291 u.warn(_('exception raised - generating '
3290 'profile anyway\n'))
3292 'profile anyway\n'))
3291 except:
3293 except:
3292 pass
3294 pass
3293 raise
3295 raise
3294 finally:
3296 finally:
3295 prof.close()
3297 prof.close()
3296 stats = hotshot.stats.load("hg.prof")
3298 stats = hotshot.stats.load("hg.prof")
3297 stats.strip_dirs()
3299 stats.strip_dirs()
3298 stats.sort_stats('time', 'calls')
3300 stats.sort_stats('time', 'calls')
3299 stats.print_stats(40)
3301 stats.print_stats(40)
3300 elif options['lsprof']:
3302 elif options['lsprof']:
3301 try:
3303 try:
3302 from mercurial import lsprof
3304 from mercurial import lsprof
3303 except ImportError:
3305 except ImportError:
3304 raise util.Abort(_(
3306 raise util.Abort(_(
3305 'lsprof not available - install from '
3307 'lsprof not available - install from '
3306 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3308 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3307 p = lsprof.Profiler()
3309 p = lsprof.Profiler()
3308 p.enable(subcalls=True)
3310 p.enable(subcalls=True)
3309 try:
3311 try:
3310 return d()
3312 return d()
3311 finally:
3313 finally:
3312 p.disable()
3314 p.disable()
3313 stats = lsprof.Stats(p.getstats())
3315 stats = lsprof.Stats(p.getstats())
3314 stats.sort()
3316 stats.sort()
3315 stats.pprint(top=10, file=sys.stderr, climit=5)
3317 stats.pprint(top=10, file=sys.stderr, climit=5)
3316 else:
3318 else:
3317 return d()
3319 return d()
3318 finally:
3320 finally:
3319 u.flush()
3321 u.flush()
3320 except:
3322 except:
3321 # enter the debugger when we hit an exception
3323 # enter the debugger when we hit an exception
3322 if options['debugger']:
3324 if options['debugger']:
3323 pdb.post_mortem(sys.exc_info()[2])
3325 pdb.post_mortem(sys.exc_info()[2])
3324 u.print_exc()
3326 u.print_exc()
3325 raise
3327 raise
3326 except ParseError, inst:
3328 except ParseError, inst:
3327 if inst.args[0]:
3329 if inst.args[0]:
3328 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3330 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3329 help_(u, inst.args[0])
3331 help_(u, inst.args[0])
3330 else:
3332 else:
3331 u.warn(_("hg: %s\n") % inst.args[1])
3333 u.warn(_("hg: %s\n") % inst.args[1])
3332 help_(u, 'shortlist')
3334 help_(u, 'shortlist')
3333 except AmbiguousCommand, inst:
3335 except AmbiguousCommand, inst:
3334 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3336 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3335 (inst.args[0], " ".join(inst.args[1])))
3337 (inst.args[0], " ".join(inst.args[1])))
3336 except UnknownCommand, inst:
3338 except UnknownCommand, inst:
3337 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3339 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3338 help_(u, 'shortlist')
3340 help_(u, 'shortlist')
3339 except hg.RepoError, inst:
3341 except hg.RepoError, inst:
3340 u.warn(_("abort: %s!\n") % inst)
3342 u.warn(_("abort: %s!\n") % inst)
3341 except lock.LockHeld, inst:
3343 except lock.LockHeld, inst:
3342 if inst.errno == errno.ETIMEDOUT:
3344 if inst.errno == errno.ETIMEDOUT:
3343 reason = _('timed out waiting for lock held by %s') % inst.locker
3345 reason = _('timed out waiting for lock held by %s') % inst.locker
3344 else:
3346 else:
3345 reason = _('lock held by %s') % inst.locker
3347 reason = _('lock held by %s') % inst.locker
3346 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3348 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3347 except lock.LockUnavailable, inst:
3349 except lock.LockUnavailable, inst:
3348 u.warn(_("abort: could not lock %s: %s\n") %
3350 u.warn(_("abort: could not lock %s: %s\n") %
3349 (inst.desc or inst.filename, inst.strerror))
3351 (inst.desc or inst.filename, inst.strerror))
3350 except revlog.RevlogError, inst:
3352 except revlog.RevlogError, inst:
3351 u.warn(_("abort: %s!\n") % inst)
3353 u.warn(_("abort: %s!\n") % inst)
3352 except util.SignalInterrupt:
3354 except util.SignalInterrupt:
3353 u.warn(_("killed!\n"))
3355 u.warn(_("killed!\n"))
3354 except KeyboardInterrupt:
3356 except KeyboardInterrupt:
3355 try:
3357 try:
3356 u.warn(_("interrupted!\n"))
3358 u.warn(_("interrupted!\n"))
3357 except IOError, inst:
3359 except IOError, inst:
3358 if inst.errno == errno.EPIPE:
3360 if inst.errno == errno.EPIPE:
3359 if u.debugflag:
3361 if u.debugflag:
3360 u.warn(_("\nbroken pipe\n"))
3362 u.warn(_("\nbroken pipe\n"))
3361 else:
3363 else:
3362 raise
3364 raise
3363 except IOError, inst:
3365 except IOError, inst:
3364 if hasattr(inst, "code"):
3366 if hasattr(inst, "code"):
3365 u.warn(_("abort: %s\n") % inst)
3367 u.warn(_("abort: %s\n") % inst)
3366 elif hasattr(inst, "reason"):
3368 elif hasattr(inst, "reason"):
3367 u.warn(_("abort: error: %s\n") % inst.reason[1])
3369 u.warn(_("abort: error: %s\n") % inst.reason[1])
3368 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3370 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3369 if u.debugflag:
3371 if u.debugflag:
3370 u.warn(_("broken pipe\n"))
3372 u.warn(_("broken pipe\n"))
3371 elif getattr(inst, "strerror", None):
3373 elif getattr(inst, "strerror", None):
3372 if getattr(inst, "filename", None):
3374 if getattr(inst, "filename", None):
3373 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3375 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3374 else:
3376 else:
3375 u.warn(_("abort: %s\n") % inst.strerror)
3377 u.warn(_("abort: %s\n") % inst.strerror)
3376 else:
3378 else:
3377 raise
3379 raise
3378 except OSError, inst:
3380 except OSError, inst:
3379 if getattr(inst, "filename", None):
3381 if getattr(inst, "filename", None):
3380 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3382 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3381 else:
3383 else:
3382 u.warn(_("abort: %s\n") % inst.strerror)
3384 u.warn(_("abort: %s\n") % inst.strerror)
3383 except util.Abort, inst:
3385 except util.Abort, inst:
3384 u.warn(_("abort: %s\n") % inst)
3386 u.warn(_("abort: %s\n") % inst)
3385 except TypeError, inst:
3387 except TypeError, inst:
3386 # was this an argument error?
3388 # was this an argument error?
3387 tb = traceback.extract_tb(sys.exc_info()[2])
3389 tb = traceback.extract_tb(sys.exc_info()[2])
3388 if len(tb) > 2: # no
3390 if len(tb) > 2: # no
3389 raise
3391 raise
3390 u.debug(inst, "\n")
3392 u.debug(inst, "\n")
3391 u.warn(_("%s: invalid arguments\n") % cmd)
3393 u.warn(_("%s: invalid arguments\n") % cmd)
3392 help_(u, cmd)
3394 help_(u, cmd)
3393 except SystemExit, inst:
3395 except SystemExit, inst:
3394 # Commands shouldn't sys.exit directly, but give a return code.
3396 # Commands shouldn't sys.exit directly, but give a return code.
3395 # Just in case catch this and and pass exit code to caller.
3397 # Just in case catch this and and pass exit code to caller.
3396 return inst.code
3398 return inst.code
3397 except:
3399 except:
3398 u.warn(_("** unknown exception encountered, details follow\n"))
3400 u.warn(_("** unknown exception encountered, details follow\n"))
3399 u.warn(_("** report bug details to "
3401 u.warn(_("** report bug details to "
3400 "http://www.selenic.com/mercurial/bts\n"))
3402 "http://www.selenic.com/mercurial/bts\n"))
3401 u.warn(_("** or mercurial@selenic.com\n"))
3403 u.warn(_("** or mercurial@selenic.com\n"))
3402 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3404 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3403 % version.get_version())
3405 % version.get_version())
3404 raise
3406 raise
3405
3407
3406 return -1
3408 return -1
@@ -1,203 +1,268 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 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 *
9 from node import *
10 demandload(globals(), 'bdiff')
11
8 from node import *
12 from node import *
9 from demandload import demandload
13 from demandload import demandload
10 demandload(globals(), "ancestor util")
14 demandload(globals(), "ancestor util")
11
15
12 class changectx(object):
16 class changectx(object):
13 """A changecontext object makes access to data related to a particular
17 """A changecontext object makes access to data related to a particular
14 changeset convenient."""
18 changeset convenient."""
15 def __init__(self, repo, changeid=None):
19 def __init__(self, repo, changeid=None):
16 """changeid is a revision number, node, or tag"""
20 """changeid is a revision number, node, or tag"""
17 self._repo = repo
21 self._repo = repo
18
22
19 if not changeid and changeid != 0:
23 if not changeid and changeid != 0:
20 p1, p2 = self._repo.dirstate.parents()
24 p1, p2 = self._repo.dirstate.parents()
21 self._rev = self._repo.changelog.rev(p1)
25 self._rev = self._repo.changelog.rev(p1)
22 if self._rev == -1:
26 if self._rev == -1:
23 changeid = 'tip'
27 changeid = 'tip'
24 else:
28 else:
25 self._node = p1
29 self._node = p1
26 return
30 return
27
31
28 self._node = self._repo.lookup(changeid)
32 self._node = self._repo.lookup(changeid)
29 self._rev = self._repo.changelog.rev(self._node)
33 self._rev = self._repo.changelog.rev(self._node)
30
34
31 def __repr__(self):
35 def __repr__(self):
32 return "<changectx %s>" % short(self.node())
36 return "<changectx %s>" % short(self.node())
33
37
34 def changeset(self):
38 def changeset(self):
35 try:
39 try:
36 return self._changeset
40 return self._changeset
37 except AttributeError:
41 except AttributeError:
38 self._changeset = self._repo.changelog.read(self.node())
42 self._changeset = self._repo.changelog.read(self.node())
39 return self._changeset
43 return self._changeset
40
44
41 def manifest(self):
45 def manifest(self):
42 try:
46 try:
43 return self._manifest
47 return self._manifest
44 except AttributeError:
48 except AttributeError:
45 self._manifest = self._repo.manifest.read(self.changeset()[0])
49 self._manifest = self._repo.manifest.read(self.changeset()[0])
46 return self._manifest
50 return self._manifest
47
51
48 def rev(self): return self._rev
52 def rev(self): return self._rev
49 def node(self): return self._node
53 def node(self): return self._node
50 def user(self): return self.changeset()[1]
54 def user(self): return self.changeset()[1]
51 def date(self): return self.changeset()[2]
55 def date(self): return self.changeset()[2]
52 def files(self): return self.changeset()[3]
56 def files(self): return self.changeset()[3]
53 def description(self): return self.changeset()[4]
57 def description(self): return self.changeset()[4]
54
58
55 def parents(self):
59 def parents(self):
56 """return contexts for each parent changeset"""
60 """return contexts for each parent changeset"""
57 p = self._repo.changelog.parents(self._node)
61 p = self._repo.changelog.parents(self._node)
58 return [ changectx(self._repo, x) for x in p ]
62 return [ changectx(self._repo, x) for x in p ]
59
63
60 def children(self):
64 def children(self):
61 """return contexts for each child changeset"""
65 """return contexts for each child changeset"""
62 c = self._repo.changelog.children(self._node)
66 c = self._repo.changelog.children(self._node)
63 return [ changectx(self._repo, x) for x in c ]
67 return [ changectx(self._repo, x) for x in c ]
64
68
65 def filenode(self, path):
69 def filenode(self, path):
66 node, flag = self._repo.manifest.find(self.changeset()[0], path)
70 node, flag = self._repo.manifest.find(self.changeset()[0], path)
67 return node
71 return node
68
72
69 def filectx(self, path, fileid=None):
73 def filectx(self, path, fileid=None):
70 """get a file context from this changeset"""
74 """get a file context from this changeset"""
71 if fileid is None:
75 if fileid is None:
72 fileid = self.filenode(path)
76 fileid = self.filenode(path)
73 return filectx(self._repo, path, fileid=fileid)
77 return filectx(self._repo, path, fileid=fileid)
74
78
75 def filectxs(self):
79 def filectxs(self):
76 """generate a file context for each file in this changeset's
80 """generate a file context for each file in this changeset's
77 manifest"""
81 manifest"""
78 mf = self.manifest()
82 mf = self.manifest()
79 m = mf.keys()
83 m = mf.keys()
80 m.sort()
84 m.sort()
81 for f in m:
85 for f in m:
82 yield self.filectx(f, fileid=mf[f])
86 yield self.filectx(f, fileid=mf[f])
83
87
84 def ancestor(self, c2):
88 def ancestor(self, c2):
85 """
89 """
86 return the ancestor context of self and c2
90 return the ancestor context of self and c2
87 """
91 """
88 n = self._repo.changelog.ancestor(self._node, c2._node)
92 n = self._repo.changelog.ancestor(self._node, c2._node)
89 return changectx(self._repo, n)
93 return changectx(self._repo, n)
90
94
91 class filectx(object):
95 class filectx(object):
92 """A filecontext object makes access to data related to a particular
96 """A filecontext object makes access to data related to a particular
93 filerevision convenient."""
97 filerevision convenient."""
94 def __init__(self, repo, path, changeid=None, fileid=None, filelog=None):
98 def __init__(self, repo, path, changeid=None, fileid=None, filelog=None):
95 """changeid can be a changeset revision, node, or tag.
99 """changeid can be a changeset revision, node, or tag.
96 fileid can be a file revision or node."""
100 fileid can be a file revision or node."""
97 self._repo = repo
101 self._repo = repo
98 self._path = path
102 self._path = path
99
103
100 assert changeid is not None or fileid is not None
104 assert changeid is not None or fileid is not None
101
105
102 if filelog:
106 if filelog:
103 self._filelog = filelog
107 self._filelog = filelog
104 else:
108 else:
105 self._filelog = self._repo.file(self._path)
109 self._filelog = self._repo.file(self._path)
106
110
107 if fileid is None:
111 if fileid is None:
108 self._changeid = changeid
112 self._changeid = changeid
109 else:
113 else:
110 self._filenode = self._filelog.lookup(fileid)
114 self._filenode = self._filelog.lookup(fileid)
111 self._changeid = self._filelog.linkrev(self._filenode)
115 self._changeid = self._filelog.linkrev(self._filenode)
112
116
113 def __getattr__(self, name):
117 def __getattr__(self, name):
114 if name == '_changectx':
118 if name == '_changectx':
115 self._changectx = changectx(self._repo, self._changeid)
119 self._changectx = changectx(self._repo, self._changeid)
116 return self._changectx
120 return self._changectx
117 elif name == '_filenode':
121 elif name == '_filenode':
118 self._filenode = self._changectx.filenode(self._path)
122 self._filenode = self._changectx.filenode(self._path)
119 return self._filenode
123 return self._filenode
120 elif name == '_filerev':
124 elif name == '_filerev':
121 self._filerev = self._filelog.rev(self._filenode)
125 self._filerev = self._filelog.rev(self._filenode)
122 return self._filerev
126 return self._filerev
123 else:
127 else:
124 raise AttributeError, name
128 raise AttributeError, name
125
129
126 def __repr__(self):
130 def __repr__(self):
127 return "<filectx %s@%s>" % (self.path(), short(self.node()))
131 return "<filectx %s@%s>" % (self.path(), short(self.node()))
128
132
129 def filerev(self): return self._filerev
133 def filerev(self): return self._filerev
130 def filenode(self): return self._filenode
134 def filenode(self): return self._filenode
131 def filelog(self): return self._filelog
135 def filelog(self): return self._filelog
132
136
133 def rev(self):
137 def rev(self):
134 if hasattr(self, "_changectx"):
138 if hasattr(self, "_changectx"):
135 return self._changectx.rev()
139 return self._changectx.rev()
136 return self._filelog.linkrev(self._filenode)
140 return self._filelog.linkrev(self._filenode)
137
141
138 def node(self): return self._changectx.node()
142 def node(self): return self._changectx.node()
139 def user(self): return self._changectx.user()
143 def user(self): return self._changectx.user()
140 def date(self): return self._changectx.date()
144 def date(self): return self._changectx.date()
141 def files(self): return self._changectx.files()
145 def files(self): return self._changectx.files()
142 def description(self): return self._changectx.description()
146 def description(self): return self._changectx.description()
143 def manifest(self): return self._changectx.manifest()
147 def manifest(self): return self._changectx.manifest()
144 def changectx(self): return self._changectx
148 def changectx(self): return self._changectx
145
149
146 def data(self): return self._filelog.read(self._filenode)
150 def data(self): return self._filelog.read(self._filenode)
147 def renamed(self): return self._filelog.renamed(self._filenode)
151 def renamed(self): return self._filelog.renamed(self._filenode)
148 def path(self): return self._path
152 def path(self): return self._path
149
153
150 def parents(self):
154 def parents(self):
151 p = self._path
155 p = self._path
152 fl = self._filelog
156 fl = self._filelog
153 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
157 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
154
158
155 r = self.renamed()
159 r = self.renamed()
156 if r:
160 if r:
157 pl[0] = (r[0], r[1], None)
161 pl[0] = (r[0], r[1], None)
158
162
159 return [ filectx(self._repo, p, fileid=n, filelog=l)
163 return [ filectx(self._repo, p, fileid=n, filelog=l)
160 for p,n,l in pl if n != nullid ]
164 for p,n,l in pl if n != nullid ]
161
165
162 def children(self):
166 def children(self):
163 # hard for renames
167 # hard for renames
164 c = self._filelog.children(self._filenode)
168 c = self._filelog.children(self._filenode)
165 return [ filectx(self._repo, self._path, fileid=x,
169 return [ filectx(self._repo, self._path, fileid=x,
166 filelog=self._filelog) for x in c ]
170 filelog=self._filelog) for x in c ]
167
171
168 def annotate(self):
172 def annotate(self, follow=False):
169 getctx = util.cachefunc(lambda x: filectx(self._repo, self._path,
173 '''returns a list of tuples of (ctx, line) for each line
170 changeid=x,
174 in the file, where ctx is the filectx of the node where
171 filelog=self._filelog))
175 that line was last changed'''
172 hist = self._filelog.annotate(self._filenode)
176
177 def decorate(text, rev):
178 return ([rev] * len(text.splitlines()), text)
179
180 def pair(parent, child):
181 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
182 child[0][b1:b2] = parent[0][a1:a2]
183 return child
184
185 getlog = util.cachefunc(lambda x: self._repo.file(x))
186 def getctx(path, fileid):
187 log = path == self._path and self._filelog or getlog(path)
188 return filectx(self._repo, path, fileid=fileid, filelog=log)
189 getctx = util.cachefunc(getctx)
190
191 def parents(f):
192 # we want to reuse filectx objects as much as possible
193 p = f._path
194 pl = [ (p, f._filelog.rev(n)) for n in f._filelog.parents(f._filenode) ]
195
196 if follow:
197 r = f.renamed()
198 if r:
199 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
173
200
174 return [(getctx(rev), line) for rev, line in hist]
201 return [ getctx(p, n) for p, n in pl if n != -1 ]
202
203 # find all ancestors
204 needed = {self: 1}
205 visit = [self]
206 files = [self._path]
207 while visit:
208 f = visit.pop(0)
209 for p in parents(f):
210 if p not in needed:
211 needed[p] = 1
212 visit.append(p)
213 if p._path not in files:
214 files.append(p._path)
215 else:
216 # count how many times we'll use this
217 needed[p] += 1
218
219 # sort by revision (per file) which is a topological order
220 visit = []
221 files.reverse()
222 for f in files:
223 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
224 fn.sort()
225 visit.extend(fn)
226 hist = {}
227
228 for r, f in visit:
229 curr = decorate(f.data(), f)
230 for p in parents(f):
231 if p != nullid:
232 curr = pair(hist[p], curr)
233 # trim the history of unneeded revs
234 needed[p] -= 1
235 if not needed[p]:
236 del hist[p]
237 hist[f] = curr
238
239 return zip(hist[f][0], hist[f][1].splitlines(1))
175
240
176 def ancestor(self, fc2):
241 def ancestor(self, fc2):
177 """
242 """
178 find the common ancestor file context, if any, of self, and fc2
243 find the common ancestor file context, if any, of self, and fc2
179 """
244 """
180
245
181 acache = {}
246 acache = {}
182 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
247 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
183 def parents(vertex):
248 def parents(vertex):
184 if vertex in acache:
249 if vertex in acache:
185 return acache[vertex]
250 return acache[vertex]
186 f, n = vertex
251 f, n = vertex
187 if f not in flcache:
252 if f not in flcache:
188 flcache[f] = self._repo.file(f)
253 flcache[f] = self._repo.file(f)
189 fl = flcache[f]
254 fl = flcache[f]
190 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
255 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
191 re = fl.renamed(n)
256 re = fl.renamed(n)
192 if re:
257 if re:
193 pl.append(re)
258 pl.append(re)
194 acache[vertex]=pl
259 acache[vertex]=pl
195 return pl
260 return pl
196
261
197 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
262 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
198 v = ancestor.ancestor(a, b, parents)
263 v = ancestor.ancestor(a, b, parents)
199 if v:
264 if v:
200 f,n = v
265 f,n = v
201 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
266 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
202
267
203 return None
268 return None
@@ -1,23 +1,75 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 export HGMERGE=true
4
3 echo % init
5 echo % init
4 hg init
6 hg init
5
7
6 echo % commit
8 echo % commit
7 echo 'a' > a
9 echo 'a' > a
8 hg ci -A -m test -u nobody -d '1 0'
10 hg ci -A -m test -u nobody -d '1 0'
9
11
10 echo % annotate -c
12 echo % annotate -c
11 hg annotate -c a
13 hg annotate -c a
12
14
13 echo % annotate -d
15 echo % annotate -d
14 hg annotate -d a
16 hg annotate -d a
15
17
16 echo % annotate -n
18 echo % annotate -n
17 hg annotate -n a
19 hg annotate -n a
18
20
19 echo % annotate -u
21 echo % annotate -u
20 hg annotate -u a
22 hg annotate -u a
21
23
22 echo % annotate -cdnu
24 echo % annotate -cdnu
23 hg annotate -cdnu a
25 hg annotate -cdnu a
26
27 cat <<EOF >>a
28 a
29 a
30 EOF
31 hg ci -ma1 -d '1 0'
32 hg cp a b
33 hg ci -mb -d '1 0'
34 cat <<EOF >> b
35 b
36 b
37 b
38 EOF
39 hg ci -mb2 -d '2 0'
40
41 echo % annotate b
42 hg annotate b
43 echo % annotate -nf b
44 hg annotate -nf b
45
46 hg up -C 2
47 cat <<EOF >> b
48 b
49 c
50 b
51 EOF
52 hg ci -mb2.1 -d '2 0'
53 hg merge
54 hg ci -mmergeb -d '3 0'
55 echo % annotate after merge
56 hg annotate -nf b
57
58 hg up -C 1
59 hg cp a b
60 cat <<EOF > b
61 a
62 z
63 a
64 EOF
65 hg ci -mc -d '3 0'
66 hg merge
67 cat <<EOF >> b
68 b
69 c
70 b
71 EOF
72 echo d >> b
73 hg ci -mmerge2 -d '4 0'
74 echo % annotate after rename merge
75 hg annotate -nf b
@@ -1,13 +1,50 b''
1 % init
1 % init
2 % commit
2 % commit
3 adding a
3 adding a
4 % annotate -c
4 % annotate -c
5 8435f90966e4: a
5 8435f90966e4: a
6 % annotate -d
6 % annotate -d
7 Thu Jan 01 00:00:01 1970 +0000: a
7 Thu Jan 01 00:00:01 1970 +0000: a
8 % annotate -n
8 % annotate -n
9 0: a
9 0: a
10 % annotate -u
10 % annotate -u
11 nobody: a
11 nobody: a
12 % annotate -cdnu
12 % annotate -cdnu
13 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
13 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
14 % annotate b
15 2: a
16 2: a
17 2: a
18 3: b
19 3: b
20 3: b
21 % annotate -nf b
22 0 a: a
23 1 a: a
24 1 a: a
25 3 b: b
26 3 b: b
27 3 b: b
28 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 merging b
30 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
31 (branch merge, don't forget to commit)
32 % annotate after merge
33 0 a: a
34 1 a: a
35 1 a: a
36 3 b: b
37 4 b: c
38 3 b: b
39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
40 merging b
41 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
42 (branch merge, don't forget to commit)
43 % annotate after rename merge
44 0 a: a
45 6 b: z
46 1 a: a
47 3 b: b
48 4 b: c
49 3 b: b
50 7 b: d
General Comments 0
You need to be logged in to leave comments. Login now