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