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