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