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