##// END OF EJS Templates
code indentation fixes
Patrick Mezard -
r13747:cede0042 default
parent child Browse files
Show More
@@ -1,4904 +1,4904 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, util, revlog, extensions, copies, error, bookmarks
12 import hg, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset, templatefilters
16 import minirst, revset, templatefilters
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 ``.hgignore``. As with add, these changes take effect at the next
61 ``.hgignore``. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 def bad(x, y):
129 def bad(x, y):
130 raise util.Abort("%s: %s" % (x, y))
130 raise util.Abort("%s: %s" % (x, y))
131
131
132 ctx = cmdutil.revsingle(repo, opts.get('rev'))
132 ctx = cmdutil.revsingle(repo, opts.get('rev'))
133 m = cmdutil.match(repo, pats, opts)
133 m = cmdutil.match(repo, pats, opts)
134 m.bad = bad
134 m.bad = bad
135 follow = not opts.get('no_follow')
135 follow = not opts.get('no_follow')
136 for abs in ctx.walk(m):
136 for abs in ctx.walk(m):
137 fctx = ctx[abs]
137 fctx = ctx[abs]
138 if not opts.get('text') and util.binary(fctx.data()):
138 if not opts.get('text') and util.binary(fctx.data()):
139 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
139 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
140 continue
140 continue
141
141
142 lines = fctx.annotate(follow=follow, linenumber=linenumber)
142 lines = fctx.annotate(follow=follow, linenumber=linenumber)
143 pieces = []
143 pieces = []
144
144
145 for f in funcmap:
145 for f in funcmap:
146 l = [f(n) for n, dummy in lines]
146 l = [f(n) for n, dummy in lines]
147 if l:
147 if l:
148 sized = [(x, encoding.colwidth(x)) for x in l]
148 sized = [(x, encoding.colwidth(x)) for x in l]
149 ml = max([w for x, w in sized])
149 ml = max([w for x, w in sized])
150 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
150 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
151
151
152 if pieces:
152 if pieces:
153 for p, l in zip(zip(*pieces), lines):
153 for p, l in zip(zip(*pieces), lines):
154 ui.write("%s: %s" % (" ".join(p), l[1]))
154 ui.write("%s: %s" % (" ".join(p), l[1]))
155
155
156 def archive(ui, repo, dest, **opts):
156 def archive(ui, repo, dest, **opts):
157 '''create an unversioned archive of a repository revision
157 '''create an unversioned archive of a repository revision
158
158
159 By default, the revision used is the parent of the working
159 By default, the revision used is the parent of the working
160 directory; use -r/--rev to specify a different revision.
160 directory; use -r/--rev to specify a different revision.
161
161
162 The archive type is automatically detected based on file
162 The archive type is automatically detected based on file
163 extension (or override using -t/--type).
163 extension (or override using -t/--type).
164
164
165 Valid types are:
165 Valid types are:
166
166
167 :``files``: a directory full of files (default)
167 :``files``: a directory full of files (default)
168 :``tar``: tar archive, uncompressed
168 :``tar``: tar archive, uncompressed
169 :``tbz2``: tar archive, compressed using bzip2
169 :``tbz2``: tar archive, compressed using bzip2
170 :``tgz``: tar archive, compressed using gzip
170 :``tgz``: tar archive, compressed using gzip
171 :``uzip``: zip archive, uncompressed
171 :``uzip``: zip archive, uncompressed
172 :``zip``: zip archive, compressed using deflate
172 :``zip``: zip archive, compressed using deflate
173
173
174 The exact name of the destination archive or directory is given
174 The exact name of the destination archive or directory is given
175 using a format string; see :hg:`help export` for details.
175 using a format string; see :hg:`help export` for details.
176
176
177 Each member added to an archive file has a directory prefix
177 Each member added to an archive file has a directory prefix
178 prepended. Use -p/--prefix to specify a format string for the
178 prepended. Use -p/--prefix to specify a format string for the
179 prefix. The default is the basename of the archive, with suffixes
179 prefix. The default is the basename of the archive, with suffixes
180 removed.
180 removed.
181
181
182 Returns 0 on success.
182 Returns 0 on success.
183 '''
183 '''
184
184
185 ctx = cmdutil.revsingle(repo, opts.get('rev'))
185 ctx = cmdutil.revsingle(repo, opts.get('rev'))
186 if not ctx:
186 if not ctx:
187 raise util.Abort(_('no working directory: please specify a revision'))
187 raise util.Abort(_('no working directory: please specify a revision'))
188 node = ctx.node()
188 node = ctx.node()
189 dest = cmdutil.make_filename(repo, dest, node)
189 dest = cmdutil.make_filename(repo, dest, node)
190 if os.path.realpath(dest) == repo.root:
190 if os.path.realpath(dest) == repo.root:
191 raise util.Abort(_('repository root cannot be destination'))
191 raise util.Abort(_('repository root cannot be destination'))
192
192
193 kind = opts.get('type') or archival.guesskind(dest) or 'files'
193 kind = opts.get('type') or archival.guesskind(dest) or 'files'
194 prefix = opts.get('prefix')
194 prefix = opts.get('prefix')
195
195
196 if dest == '-':
196 if dest == '-':
197 if kind == 'files':
197 if kind == 'files':
198 raise util.Abort(_('cannot archive plain files to stdout'))
198 raise util.Abort(_('cannot archive plain files to stdout'))
199 dest = sys.stdout
199 dest = sys.stdout
200 if not prefix:
200 if not prefix:
201 prefix = os.path.basename(repo.root) + '-%h'
201 prefix = os.path.basename(repo.root) + '-%h'
202
202
203 prefix = cmdutil.make_filename(repo, prefix, node)
203 prefix = cmdutil.make_filename(repo, prefix, node)
204 matchfn = cmdutil.match(repo, [], opts)
204 matchfn = cmdutil.match(repo, [], opts)
205 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
205 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
206 matchfn, prefix, subrepos=opts.get('subrepos'))
206 matchfn, prefix, subrepos=opts.get('subrepos'))
207
207
208 def backout(ui, repo, node=None, rev=None, **opts):
208 def backout(ui, repo, node=None, rev=None, **opts):
209 '''reverse effect of earlier changeset
209 '''reverse effect of earlier changeset
210
210
211 Prepare a new changeset with the effect of REV undone in the
211 Prepare a new changeset with the effect of REV undone in the
212 current working directory.
212 current working directory.
213
213
214 If REV is the parent of the working directory, then this new changeset
214 If REV is the parent of the working directory, then this new changeset
215 is committed automatically. Otherwise, hg needs to merge the
215 is committed automatically. Otherwise, hg needs to merge the
216 changes and the merged result is left uncommitted.
216 changes and the merged result is left uncommitted.
217
217
218 By default, the pending changeset will have one parent,
218 By default, the pending changeset will have one parent,
219 maintaining a linear history. With --merge, the pending changeset
219 maintaining a linear history. With --merge, the pending changeset
220 will instead have two parents: the old parent of the working
220 will instead have two parents: the old parent of the working
221 directory and a new child of REV that simply undoes REV.
221 directory and a new child of REV that simply undoes REV.
222
222
223 Before version 1.7, the behavior without --merge was equivalent to
223 Before version 1.7, the behavior without --merge was equivalent to
224 specifying --merge followed by :hg:`update --clean .` to cancel
224 specifying --merge followed by :hg:`update --clean .` to cancel
225 the merge and leave the child of REV as a head to be merged
225 the merge and leave the child of REV as a head to be merged
226 separately.
226 separately.
227
227
228 See :hg:`help dates` for a list of formats valid for -d/--date.
228 See :hg:`help dates` for a list of formats valid for -d/--date.
229
229
230 Returns 0 on success.
230 Returns 0 on success.
231 '''
231 '''
232 if rev and node:
232 if rev and node:
233 raise util.Abort(_("please specify just one revision"))
233 raise util.Abort(_("please specify just one revision"))
234
234
235 if not rev:
235 if not rev:
236 rev = node
236 rev = node
237
237
238 if not rev:
238 if not rev:
239 raise util.Abort(_("please specify a revision to backout"))
239 raise util.Abort(_("please specify a revision to backout"))
240
240
241 date = opts.get('date')
241 date = opts.get('date')
242 if date:
242 if date:
243 opts['date'] = util.parsedate(date)
243 opts['date'] = util.parsedate(date)
244
244
245 cmdutil.bail_if_changed(repo)
245 cmdutil.bail_if_changed(repo)
246 node = cmdutil.revsingle(repo, rev).node()
246 node = cmdutil.revsingle(repo, rev).node()
247
247
248 op1, op2 = repo.dirstate.parents()
248 op1, op2 = repo.dirstate.parents()
249 a = repo.changelog.ancestor(op1, node)
249 a = repo.changelog.ancestor(op1, node)
250 if a != node:
250 if a != node:
251 raise util.Abort(_('cannot backout change on a different branch'))
251 raise util.Abort(_('cannot backout change on a different branch'))
252
252
253 p1, p2 = repo.changelog.parents(node)
253 p1, p2 = repo.changelog.parents(node)
254 if p1 == nullid:
254 if p1 == nullid:
255 raise util.Abort(_('cannot backout a change with no parents'))
255 raise util.Abort(_('cannot backout a change with no parents'))
256 if p2 != nullid:
256 if p2 != nullid:
257 if not opts.get('parent'):
257 if not opts.get('parent'):
258 raise util.Abort(_('cannot backout a merge changeset without '
258 raise util.Abort(_('cannot backout a merge changeset without '
259 '--parent'))
259 '--parent'))
260 p = repo.lookup(opts['parent'])
260 p = repo.lookup(opts['parent'])
261 if p not in (p1, p2):
261 if p not in (p1, p2):
262 raise util.Abort(_('%s is not a parent of %s') %
262 raise util.Abort(_('%s is not a parent of %s') %
263 (short(p), short(node)))
263 (short(p), short(node)))
264 parent = p
264 parent = p
265 else:
265 else:
266 if opts.get('parent'):
266 if opts.get('parent'):
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 parent = p1
268 parent = p1
269
269
270 # the backout should appear on the same branch
270 # the backout should appear on the same branch
271 branch = repo.dirstate.branch()
271 branch = repo.dirstate.branch()
272 hg.clean(repo, node, show_stats=False)
272 hg.clean(repo, node, show_stats=False)
273 repo.dirstate.setbranch(branch)
273 repo.dirstate.setbranch(branch)
274 revert_opts = opts.copy()
274 revert_opts = opts.copy()
275 revert_opts['date'] = None
275 revert_opts['date'] = None
276 revert_opts['all'] = True
276 revert_opts['all'] = True
277 revert_opts['rev'] = hex(parent)
277 revert_opts['rev'] = hex(parent)
278 revert_opts['no_backup'] = None
278 revert_opts['no_backup'] = None
279 revert(ui, repo, **revert_opts)
279 revert(ui, repo, **revert_opts)
280 if not opts.get('merge') and op1 != node:
280 if not opts.get('merge') and op1 != node:
281 try:
281 try:
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 return hg.update(repo, op1)
283 return hg.update(repo, op1)
284 finally:
284 finally:
285 ui.setconfig('ui', 'forcemerge', '')
285 ui.setconfig('ui', 'forcemerge', '')
286
286
287 commit_opts = opts.copy()
287 commit_opts = opts.copy()
288 commit_opts['addremove'] = False
288 commit_opts['addremove'] = False
289 if not commit_opts['message'] and not commit_opts['logfile']:
289 if not commit_opts['message'] and not commit_opts['logfile']:
290 # we don't translate commit messages
290 # we don't translate commit messages
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['force_editor'] = True
292 commit_opts['force_editor'] = True
293 commit(ui, repo, **commit_opts)
293 commit(ui, repo, **commit_opts)
294 def nice(node):
294 def nice(node):
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 ui.status(_('changeset %s backs out changeset %s\n') %
296 ui.status(_('changeset %s backs out changeset %s\n') %
297 (nice(repo.changelog.tip()), nice(node)))
297 (nice(repo.changelog.tip()), nice(node)))
298 if opts.get('merge') and op1 != node:
298 if opts.get('merge') and op1 != node:
299 hg.clean(repo, op1, show_stats=False)
299 hg.clean(repo, op1, show_stats=False)
300 ui.status(_('merging with changeset %s\n')
300 ui.status(_('merging with changeset %s\n')
301 % nice(repo.changelog.tip()))
301 % nice(repo.changelog.tip()))
302 try:
302 try:
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 return hg.merge(repo, hex(repo.changelog.tip()))
304 return hg.merge(repo, hex(repo.changelog.tip()))
305 finally:
305 finally:
306 ui.setconfig('ui', 'forcemerge', '')
306 ui.setconfig('ui', 'forcemerge', '')
307 return 0
307 return 0
308
308
309 def bisect(ui, repo, rev=None, extra=None, command=None,
309 def bisect(ui, repo, rev=None, extra=None, command=None,
310 reset=None, good=None, bad=None, skip=None, extend=None,
310 reset=None, good=None, bad=None, skip=None, extend=None,
311 noupdate=None):
311 noupdate=None):
312 """subdivision search of changesets
312 """subdivision search of changesets
313
313
314 This command helps to find changesets which introduce problems. To
314 This command helps to find changesets which introduce problems. To
315 use, mark the earliest changeset you know exhibits the problem as
315 use, mark the earliest changeset you know exhibits the problem as
316 bad, then mark the latest changeset which is free from the problem
316 bad, then mark the latest changeset which is free from the problem
317 as good. Bisect will update your working directory to a revision
317 as good. Bisect will update your working directory to a revision
318 for testing (unless the -U/--noupdate option is specified). Once
318 for testing (unless the -U/--noupdate option is specified). Once
319 you have performed tests, mark the working directory as good or
319 you have performed tests, mark the working directory as good or
320 bad, and bisect will either update to another candidate changeset
320 bad, and bisect will either update to another candidate changeset
321 or announce that it has found the bad revision.
321 or announce that it has found the bad revision.
322
322
323 As a shortcut, you can also use the revision argument to mark a
323 As a shortcut, you can also use the revision argument to mark a
324 revision as good or bad without checking it out first.
324 revision as good or bad without checking it out first.
325
325
326 If you supply a command, it will be used for automatic bisection.
326 If you supply a command, it will be used for automatic bisection.
327 Its exit status will be used to mark revisions as good or bad:
327 Its exit status will be used to mark revisions as good or bad:
328 status 0 means good, 125 means to skip the revision, 127
328 status 0 means good, 125 means to skip the revision, 127
329 (command not found) will abort the bisection, and any other
329 (command not found) will abort the bisection, and any other
330 non-zero exit status means the revision is bad.
330 non-zero exit status means the revision is bad.
331
331
332 Returns 0 on success.
332 Returns 0 on success.
333 """
333 """
334 def extendbisectrange(nodes, good):
334 def extendbisectrange(nodes, good):
335 # bisect is incomplete when it ends on a merge node and
335 # bisect is incomplete when it ends on a merge node and
336 # one of the parent was not checked.
336 # one of the parent was not checked.
337 parents = repo[nodes[0]].parents()
337 parents = repo[nodes[0]].parents()
338 if len(parents) > 1:
338 if len(parents) > 1:
339 side = good and state['bad'] or state['good']
339 side = good and state['bad'] or state['good']
340 num = len(set(i.node() for i in parents) & set(side))
340 num = len(set(i.node() for i in parents) & set(side))
341 if num == 1:
341 if num == 1:
342 return parents[0].ancestor(parents[1])
342 return parents[0].ancestor(parents[1])
343 return None
343 return None
344
344
345 def print_result(nodes, good):
345 def print_result(nodes, good):
346 displayer = cmdutil.show_changeset(ui, repo, {})
346 displayer = cmdutil.show_changeset(ui, repo, {})
347 if len(nodes) == 1:
347 if len(nodes) == 1:
348 # narrowed it down to a single revision
348 # narrowed it down to a single revision
349 if good:
349 if good:
350 ui.write(_("The first good revision is:\n"))
350 ui.write(_("The first good revision is:\n"))
351 else:
351 else:
352 ui.write(_("The first bad revision is:\n"))
352 ui.write(_("The first bad revision is:\n"))
353 displayer.show(repo[nodes[0]])
353 displayer.show(repo[nodes[0]])
354 parents = repo[nodes[0]].parents()
354 parents = repo[nodes[0]].parents()
355 extendnode = extendbisectrange(nodes, good)
355 extendnode = extendbisectrange(nodes, good)
356 if extendnode is not None:
356 if extendnode is not None:
357 ui.write(_('Not all ancestors of this changeset have been'
357 ui.write(_('Not all ancestors of this changeset have been'
358 ' checked.\nUse bisect --extend to continue the '
358 ' checked.\nUse bisect --extend to continue the '
359 'bisection from\nthe common ancestor, %s.\n')
359 'bisection from\nthe common ancestor, %s.\n')
360 % short(extendnode.node()))
360 % short(extendnode.node()))
361 else:
361 else:
362 # multiple possible revisions
362 # multiple possible revisions
363 if good:
363 if good:
364 ui.write(_("Due to skipped revisions, the first "
364 ui.write(_("Due to skipped revisions, the first "
365 "good revision could be any of:\n"))
365 "good revision could be any of:\n"))
366 else:
366 else:
367 ui.write(_("Due to skipped revisions, the first "
367 ui.write(_("Due to skipped revisions, the first "
368 "bad revision could be any of:\n"))
368 "bad revision could be any of:\n"))
369 for n in nodes:
369 for n in nodes:
370 displayer.show(repo[n])
370 displayer.show(repo[n])
371 displayer.close()
371 displayer.close()
372
372
373 def check_state(state, interactive=True):
373 def check_state(state, interactive=True):
374 if not state['good'] or not state['bad']:
374 if not state['good'] or not state['bad']:
375 if (good or bad or skip or reset) and interactive:
375 if (good or bad or skip or reset) and interactive:
376 return
376 return
377 if not state['good']:
377 if not state['good']:
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
379 else:
379 else:
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
381 return True
381 return True
382
382
383 # backward compatibility
383 # backward compatibility
384 if rev in "good bad reset init".split():
384 if rev in "good bad reset init".split():
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
386 cmd, rev, extra = rev, extra, None
386 cmd, rev, extra = rev, extra, None
387 if cmd == "good":
387 if cmd == "good":
388 good = True
388 good = True
389 elif cmd == "bad":
389 elif cmd == "bad":
390 bad = True
390 bad = True
391 else:
391 else:
392 reset = True
392 reset = True
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
394 raise util.Abort(_('incompatible arguments'))
394 raise util.Abort(_('incompatible arguments'))
395
395
396 if reset:
396 if reset:
397 p = repo.join("bisect.state")
397 p = repo.join("bisect.state")
398 if os.path.exists(p):
398 if os.path.exists(p):
399 os.unlink(p)
399 os.unlink(p)
400 return
400 return
401
401
402 state = hbisect.load_state(repo)
402 state = hbisect.load_state(repo)
403
403
404 if command:
404 if command:
405 changesets = 1
405 changesets = 1
406 try:
406 try:
407 while changesets:
407 while changesets:
408 # update state
408 # update state
409 status = util.system(command)
409 status = util.system(command)
410 if status == 125:
410 if status == 125:
411 transition = "skip"
411 transition = "skip"
412 elif status == 0:
412 elif status == 0:
413 transition = "good"
413 transition = "good"
414 # status < 0 means process was killed
414 # status < 0 means process was killed
415 elif status == 127:
415 elif status == 127:
416 raise util.Abort(_("failed to execute %s") % command)
416 raise util.Abort(_("failed to execute %s") % command)
417 elif status < 0:
417 elif status < 0:
418 raise util.Abort(_("%s killed") % command)
418 raise util.Abort(_("%s killed") % command)
419 else:
419 else:
420 transition = "bad"
420 transition = "bad"
421 ctx = cmdutil.revsingle(repo, rev)
421 ctx = cmdutil.revsingle(repo, rev)
422 rev = None # clear for future iterations
422 rev = None # clear for future iterations
423 state[transition].append(ctx.node())
423 state[transition].append(ctx.node())
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
425 check_state(state, interactive=False)
425 check_state(state, interactive=False)
426 # bisect
426 # bisect
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
428 # update to next check
428 # update to next check
429 cmdutil.bail_if_changed(repo)
429 cmdutil.bail_if_changed(repo)
430 hg.clean(repo, nodes[0], show_stats=False)
430 hg.clean(repo, nodes[0], show_stats=False)
431 finally:
431 finally:
432 hbisect.save_state(repo, state)
432 hbisect.save_state(repo, state)
433 print_result(nodes, good)
433 print_result(nodes, good)
434 return
434 return
435
435
436 # update state
436 # update state
437
437
438 if rev:
438 if rev:
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
440 else:
440 else:
441 nodes = [repo.lookup('.')]
441 nodes = [repo.lookup('.')]
442
442
443 if good or bad or skip:
443 if good or bad or skip:
444 if good:
444 if good:
445 state['good'] += nodes
445 state['good'] += nodes
446 elif bad:
446 elif bad:
447 state['bad'] += nodes
447 state['bad'] += nodes
448 elif skip:
448 elif skip:
449 state['skip'] += nodes
449 state['skip'] += nodes
450 hbisect.save_state(repo, state)
450 hbisect.save_state(repo, state)
451
451
452 if not check_state(state):
452 if not check_state(state):
453 return
453 return
454
454
455 # actually bisect
455 # actually bisect
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
457 if extend:
457 if extend:
458 if not changesets:
458 if not changesets:
459 extendnode = extendbisectrange(nodes, good)
459 extendnode = extendbisectrange(nodes, good)
460 if extendnode is not None:
460 if extendnode is not None:
461 ui.write(_("Extending search to changeset %d:%s\n"
461 ui.write(_("Extending search to changeset %d:%s\n"
462 % (extendnode.rev(), short(extendnode.node()))))
462 % (extendnode.rev(), short(extendnode.node()))))
463 if noupdate:
463 if noupdate:
464 return
464 return
465 cmdutil.bail_if_changed(repo)
465 cmdutil.bail_if_changed(repo)
466 return hg.clean(repo, extendnode.node())
466 return hg.clean(repo, extendnode.node())
467 raise util.Abort(_("nothing to extend"))
467 raise util.Abort(_("nothing to extend"))
468
468
469 if changesets == 0:
469 if changesets == 0:
470 print_result(nodes, good)
470 print_result(nodes, good)
471 else:
471 else:
472 assert len(nodes) == 1 # only a single node can be tested next
472 assert len(nodes) == 1 # only a single node can be tested next
473 node = nodes[0]
473 node = nodes[0]
474 # compute the approximate number of remaining tests
474 # compute the approximate number of remaining tests
475 tests, size = 0, 2
475 tests, size = 0, 2
476 while size <= changesets:
476 while size <= changesets:
477 tests, size = tests + 1, size * 2
477 tests, size = tests + 1, size * 2
478 rev = repo.changelog.rev(node)
478 rev = repo.changelog.rev(node)
479 ui.write(_("Testing changeset %d:%s "
479 ui.write(_("Testing changeset %d:%s "
480 "(%d changesets remaining, ~%d tests)\n")
480 "(%d changesets remaining, ~%d tests)\n")
481 % (rev, short(node), changesets, tests))
481 % (rev, short(node), changesets, tests))
482 if not noupdate:
482 if not noupdate:
483 cmdutil.bail_if_changed(repo)
483 cmdutil.bail_if_changed(repo)
484 return hg.clean(repo, node)
484 return hg.clean(repo, node)
485
485
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
487 '''track a line of development with movable markers
487 '''track a line of development with movable markers
488
488
489 Bookmarks are pointers to certain commits that move when
489 Bookmarks are pointers to certain commits that move when
490 committing. Bookmarks are local. They can be renamed, copied and
490 committing. Bookmarks are local. They can be renamed, copied and
491 deleted. It is possible to use bookmark names in :hg:`merge` and
491 deleted. It is possible to use bookmark names in :hg:`merge` and
492 :hg:`update` to merge and update respectively to a given bookmark.
492 :hg:`update` to merge and update respectively to a given bookmark.
493
493
494 You can use :hg:`bookmark NAME` to set a bookmark on the working
494 You can use :hg:`bookmark NAME` to set a bookmark on the working
495 directory's parent revision with the given name. If you specify
495 directory's parent revision with the given name. If you specify
496 a revision using -r REV (where REV may be an existing bookmark),
496 a revision using -r REV (where REV may be an existing bookmark),
497 the bookmark is assigned to that revision.
497 the bookmark is assigned to that revision.
498
498
499 Bookmarks can be pushed and pulled between repositories (see :hg:`help
499 Bookmarks can be pushed and pulled between repositories (see :hg:`help
500 push` and :hg:`help pull`). This requires both the local and remote
500 push` and :hg:`help pull`). This requires both the local and remote
501 repositories to support bookmarks. For versions prior to 1.8, this means
501 repositories to support bookmarks. For versions prior to 1.8, this means
502 the bookmarks extension must be enabled.
502 the bookmarks extension must be enabled.
503 '''
503 '''
504 hexfn = ui.debugflag and hex or short
504 hexfn = ui.debugflag and hex or short
505 marks = repo._bookmarks
505 marks = repo._bookmarks
506 cur = repo.changectx('.').node()
506 cur = repo.changectx('.').node()
507
507
508 if rename:
508 if rename:
509 if rename not in marks:
509 if rename not in marks:
510 raise util.Abort(_("a bookmark of this name does not exist"))
510 raise util.Abort(_("a bookmark of this name does not exist"))
511 if mark in marks and not force:
511 if mark in marks and not force:
512 raise util.Abort(_("a bookmark of the same name already exists"))
512 raise util.Abort(_("a bookmark of the same name already exists"))
513 if mark is None:
513 if mark is None:
514 raise util.Abort(_("new bookmark name required"))
514 raise util.Abort(_("new bookmark name required"))
515 marks[mark] = marks[rename]
515 marks[mark] = marks[rename]
516 if repo._bookmarkcurrent == rename:
516 if repo._bookmarkcurrent == rename:
517 bookmarks.setcurrent(repo, mark)
517 bookmarks.setcurrent(repo, mark)
518 del marks[rename]
518 del marks[rename]
519 bookmarks.write(repo)
519 bookmarks.write(repo)
520 return
520 return
521
521
522 if delete:
522 if delete:
523 if mark is None:
523 if mark is None:
524 raise util.Abort(_("bookmark name required"))
524 raise util.Abort(_("bookmark name required"))
525 if mark not in marks:
525 if mark not in marks:
526 raise util.Abort(_("a bookmark of this name does not exist"))
526 raise util.Abort(_("a bookmark of this name does not exist"))
527 if mark == repo._bookmarkcurrent:
527 if mark == repo._bookmarkcurrent:
528 bookmarks.setcurrent(repo, None)
528 bookmarks.setcurrent(repo, None)
529 del marks[mark]
529 del marks[mark]
530 bookmarks.write(repo)
530 bookmarks.write(repo)
531 return
531 return
532
532
533 if mark is not None:
533 if mark is not None:
534 if "\n" in mark:
534 if "\n" in mark:
535 raise util.Abort(_("bookmark name cannot contain newlines"))
535 raise util.Abort(_("bookmark name cannot contain newlines"))
536 mark = mark.strip()
536 mark = mark.strip()
537 if not mark:
537 if not mark:
538 raise util.Abort(_("bookmark names cannot consist entirely of "
538 raise util.Abort(_("bookmark names cannot consist entirely of "
539 "whitespace"))
539 "whitespace"))
540 if mark in marks and not force:
540 if mark in marks and not force:
541 raise util.Abort(_("a bookmark of the same name already exists"))
541 raise util.Abort(_("a bookmark of the same name already exists"))
542 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
542 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
543 and not force):
543 and not force):
544 raise util.Abort(
544 raise util.Abort(
545 _("a bookmark cannot have the name of an existing branch"))
545 _("a bookmark cannot have the name of an existing branch"))
546 if rev:
546 if rev:
547 marks[mark] = repo.lookup(rev)
547 marks[mark] = repo.lookup(rev)
548 else:
548 else:
549 marks[mark] = repo.changectx('.').node()
549 marks[mark] = repo.changectx('.').node()
550 if repo.changectx('.').node() == marks[mark]:
550 if repo.changectx('.').node() == marks[mark]:
551 bookmarks.setcurrent(repo, mark)
551 bookmarks.setcurrent(repo, mark)
552 bookmarks.write(repo)
552 bookmarks.write(repo)
553 return
553 return
554
554
555 if mark is None:
555 if mark is None:
556 if rev:
556 if rev:
557 raise util.Abort(_("bookmark name required"))
557 raise util.Abort(_("bookmark name required"))
558 if len(marks) == 0:
558 if len(marks) == 0:
559 ui.status(_("no bookmarks set\n"))
559 ui.status(_("no bookmarks set\n"))
560 else:
560 else:
561 for bmark, n in sorted(marks.iteritems()):
561 for bmark, n in sorted(marks.iteritems()):
562 current = repo._bookmarkcurrent
562 current = repo._bookmarkcurrent
563 if bmark == current and n == cur:
563 if bmark == current and n == cur:
564 prefix, label = '*', 'bookmarks.current'
564 prefix, label = '*', 'bookmarks.current'
565 else:
565 else:
566 prefix, label = ' ', ''
566 prefix, label = ' ', ''
567
567
568 if ui.quiet:
568 if ui.quiet:
569 ui.write("%s\n" % bmark, label=label)
569 ui.write("%s\n" % bmark, label=label)
570 else:
570 else:
571 ui.write(" %s %-25s %d:%s\n" % (
571 ui.write(" %s %-25s %d:%s\n" % (
572 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
572 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
573 label=label)
573 label=label)
574 return
574 return
575
575
576 def branch(ui, repo, label=None, **opts):
576 def branch(ui, repo, label=None, **opts):
577 """set or show the current branch name
577 """set or show the current branch name
578
578
579 With no argument, show the current branch name. With one argument,
579 With no argument, show the current branch name. With one argument,
580 set the working directory branch name (the branch will not exist
580 set the working directory branch name (the branch will not exist
581 in the repository until the next commit). Standard practice
581 in the repository until the next commit). Standard practice
582 recommends that primary development take place on the 'default'
582 recommends that primary development take place on the 'default'
583 branch.
583 branch.
584
584
585 Unless -f/--force is specified, branch will not let you set a
585 Unless -f/--force is specified, branch will not let you set a
586 branch name that already exists, even if it's inactive.
586 branch name that already exists, even if it's inactive.
587
587
588 Use -C/--clean to reset the working directory branch to that of
588 Use -C/--clean to reset the working directory branch to that of
589 the parent of the working directory, negating a previous branch
589 the parent of the working directory, negating a previous branch
590 change.
590 change.
591
591
592 Use the command :hg:`update` to switch to an existing branch. Use
592 Use the command :hg:`update` to switch to an existing branch. Use
593 :hg:`commit --close-branch` to mark this branch as closed.
593 :hg:`commit --close-branch` to mark this branch as closed.
594
594
595 Returns 0 on success.
595 Returns 0 on success.
596 """
596 """
597
597
598 if opts.get('clean'):
598 if opts.get('clean'):
599 label = repo[None].parents()[0].branch()
599 label = repo[None].parents()[0].branch()
600 repo.dirstate.setbranch(label)
600 repo.dirstate.setbranch(label)
601 ui.status(_('reset working directory to branch %s\n') % label)
601 ui.status(_('reset working directory to branch %s\n') % label)
602 elif label:
602 elif label:
603 if not opts.get('force') and label in repo.branchtags():
603 if not opts.get('force') and label in repo.branchtags():
604 if label not in [p.branch() for p in repo.parents()]:
604 if label not in [p.branch() for p in repo.parents()]:
605 raise util.Abort(_('a branch of the same name already exists'
605 raise util.Abort(_('a branch of the same name already exists'
606 " (use 'hg update' to switch to it)"))
606 " (use 'hg update' to switch to it)"))
607 repo.dirstate.setbranch(label)
607 repo.dirstate.setbranch(label)
608 ui.status(_('marked working directory as branch %s\n') % label)
608 ui.status(_('marked working directory as branch %s\n') % label)
609 else:
609 else:
610 ui.write("%s\n" % repo.dirstate.branch())
610 ui.write("%s\n" % repo.dirstate.branch())
611
611
612 def branches(ui, repo, active=False, closed=False):
612 def branches(ui, repo, active=False, closed=False):
613 """list repository named branches
613 """list repository named branches
614
614
615 List the repository's named branches, indicating which ones are
615 List the repository's named branches, indicating which ones are
616 inactive. If -c/--closed is specified, also list branches which have
616 inactive. If -c/--closed is specified, also list branches which have
617 been marked closed (see :hg:`commit --close-branch`).
617 been marked closed (see :hg:`commit --close-branch`).
618
618
619 If -a/--active is specified, only show active branches. A branch
619 If -a/--active is specified, only show active branches. A branch
620 is considered active if it contains repository heads.
620 is considered active if it contains repository heads.
621
621
622 Use the command :hg:`update` to switch to an existing branch.
622 Use the command :hg:`update` to switch to an existing branch.
623
623
624 Returns 0.
624 Returns 0.
625 """
625 """
626
626
627 hexfunc = ui.debugflag and hex or short
627 hexfunc = ui.debugflag and hex or short
628 activebranches = [repo[n].branch() for n in repo.heads()]
628 activebranches = [repo[n].branch() for n in repo.heads()]
629 def testactive(tag, node):
629 def testactive(tag, node):
630 realhead = tag in activebranches
630 realhead = tag in activebranches
631 open = node in repo.branchheads(tag, closed=False)
631 open = node in repo.branchheads(tag, closed=False)
632 return realhead and open
632 return realhead and open
633 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
633 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
634 for tag, node in repo.branchtags().items()],
634 for tag, node in repo.branchtags().items()],
635 reverse=True)
635 reverse=True)
636
636
637 for isactive, node, tag in branches:
637 for isactive, node, tag in branches:
638 if (not active) or isactive:
638 if (not active) or isactive:
639 if ui.quiet:
639 if ui.quiet:
640 ui.write("%s\n" % tag)
640 ui.write("%s\n" % tag)
641 else:
641 else:
642 hn = repo.lookup(node)
642 hn = repo.lookup(node)
643 if isactive:
643 if isactive:
644 label = 'branches.active'
644 label = 'branches.active'
645 notice = ''
645 notice = ''
646 elif hn not in repo.branchheads(tag, closed=False):
646 elif hn not in repo.branchheads(tag, closed=False):
647 if not closed:
647 if not closed:
648 continue
648 continue
649 label = 'branches.closed'
649 label = 'branches.closed'
650 notice = _(' (closed)')
650 notice = _(' (closed)')
651 else:
651 else:
652 label = 'branches.inactive'
652 label = 'branches.inactive'
653 notice = _(' (inactive)')
653 notice = _(' (inactive)')
654 if tag == repo.dirstate.branch():
654 if tag == repo.dirstate.branch():
655 label = 'branches.current'
655 label = 'branches.current'
656 rev = str(node).rjust(31 - encoding.colwidth(tag))
656 rev = str(node).rjust(31 - encoding.colwidth(tag))
657 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
657 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
658 tag = ui.label(tag, label)
658 tag = ui.label(tag, label)
659 ui.write("%s %s%s\n" % (tag, rev, notice))
659 ui.write("%s %s%s\n" % (tag, rev, notice))
660
660
661 def bundle(ui, repo, fname, dest=None, **opts):
661 def bundle(ui, repo, fname, dest=None, **opts):
662 """create a changegroup file
662 """create a changegroup file
663
663
664 Generate a compressed changegroup file collecting changesets not
664 Generate a compressed changegroup file collecting changesets not
665 known to be in another repository.
665 known to be in another repository.
666
666
667 If you omit the destination repository, then hg assumes the
667 If you omit the destination repository, then hg assumes the
668 destination will have all the nodes you specify with --base
668 destination will have all the nodes you specify with --base
669 parameters. To create a bundle containing all changesets, use
669 parameters. To create a bundle containing all changesets, use
670 -a/--all (or --base null).
670 -a/--all (or --base null).
671
671
672 You can change compression method with the -t/--type option.
672 You can change compression method with the -t/--type option.
673 The available compression methods are: none, bzip2, and
673 The available compression methods are: none, bzip2, and
674 gzip (by default, bundles are compressed using bzip2).
674 gzip (by default, bundles are compressed using bzip2).
675
675
676 The bundle file can then be transferred using conventional means
676 The bundle file can then be transferred using conventional means
677 and applied to another repository with the unbundle or pull
677 and applied to another repository with the unbundle or pull
678 command. This is useful when direct push and pull are not
678 command. This is useful when direct push and pull are not
679 available or when exporting an entire repository is undesirable.
679 available or when exporting an entire repository is undesirable.
680
680
681 Applying bundles preserves all changeset contents including
681 Applying bundles preserves all changeset contents including
682 permissions, copy/rename information, and revision history.
682 permissions, copy/rename information, and revision history.
683
683
684 Returns 0 on success, 1 if no changes found.
684 Returns 0 on success, 1 if no changes found.
685 """
685 """
686 revs = None
686 revs = None
687 if 'rev' in opts:
687 if 'rev' in opts:
688 revs = cmdutil.revrange(repo, opts['rev'])
688 revs = cmdutil.revrange(repo, opts['rev'])
689
689
690 if opts.get('all'):
690 if opts.get('all'):
691 base = ['null']
691 base = ['null']
692 else:
692 else:
693 base = cmdutil.revrange(repo, opts.get('base'))
693 base = cmdutil.revrange(repo, opts.get('base'))
694 if base:
694 if base:
695 if dest:
695 if dest:
696 raise util.Abort(_("--base is incompatible with specifying "
696 raise util.Abort(_("--base is incompatible with specifying "
697 "a destination"))
697 "a destination"))
698 base = [repo.lookup(rev) for rev in base]
698 base = [repo.lookup(rev) for rev in base]
699 # create the right base
699 # create the right base
700 # XXX: nodesbetween / changegroup* should be "fixed" instead
700 # XXX: nodesbetween / changegroup* should be "fixed" instead
701 o = []
701 o = []
702 has = set((nullid,))
702 has = set((nullid,))
703 for n in base:
703 for n in base:
704 has.update(repo.changelog.reachable(n))
704 has.update(repo.changelog.reachable(n))
705 if revs:
705 if revs:
706 revs = [repo.lookup(rev) for rev in revs]
706 revs = [repo.lookup(rev) for rev in revs]
707 visit = revs[:]
707 visit = revs[:]
708 has.difference_update(visit)
708 has.difference_update(visit)
709 else:
709 else:
710 visit = repo.changelog.heads()
710 visit = repo.changelog.heads()
711 seen = {}
711 seen = {}
712 while visit:
712 while visit:
713 n = visit.pop(0)
713 n = visit.pop(0)
714 parents = [p for p in repo.changelog.parents(n) if p not in has]
714 parents = [p for p in repo.changelog.parents(n) if p not in has]
715 if len(parents) == 0:
715 if len(parents) == 0:
716 if n not in has:
716 if n not in has:
717 o.append(n)
717 o.append(n)
718 else:
718 else:
719 for p in parents:
719 for p in parents:
720 if p not in seen:
720 if p not in seen:
721 seen[p] = 1
721 seen[p] = 1
722 visit.append(p)
722 visit.append(p)
723 else:
723 else:
724 dest = ui.expandpath(dest or 'default-push', dest or 'default')
724 dest = ui.expandpath(dest or 'default-push', dest or 'default')
725 dest, branches = hg.parseurl(dest, opts.get('branch'))
725 dest, branches = hg.parseurl(dest, opts.get('branch'))
726 other = hg.repository(hg.remoteui(repo, opts), dest)
726 other = hg.repository(hg.remoteui(repo, opts), dest)
727 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
727 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
728 if revs:
728 if revs:
729 revs = [repo.lookup(rev) for rev in revs]
729 revs = [repo.lookup(rev) for rev in revs]
730 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
730 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
731
731
732 if not o:
732 if not o:
733 ui.status(_("no changes found\n"))
733 ui.status(_("no changes found\n"))
734 return 1
734 return 1
735
735
736 if revs:
736 if revs:
737 cg = repo.changegroupsubset(o, revs, 'bundle')
737 cg = repo.changegroupsubset(o, revs, 'bundle')
738 else:
738 else:
739 cg = repo.changegroup(o, 'bundle')
739 cg = repo.changegroup(o, 'bundle')
740
740
741 bundletype = opts.get('type', 'bzip2').lower()
741 bundletype = opts.get('type', 'bzip2').lower()
742 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
742 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
743 bundletype = btypes.get(bundletype)
743 bundletype = btypes.get(bundletype)
744 if bundletype not in changegroup.bundletypes:
744 if bundletype not in changegroup.bundletypes:
745 raise util.Abort(_('unknown bundle type specified with --type'))
745 raise util.Abort(_('unknown bundle type specified with --type'))
746
746
747 changegroup.writebundle(cg, fname, bundletype)
747 changegroup.writebundle(cg, fname, bundletype)
748
748
749 def cat(ui, repo, file1, *pats, **opts):
749 def cat(ui, repo, file1, *pats, **opts):
750 """output the current or given revision of files
750 """output the current or given revision of files
751
751
752 Print the specified files as they were at the given revision. If
752 Print the specified files as they were at the given revision. If
753 no revision is given, the parent of the working directory is used,
753 no revision is given, the parent of the working directory is used,
754 or tip if no revision is checked out.
754 or tip if no revision is checked out.
755
755
756 Output may be to a file, in which case the name of the file is
756 Output may be to a file, in which case the name of the file is
757 given using a format string. The formatting rules are the same as
757 given using a format string. The formatting rules are the same as
758 for the export command, with the following additions:
758 for the export command, with the following additions:
759
759
760 :``%s``: basename of file being printed
760 :``%s``: basename of file being printed
761 :``%d``: dirname of file being printed, or '.' if in repository root
761 :``%d``: dirname of file being printed, or '.' if in repository root
762 :``%p``: root-relative path name of file being printed
762 :``%p``: root-relative path name of file being printed
763
763
764 Returns 0 on success.
764 Returns 0 on success.
765 """
765 """
766 ctx = cmdutil.revsingle(repo, opts.get('rev'))
766 ctx = cmdutil.revsingle(repo, opts.get('rev'))
767 err = 1
767 err = 1
768 m = cmdutil.match(repo, (file1,) + pats, opts)
768 m = cmdutil.match(repo, (file1,) + pats, opts)
769 for abs in ctx.walk(m):
769 for abs in ctx.walk(m):
770 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
770 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
771 data = ctx[abs].data()
771 data = ctx[abs].data()
772 if opts.get('decode'):
772 if opts.get('decode'):
773 data = repo.wwritedata(abs, data)
773 data = repo.wwritedata(abs, data)
774 fp.write(data)
774 fp.write(data)
775 fp.close()
775 fp.close()
776 err = 0
776 err = 0
777 return err
777 return err
778
778
779 def clone(ui, source, dest=None, **opts):
779 def clone(ui, source, dest=None, **opts):
780 """make a copy of an existing repository
780 """make a copy of an existing repository
781
781
782 Create a copy of an existing repository in a new directory.
782 Create a copy of an existing repository in a new directory.
783
783
784 If no destination directory name is specified, it defaults to the
784 If no destination directory name is specified, it defaults to the
785 basename of the source.
785 basename of the source.
786
786
787 The location of the source is added to the new repository's
787 The location of the source is added to the new repository's
788 ``.hg/hgrc`` file, as the default to be used for future pulls.
788 ``.hg/hgrc`` file, as the default to be used for future pulls.
789
789
790 See :hg:`help urls` for valid source format details.
790 See :hg:`help urls` for valid source format details.
791
791
792 It is possible to specify an ``ssh://`` URL as the destination, but no
792 It is possible to specify an ``ssh://`` URL as the destination, but no
793 ``.hg/hgrc`` and working directory will be created on the remote side.
793 ``.hg/hgrc`` and working directory will be created on the remote side.
794 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
794 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
795
795
796 A set of changesets (tags, or branch names) to pull may be specified
796 A set of changesets (tags, or branch names) to pull may be specified
797 by listing each changeset (tag, or branch name) with -r/--rev.
797 by listing each changeset (tag, or branch name) with -r/--rev.
798 If -r/--rev is used, the cloned repository will contain only a subset
798 If -r/--rev is used, the cloned repository will contain only a subset
799 of the changesets of the source repository. Only the set of changesets
799 of the changesets of the source repository. Only the set of changesets
800 defined by all -r/--rev options (including all their ancestors)
800 defined by all -r/--rev options (including all their ancestors)
801 will be pulled into the destination repository.
801 will be pulled into the destination repository.
802 No subsequent changesets (including subsequent tags) will be present
802 No subsequent changesets (including subsequent tags) will be present
803 in the destination.
803 in the destination.
804
804
805 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
805 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
806 local source repositories.
806 local source repositories.
807
807
808 For efficiency, hardlinks are used for cloning whenever the source
808 For efficiency, hardlinks are used for cloning whenever the source
809 and destination are on the same filesystem (note this applies only
809 and destination are on the same filesystem (note this applies only
810 to the repository data, not to the working directory). Some
810 to the repository data, not to the working directory). Some
811 filesystems, such as AFS, implement hardlinking incorrectly, but
811 filesystems, such as AFS, implement hardlinking incorrectly, but
812 do not report errors. In these cases, use the --pull option to
812 do not report errors. In these cases, use the --pull option to
813 avoid hardlinking.
813 avoid hardlinking.
814
814
815 In some cases, you can clone repositories and the working directory
815 In some cases, you can clone repositories and the working directory
816 using full hardlinks with ::
816 using full hardlinks with ::
817
817
818 $ cp -al REPO REPOCLONE
818 $ cp -al REPO REPOCLONE
819
819
820 This is the fastest way to clone, but it is not always safe. The
820 This is the fastest way to clone, but it is not always safe. The
821 operation is not atomic (making sure REPO is not modified during
821 operation is not atomic (making sure REPO is not modified during
822 the operation is up to you) and you have to make sure your editor
822 the operation is up to you) and you have to make sure your editor
823 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
823 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
824 this is not compatible with certain extensions that place their
824 this is not compatible with certain extensions that place their
825 metadata under the .hg directory, such as mq.
825 metadata under the .hg directory, such as mq.
826
826
827 Mercurial will update the working directory to the first applicable
827 Mercurial will update the working directory to the first applicable
828 revision from this list:
828 revision from this list:
829
829
830 a) null if -U or the source repository has no changesets
830 a) null if -U or the source repository has no changesets
831 b) if -u . and the source repository is local, the first parent of
831 b) if -u . and the source repository is local, the first parent of
832 the source repository's working directory
832 the source repository's working directory
833 c) the changeset specified with -u (if a branch name, this means the
833 c) the changeset specified with -u (if a branch name, this means the
834 latest head of that branch)
834 latest head of that branch)
835 d) the changeset specified with -r
835 d) the changeset specified with -r
836 e) the tipmost head specified with -b
836 e) the tipmost head specified with -b
837 f) the tipmost head specified with the url#branch source syntax
837 f) the tipmost head specified with the url#branch source syntax
838 g) the tipmost head of the default branch
838 g) the tipmost head of the default branch
839 h) tip
839 h) tip
840
840
841 Returns 0 on success.
841 Returns 0 on success.
842 """
842 """
843 if opts.get('noupdate') and opts.get('updaterev'):
843 if opts.get('noupdate') and opts.get('updaterev'):
844 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
844 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
845
845
846 r = hg.clone(hg.remoteui(ui, opts), source, dest,
846 r = hg.clone(hg.remoteui(ui, opts), source, dest,
847 pull=opts.get('pull'),
847 pull=opts.get('pull'),
848 stream=opts.get('uncompressed'),
848 stream=opts.get('uncompressed'),
849 rev=opts.get('rev'),
849 rev=opts.get('rev'),
850 update=opts.get('updaterev') or not opts.get('noupdate'),
850 update=opts.get('updaterev') or not opts.get('noupdate'),
851 branch=opts.get('branch'))
851 branch=opts.get('branch'))
852
852
853 return r is None
853 return r is None
854
854
855 def commit(ui, repo, *pats, **opts):
855 def commit(ui, repo, *pats, **opts):
856 """commit the specified files or all outstanding changes
856 """commit the specified files or all outstanding changes
857
857
858 Commit changes to the given files into the repository. Unlike a
858 Commit changes to the given files into the repository. Unlike a
859 centralized SCM, this operation is a local operation. See
859 centralized SCM, this operation is a local operation. See
860 :hg:`push` for a way to actively distribute your changes.
860 :hg:`push` for a way to actively distribute your changes.
861
861
862 If a list of files is omitted, all changes reported by :hg:`status`
862 If a list of files is omitted, all changes reported by :hg:`status`
863 will be committed.
863 will be committed.
864
864
865 If you are committing the result of a merge, do not provide any
865 If you are committing the result of a merge, do not provide any
866 filenames or -I/-X filters.
866 filenames or -I/-X filters.
867
867
868 If no commit message is specified, Mercurial starts your
868 If no commit message is specified, Mercurial starts your
869 configured editor where you can enter a message. In case your
869 configured editor where you can enter a message. In case your
870 commit fails, you will find a backup of your message in
870 commit fails, you will find a backup of your message in
871 ``.hg/last-message.txt``.
871 ``.hg/last-message.txt``.
872
872
873 See :hg:`help dates` for a list of formats valid for -d/--date.
873 See :hg:`help dates` for a list of formats valid for -d/--date.
874
874
875 Returns 0 on success, 1 if nothing changed.
875 Returns 0 on success, 1 if nothing changed.
876 """
876 """
877 extra = {}
877 extra = {}
878 if opts.get('close_branch'):
878 if opts.get('close_branch'):
879 if repo['.'].node() not in repo.branchheads():
879 if repo['.'].node() not in repo.branchheads():
880 # The topo heads set is included in the branch heads set of the
880 # The topo heads set is included in the branch heads set of the
881 # current branch, so it's sufficient to test branchheads
881 # current branch, so it's sufficient to test branchheads
882 raise util.Abort(_('can only close branch heads'))
882 raise util.Abort(_('can only close branch heads'))
883 extra['close'] = 1
883 extra['close'] = 1
884 e = cmdutil.commiteditor
884 e = cmdutil.commiteditor
885 if opts.get('force_editor'):
885 if opts.get('force_editor'):
886 e = cmdutil.commitforceeditor
886 e = cmdutil.commitforceeditor
887
887
888 def commitfunc(ui, repo, message, match, opts):
888 def commitfunc(ui, repo, message, match, opts):
889 return repo.commit(message, opts.get('user'), opts.get('date'), match,
889 return repo.commit(message, opts.get('user'), opts.get('date'), match,
890 editor=e, extra=extra)
890 editor=e, extra=extra)
891
891
892 branch = repo[None].branch()
892 branch = repo[None].branch()
893 bheads = repo.branchheads(branch)
893 bheads = repo.branchheads(branch)
894
894
895 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
895 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
896 if not node:
896 if not node:
897 ui.status(_("nothing changed\n"))
897 ui.status(_("nothing changed\n"))
898 return 1
898 return 1
899
899
900 ctx = repo[node]
900 ctx = repo[node]
901 parents = ctx.parents()
901 parents = ctx.parents()
902
902
903 if bheads and not [x for x in parents
903 if bheads and not [x for x in parents
904 if x.node() in bheads and x.branch() == branch]:
904 if x.node() in bheads and x.branch() == branch]:
905 ui.status(_('created new head\n'))
905 ui.status(_('created new head\n'))
906 # The message is not printed for initial roots. For the other
906 # The message is not printed for initial roots. For the other
907 # changesets, it is printed in the following situations:
907 # changesets, it is printed in the following situations:
908 #
908 #
909 # Par column: for the 2 parents with ...
909 # Par column: for the 2 parents with ...
910 # N: null or no parent
910 # N: null or no parent
911 # B: parent is on another named branch
911 # B: parent is on another named branch
912 # C: parent is a regular non head changeset
912 # C: parent is a regular non head changeset
913 # H: parent was a branch head of the current branch
913 # H: parent was a branch head of the current branch
914 # Msg column: whether we print "created new head" message
914 # Msg column: whether we print "created new head" message
915 # In the following, it is assumed that there already exists some
915 # In the following, it is assumed that there already exists some
916 # initial branch heads of the current branch, otherwise nothing is
916 # initial branch heads of the current branch, otherwise nothing is
917 # printed anyway.
917 # printed anyway.
918 #
918 #
919 # Par Msg Comment
919 # Par Msg Comment
920 # NN y additional topo root
920 # NN y additional topo root
921 #
921 #
922 # BN y additional branch root
922 # BN y additional branch root
923 # CN y additional topo head
923 # CN y additional topo head
924 # HN n usual case
924 # HN n usual case
925 #
925 #
926 # BB y weird additional branch root
926 # BB y weird additional branch root
927 # CB y branch merge
927 # CB y branch merge
928 # HB n merge with named branch
928 # HB n merge with named branch
929 #
929 #
930 # CC y additional head from merge
930 # CC y additional head from merge
931 # CH n merge with a head
931 # CH n merge with a head
932 #
932 #
933 # HH n head merge: head count decreases
933 # HH n head merge: head count decreases
934
934
935 if not opts.get('close_branch'):
935 if not opts.get('close_branch'):
936 for r in parents:
936 for r in parents:
937 if r.extra().get('close') and r.branch() == branch:
937 if r.extra().get('close') and r.branch() == branch:
938 ui.status(_('reopening closed branch head %d\n') % r)
938 ui.status(_('reopening closed branch head %d\n') % r)
939
939
940 if ui.debugflag:
940 if ui.debugflag:
941 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
941 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
942 elif ui.verbose:
942 elif ui.verbose:
943 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
943 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
944
944
945 def copy(ui, repo, *pats, **opts):
945 def copy(ui, repo, *pats, **opts):
946 """mark files as copied for the next commit
946 """mark files as copied for the next commit
947
947
948 Mark dest as having copies of source files. If dest is a
948 Mark dest as having copies of source files. If dest is a
949 directory, copies are put in that directory. If dest is a file,
949 directory, copies are put in that directory. If dest is a file,
950 the source must be a single file.
950 the source must be a single file.
951
951
952 By default, this command copies the contents of files as they
952 By default, this command copies the contents of files as they
953 exist in the working directory. If invoked with -A/--after, the
953 exist in the working directory. If invoked with -A/--after, the
954 operation is recorded, but no copying is performed.
954 operation is recorded, but no copying is performed.
955
955
956 This command takes effect with the next commit. To undo a copy
956 This command takes effect with the next commit. To undo a copy
957 before that, see :hg:`revert`.
957 before that, see :hg:`revert`.
958
958
959 Returns 0 on success, 1 if errors are encountered.
959 Returns 0 on success, 1 if errors are encountered.
960 """
960 """
961 wlock = repo.wlock(False)
961 wlock = repo.wlock(False)
962 try:
962 try:
963 return cmdutil.copy(ui, repo, pats, opts)
963 return cmdutil.copy(ui, repo, pats, opts)
964 finally:
964 finally:
965 wlock.release()
965 wlock.release()
966
966
967 def debugancestor(ui, repo, *args):
967 def debugancestor(ui, repo, *args):
968 """find the ancestor revision of two revisions in a given index"""
968 """find the ancestor revision of two revisions in a given index"""
969 if len(args) == 3:
969 if len(args) == 3:
970 index, rev1, rev2 = args
970 index, rev1, rev2 = args
971 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
971 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
972 lookup = r.lookup
972 lookup = r.lookup
973 elif len(args) == 2:
973 elif len(args) == 2:
974 if not repo:
974 if not repo:
975 raise util.Abort(_("there is no Mercurial repository here "
975 raise util.Abort(_("there is no Mercurial repository here "
976 "(.hg not found)"))
976 "(.hg not found)"))
977 rev1, rev2 = args
977 rev1, rev2 = args
978 r = repo.changelog
978 r = repo.changelog
979 lookup = repo.lookup
979 lookup = repo.lookup
980 else:
980 else:
981 raise util.Abort(_('either two or three arguments required'))
981 raise util.Abort(_('either two or three arguments required'))
982 a = r.ancestor(lookup(rev1), lookup(rev2))
982 a = r.ancestor(lookup(rev1), lookup(rev2))
983 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
983 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
984
984
985 def debugbuilddag(ui, repo, text,
985 def debugbuilddag(ui, repo, text,
986 mergeable_file=False,
986 mergeable_file=False,
987 appended_file=False,
987 appended_file=False,
988 overwritten_file=False,
988 overwritten_file=False,
989 new_file=False):
989 new_file=False):
990 """builds a repo with a given dag from scratch in the current empty repo
990 """builds a repo with a given dag from scratch in the current empty repo
991
991
992 Elements:
992 Elements:
993
993
994 - "+n" is a linear run of n nodes based on the current default parent
994 - "+n" is a linear run of n nodes based on the current default parent
995 - "." is a single node based on the current default parent
995 - "." is a single node based on the current default parent
996 - "$" resets the default parent to null (implied at the start);
996 - "$" resets the default parent to null (implied at the start);
997 otherwise the default parent is always the last node created
997 otherwise the default parent is always the last node created
998 - "<p" sets the default parent to the backref p
998 - "<p" sets the default parent to the backref p
999 - "*p" is a fork at parent p, which is a backref
999 - "*p" is a fork at parent p, which is a backref
1000 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1000 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1001 - "/p2" is a merge of the preceding node and p2
1001 - "/p2" is a merge of the preceding node and p2
1002 - ":tag" defines a local tag for the preceding node
1002 - ":tag" defines a local tag for the preceding node
1003 - "@branch" sets the named branch for subsequent nodes
1003 - "@branch" sets the named branch for subsequent nodes
1004 - "!command" runs the command using your shell
1004 - "!command" runs the command using your shell
1005 - "!!my command\\n" is like "!", but to the end of the line
1005 - "!!my command\\n" is like "!", but to the end of the line
1006 - "#...\\n" is a comment up to the end of the line
1006 - "#...\\n" is a comment up to the end of the line
1007
1007
1008 Whitespace between the above elements is ignored.
1008 Whitespace between the above elements is ignored.
1009
1009
1010 A backref is either
1010 A backref is either
1011
1011
1012 - a number n, which references the node curr-n, where curr is the current
1012 - a number n, which references the node curr-n, where curr is the current
1013 node, or
1013 node, or
1014 - the name of a local tag you placed earlier using ":tag", or
1014 - the name of a local tag you placed earlier using ":tag", or
1015 - empty to denote the default parent.
1015 - empty to denote the default parent.
1016
1016
1017 All string valued-elements are either strictly alphanumeric, or must
1017 All string valued-elements are either strictly alphanumeric, or must
1018 be enclosed in double quotes ("..."), with "\\" as escape character.
1018 be enclosed in double quotes ("..."), with "\\" as escape character.
1019
1019
1020 Note that the --overwritten-file and --appended-file options imply the
1020 Note that the --overwritten-file and --appended-file options imply the
1021 use of "HGMERGE=internal:local" during DAG buildup.
1021 use of "HGMERGE=internal:local" during DAG buildup.
1022 """
1022 """
1023
1023
1024 if not (mergeable_file or appended_file or overwritten_file or new_file):
1024 if not (mergeable_file or appended_file or overwritten_file or new_file):
1025 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
1025 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
1026
1026
1027 if len(repo.changelog) > 0:
1027 if len(repo.changelog) > 0:
1028 raise util.Abort(_('repository is not empty'))
1028 raise util.Abort(_('repository is not empty'))
1029
1029
1030 if overwritten_file or appended_file:
1030 if overwritten_file or appended_file:
1031 # we don't want to fail in merges during buildup
1031 # we don't want to fail in merges during buildup
1032 os.environ['HGMERGE'] = 'internal:local'
1032 os.environ['HGMERGE'] = 'internal:local'
1033
1033
1034 def writefile(fname, text, fmode="wb"):
1034 def writefile(fname, text, fmode="wb"):
1035 f = open(fname, fmode)
1035 f = open(fname, fmode)
1036 try:
1036 try:
1037 f.write(text)
1037 f.write(text)
1038 finally:
1038 finally:
1039 f.close()
1039 f.close()
1040
1040
1041 if mergeable_file:
1041 if mergeable_file:
1042 linesperrev = 2
1042 linesperrev = 2
1043 # determine number of revs in DAG
1043 # determine number of revs in DAG
1044 n = 0
1044 n = 0
1045 for type, data in dagparser.parsedag(text):
1045 for type, data in dagparser.parsedag(text):
1046 if type == 'n':
1046 if type == 'n':
1047 n += 1
1047 n += 1
1048 # make a file with k lines per rev
1048 # make a file with k lines per rev
1049 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1049 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1050 + "\n")
1050 + "\n")
1051
1051
1052 at = -1
1052 at = -1
1053 atbranch = 'default'
1053 atbranch = 'default'
1054 for type, data in dagparser.parsedag(text):
1054 for type, data in dagparser.parsedag(text):
1055 if type == 'n':
1055 if type == 'n':
1056 ui.status('node %s\n' % str(data))
1056 ui.status('node %s\n' % str(data))
1057 id, ps = data
1057 id, ps = data
1058 p1 = ps[0]
1058 p1 = ps[0]
1059 if p1 != at:
1059 if p1 != at:
1060 update(ui, repo, node=str(p1), clean=True)
1060 update(ui, repo, node=str(p1), clean=True)
1061 at = p1
1061 at = p1
1062 if repo.dirstate.branch() != atbranch:
1062 if repo.dirstate.branch() != atbranch:
1063 branch(ui, repo, atbranch, force=True)
1063 branch(ui, repo, atbranch, force=True)
1064 if len(ps) > 1:
1064 if len(ps) > 1:
1065 p2 = ps[1]
1065 p2 = ps[1]
1066 merge(ui, repo, node=p2)
1066 merge(ui, repo, node=p2)
1067
1067
1068 if mergeable_file:
1068 if mergeable_file:
1069 f = open("mf", "rb+")
1069 f = open("mf", "rb+")
1070 try:
1070 try:
1071 lines = f.read().split("\n")
1071 lines = f.read().split("\n")
1072 lines[id * linesperrev] += " r%i" % id
1072 lines[id * linesperrev] += " r%i" % id
1073 f.seek(0)
1073 f.seek(0)
1074 f.write("\n".join(lines))
1074 f.write("\n".join(lines))
1075 finally:
1075 finally:
1076 f.close()
1076 f.close()
1077
1077
1078 if appended_file:
1078 if appended_file:
1079 writefile("af", "r%i\n" % id, "ab")
1079 writefile("af", "r%i\n" % id, "ab")
1080
1080
1081 if overwritten_file:
1081 if overwritten_file:
1082 writefile("of", "r%i\n" % id)
1082 writefile("of", "r%i\n" % id)
1083
1083
1084 if new_file:
1084 if new_file:
1085 writefile("nf%i" % id, "r%i\n" % id)
1085 writefile("nf%i" % id, "r%i\n" % id)
1086
1086
1087 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1087 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1088 at = id
1088 at = id
1089 elif type == 'l':
1089 elif type == 'l':
1090 id, name = data
1090 id, name = data
1091 ui.status('tag %s\n' % name)
1091 ui.status('tag %s\n' % name)
1092 tag(ui, repo, name, local=True)
1092 tag(ui, repo, name, local=True)
1093 elif type == 'a':
1093 elif type == 'a':
1094 ui.status('branch %s\n' % data)
1094 ui.status('branch %s\n' % data)
1095 atbranch = data
1095 atbranch = data
1096 elif type in 'cC':
1096 elif type in 'cC':
1097 r = util.system(data, cwd=repo.root)
1097 r = util.system(data, cwd=repo.root)
1098 if r:
1098 if r:
1099 desc, r = util.explain_exit(r)
1099 desc, r = util.explain_exit(r)
1100 raise util.Abort(_('%s command %s') % (data, desc))
1100 raise util.Abort(_('%s command %s') % (data, desc))
1101
1101
1102 def debugcommands(ui, cmd='', *args):
1102 def debugcommands(ui, cmd='', *args):
1103 """list all available commands and options"""
1103 """list all available commands and options"""
1104 for cmd, vals in sorted(table.iteritems()):
1104 for cmd, vals in sorted(table.iteritems()):
1105 cmd = cmd.split('|')[0].strip('^')
1105 cmd = cmd.split('|')[0].strip('^')
1106 opts = ', '.join([i[1] for i in vals[1]])
1106 opts = ', '.join([i[1] for i in vals[1]])
1107 ui.write('%s: %s\n' % (cmd, opts))
1107 ui.write('%s: %s\n' % (cmd, opts))
1108
1108
1109 def debugcomplete(ui, cmd='', **opts):
1109 def debugcomplete(ui, cmd='', **opts):
1110 """returns the completion list associated with the given command"""
1110 """returns the completion list associated with the given command"""
1111
1111
1112 if opts.get('options'):
1112 if opts.get('options'):
1113 options = []
1113 options = []
1114 otables = [globalopts]
1114 otables = [globalopts]
1115 if cmd:
1115 if cmd:
1116 aliases, entry = cmdutil.findcmd(cmd, table, False)
1116 aliases, entry = cmdutil.findcmd(cmd, table, False)
1117 otables.append(entry[1])
1117 otables.append(entry[1])
1118 for t in otables:
1118 for t in otables:
1119 for o in t:
1119 for o in t:
1120 if "(DEPRECATED)" in o[3]:
1120 if "(DEPRECATED)" in o[3]:
1121 continue
1121 continue
1122 if o[0]:
1122 if o[0]:
1123 options.append('-%s' % o[0])
1123 options.append('-%s' % o[0])
1124 options.append('--%s' % o[1])
1124 options.append('--%s' % o[1])
1125 ui.write("%s\n" % "\n".join(options))
1125 ui.write("%s\n" % "\n".join(options))
1126 return
1126 return
1127
1127
1128 cmdlist = cmdutil.findpossible(cmd, table)
1128 cmdlist = cmdutil.findpossible(cmd, table)
1129 if ui.verbose:
1129 if ui.verbose:
1130 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1130 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1131 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1131 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1132
1132
1133 def debugfsinfo(ui, path = "."):
1133 def debugfsinfo(ui, path = "."):
1134 """show information detected about current filesystem"""
1134 """show information detected about current filesystem"""
1135 open('.debugfsinfo', 'w').write('')
1135 open('.debugfsinfo', 'w').write('')
1136 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1136 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1137 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1137 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1138 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1138 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1139 and 'yes' or 'no'))
1139 and 'yes' or 'no'))
1140 os.unlink('.debugfsinfo')
1140 os.unlink('.debugfsinfo')
1141
1141
1142 def debugrebuildstate(ui, repo, rev="tip"):
1142 def debugrebuildstate(ui, repo, rev="tip"):
1143 """rebuild the dirstate as it would look like for the given revision"""
1143 """rebuild the dirstate as it would look like for the given revision"""
1144 ctx = cmdutil.revsingle(repo, rev)
1144 ctx = cmdutil.revsingle(repo, rev)
1145 wlock = repo.wlock()
1145 wlock = repo.wlock()
1146 try:
1146 try:
1147 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1147 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1148 finally:
1148 finally:
1149 wlock.release()
1149 wlock.release()
1150
1150
1151 def debugcheckstate(ui, repo):
1151 def debugcheckstate(ui, repo):
1152 """validate the correctness of the current dirstate"""
1152 """validate the correctness of the current dirstate"""
1153 parent1, parent2 = repo.dirstate.parents()
1153 parent1, parent2 = repo.dirstate.parents()
1154 m1 = repo[parent1].manifest()
1154 m1 = repo[parent1].manifest()
1155 m2 = repo[parent2].manifest()
1155 m2 = repo[parent2].manifest()
1156 errors = 0
1156 errors = 0
1157 for f in repo.dirstate:
1157 for f in repo.dirstate:
1158 state = repo.dirstate[f]
1158 state = repo.dirstate[f]
1159 if state in "nr" and f not in m1:
1159 if state in "nr" and f not in m1:
1160 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1160 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1161 errors += 1
1161 errors += 1
1162 if state in "a" and f in m1:
1162 if state in "a" and f in m1:
1163 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1163 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1164 errors += 1
1164 errors += 1
1165 if state in "m" and f not in m1 and f not in m2:
1165 if state in "m" and f not in m1 and f not in m2:
1166 ui.warn(_("%s in state %s, but not in either manifest\n") %
1166 ui.warn(_("%s in state %s, but not in either manifest\n") %
1167 (f, state))
1167 (f, state))
1168 errors += 1
1168 errors += 1
1169 for f in m1:
1169 for f in m1:
1170 state = repo.dirstate[f]
1170 state = repo.dirstate[f]
1171 if state not in "nrm":
1171 if state not in "nrm":
1172 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1172 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1173 errors += 1
1173 errors += 1
1174 if errors:
1174 if errors:
1175 error = _(".hg/dirstate inconsistent with current parent's manifest")
1175 error = _(".hg/dirstate inconsistent with current parent's manifest")
1176 raise util.Abort(error)
1176 raise util.Abort(error)
1177
1177
1178 def showconfig(ui, repo, *values, **opts):
1178 def showconfig(ui, repo, *values, **opts):
1179 """show combined config settings from all hgrc files
1179 """show combined config settings from all hgrc files
1180
1180
1181 With no arguments, print names and values of all config items.
1181 With no arguments, print names and values of all config items.
1182
1182
1183 With one argument of the form section.name, print just the value
1183 With one argument of the form section.name, print just the value
1184 of that config item.
1184 of that config item.
1185
1185
1186 With multiple arguments, print names and values of all config
1186 With multiple arguments, print names and values of all config
1187 items with matching section names.
1187 items with matching section names.
1188
1188
1189 With --debug, the source (filename and line number) is printed
1189 With --debug, the source (filename and line number) is printed
1190 for each config item.
1190 for each config item.
1191
1191
1192 Returns 0 on success.
1192 Returns 0 on success.
1193 """
1193 """
1194
1194
1195 for f in util.rcpath():
1195 for f in util.rcpath():
1196 ui.debug(_('read config from: %s\n') % f)
1196 ui.debug(_('read config from: %s\n') % f)
1197 untrusted = bool(opts.get('untrusted'))
1197 untrusted = bool(opts.get('untrusted'))
1198 if values:
1198 if values:
1199 sections = [v for v in values if '.' not in v]
1199 sections = [v for v in values if '.' not in v]
1200 items = [v for v in values if '.' in v]
1200 items = [v for v in values if '.' in v]
1201 if len(items) > 1 or items and sections:
1201 if len(items) > 1 or items and sections:
1202 raise util.Abort(_('only one config item permitted'))
1202 raise util.Abort(_('only one config item permitted'))
1203 for section, name, value in ui.walkconfig(untrusted=untrusted):
1203 for section, name, value in ui.walkconfig(untrusted=untrusted):
1204 value = str(value).replace('\n', '\\n')
1204 value = str(value).replace('\n', '\\n')
1205 sectname = section + '.' + name
1205 sectname = section + '.' + name
1206 if values:
1206 if values:
1207 for v in values:
1207 for v in values:
1208 if v == section:
1208 if v == section:
1209 ui.debug('%s: ' %
1209 ui.debug('%s: ' %
1210 ui.configsource(section, name, untrusted))
1210 ui.configsource(section, name, untrusted))
1211 ui.write('%s=%s\n' % (sectname, value))
1211 ui.write('%s=%s\n' % (sectname, value))
1212 elif v == sectname:
1212 elif v == sectname:
1213 ui.debug('%s: ' %
1213 ui.debug('%s: ' %
1214 ui.configsource(section, name, untrusted))
1214 ui.configsource(section, name, untrusted))
1215 ui.write(value, '\n')
1215 ui.write(value, '\n')
1216 else:
1216 else:
1217 ui.debug('%s: ' %
1217 ui.debug('%s: ' %
1218 ui.configsource(section, name, untrusted))
1218 ui.configsource(section, name, untrusted))
1219 ui.write('%s=%s\n' % (sectname, value))
1219 ui.write('%s=%s\n' % (sectname, value))
1220
1220
1221 def debugknown(ui, repopath, *ids, **opts):
1221 def debugknown(ui, repopath, *ids, **opts):
1222 """test whether node ids are known to a repo
1222 """test whether node ids are known to a repo
1223
1223
1224 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1224 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1225 indicating unknown/known.
1225 indicating unknown/known.
1226 """
1226 """
1227 repo = hg.repository(ui, repopath)
1227 repo = hg.repository(ui, repopath)
1228 if not repo.capable('known'):
1228 if not repo.capable('known'):
1229 raise util.Abort("known() not supported by target repository")
1229 raise util.Abort("known() not supported by target repository")
1230 flags = repo.known([bin(s) for s in ids])
1230 flags = repo.known([bin(s) for s in ids])
1231 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1231 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1232
1232
1233 def debugbundle(ui, bundlepath, all=None, **opts):
1233 def debugbundle(ui, bundlepath, all=None, **opts):
1234 """lists the contents of a bundle"""
1234 """lists the contents of a bundle"""
1235 f = url.open(ui, bundlepath)
1235 f = url.open(ui, bundlepath)
1236 try:
1236 try:
1237 gen = changegroup.readbundle(f, bundlepath)
1237 gen = changegroup.readbundle(f, bundlepath)
1238 if all:
1238 if all:
1239 ui.write("format: id, p1, p2, cset, len(delta)\n")
1239 ui.write("format: id, p1, p2, cset, len(delta)\n")
1240
1240
1241 def showchunks(named):
1241 def showchunks(named):
1242 ui.write("\n%s\n" % named)
1242 ui.write("\n%s\n" % named)
1243 while 1:
1244 chunkdata = gen.parsechunk()
1245 if not chunkdata:
1246 break
1247 node = chunkdata['node']
1248 p1 = chunkdata['p1']
1249 p2 = chunkdata['p2']
1250 cs = chunkdata['cs']
1251 delta = chunkdata['data']
1252 ui.write("%s %s %s %s %s\n" %
1253 (hex(node), hex(p1), hex(p2),
1254 hex(cs), len(delta)))
1255
1256 showchunks("changelog")
1257 showchunks("manifest")
1258 while 1:
1259 fname = gen.chunk()
1260 if not fname:
1261 break
1262 showchunks(fname)
1263 else:
1264 while 1:
1243 while 1:
1265 chunkdata = gen.parsechunk()
1244 chunkdata = gen.parsechunk()
1266 if not chunkdata:
1245 if not chunkdata:
1267 break
1246 break
1268 node = chunkdata['node']
1247 node = chunkdata['node']
1269 ui.write("%s\n" % hex(node))
1248 p1 = chunkdata['p1']
1249 p2 = chunkdata['p2']
1250 cs = chunkdata['cs']
1251 delta = chunkdata['data']
1252 ui.write("%s %s %s %s %s\n" %
1253 (hex(node), hex(p1), hex(p2),
1254 hex(cs), len(delta)))
1255
1256 showchunks("changelog")
1257 showchunks("manifest")
1258 while 1:
1259 fname = gen.chunk()
1260 if not fname:
1261 break
1262 showchunks(fname)
1263 else:
1264 while 1:
1265 chunkdata = gen.parsechunk()
1266 if not chunkdata:
1267 break
1268 node = chunkdata['node']
1269 ui.write("%s\n" % hex(node))
1270 finally:
1270 finally:
1271 f.close()
1271 f.close()
1272
1272
1273 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1273 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1274 """retrieves a bundle from a repo
1274 """retrieves a bundle from a repo
1275
1275
1276 Every ID must be a full-length hex node id string. Saves the bundle to the
1276 Every ID must be a full-length hex node id string. Saves the bundle to the
1277 given file.
1277 given file.
1278 """
1278 """
1279 repo = hg.repository(ui, repopath)
1279 repo = hg.repository(ui, repopath)
1280 if not repo.capable('getbundle'):
1280 if not repo.capable('getbundle'):
1281 raise util.Abort("getbundle() not supported by target repository")
1281 raise util.Abort("getbundle() not supported by target repository")
1282 args = {}
1282 args = {}
1283 if common:
1283 if common:
1284 args['common'] = [bin(s) for s in common]
1284 args['common'] = [bin(s) for s in common]
1285 if head:
1285 if head:
1286 args['heads'] = [bin(s) for s in head]
1286 args['heads'] = [bin(s) for s in head]
1287 bundle = repo.getbundle('debug', **args)
1287 bundle = repo.getbundle('debug', **args)
1288
1288
1289 bundletype = opts.get('type', 'bzip2').lower()
1289 bundletype = opts.get('type', 'bzip2').lower()
1290 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1290 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1291 bundletype = btypes.get(bundletype)
1291 bundletype = btypes.get(bundletype)
1292 if bundletype not in changegroup.bundletypes:
1292 if bundletype not in changegroup.bundletypes:
1293 raise util.Abort(_('unknown bundle type specified with --type'))
1293 raise util.Abort(_('unknown bundle type specified with --type'))
1294 changegroup.writebundle(bundle, bundlepath, bundletype)
1294 changegroup.writebundle(bundle, bundlepath, bundletype)
1295
1295
1296 def debugpushkey(ui, repopath, namespace, *keyinfo):
1296 def debugpushkey(ui, repopath, namespace, *keyinfo):
1297 '''access the pushkey key/value protocol
1297 '''access the pushkey key/value protocol
1298
1298
1299 With two args, list the keys in the given namespace.
1299 With two args, list the keys in the given namespace.
1300
1300
1301 With five args, set a key to new if it currently is set to old.
1301 With five args, set a key to new if it currently is set to old.
1302 Reports success or failure.
1302 Reports success or failure.
1303 '''
1303 '''
1304
1304
1305 target = hg.repository(ui, repopath)
1305 target = hg.repository(ui, repopath)
1306 if keyinfo:
1306 if keyinfo:
1307 key, old, new = keyinfo
1307 key, old, new = keyinfo
1308 r = target.pushkey(namespace, key, old, new)
1308 r = target.pushkey(namespace, key, old, new)
1309 ui.status(str(r) + '\n')
1309 ui.status(str(r) + '\n')
1310 return not r
1310 return not r
1311 else:
1311 else:
1312 for k, v in target.listkeys(namespace).iteritems():
1312 for k, v in target.listkeys(namespace).iteritems():
1313 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1313 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1314 v.encode('string-escape')))
1314 v.encode('string-escape')))
1315
1315
1316 def debugrevspec(ui, repo, expr):
1316 def debugrevspec(ui, repo, expr):
1317 '''parse and apply a revision specification'''
1317 '''parse and apply a revision specification'''
1318 if ui.verbose:
1318 if ui.verbose:
1319 tree = revset.parse(expr)[0]
1319 tree = revset.parse(expr)[0]
1320 ui.note(tree, "\n")
1320 ui.note(tree, "\n")
1321 func = revset.match(expr)
1321 func = revset.match(expr)
1322 for c in func(repo, range(len(repo))):
1322 for c in func(repo, range(len(repo))):
1323 ui.write("%s\n" % c)
1323 ui.write("%s\n" % c)
1324
1324
1325 def debugsetparents(ui, repo, rev1, rev2=None):
1325 def debugsetparents(ui, repo, rev1, rev2=None):
1326 """manually set the parents of the current working directory
1326 """manually set the parents of the current working directory
1327
1327
1328 This is useful for writing repository conversion tools, but should
1328 This is useful for writing repository conversion tools, but should
1329 be used with care.
1329 be used with care.
1330
1330
1331 Returns 0 on success.
1331 Returns 0 on success.
1332 """
1332 """
1333
1333
1334 r1 = cmdutil.revsingle(repo, rev1).node()
1334 r1 = cmdutil.revsingle(repo, rev1).node()
1335 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1335 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1336
1336
1337 wlock = repo.wlock()
1337 wlock = repo.wlock()
1338 try:
1338 try:
1339 repo.dirstate.setparents(r1, r2)
1339 repo.dirstate.setparents(r1, r2)
1340 finally:
1340 finally:
1341 wlock.release()
1341 wlock.release()
1342
1342
1343 def debugstate(ui, repo, nodates=None):
1343 def debugstate(ui, repo, nodates=None):
1344 """show the contents of the current dirstate"""
1344 """show the contents of the current dirstate"""
1345 timestr = ""
1345 timestr = ""
1346 showdate = not nodates
1346 showdate = not nodates
1347 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1347 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1348 if showdate:
1348 if showdate:
1349 if ent[3] == -1:
1349 if ent[3] == -1:
1350 # Pad or slice to locale representation
1350 # Pad or slice to locale representation
1351 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1351 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1352 time.localtime(0)))
1352 time.localtime(0)))
1353 timestr = 'unset'
1353 timestr = 'unset'
1354 timestr = (timestr[:locale_len] +
1354 timestr = (timestr[:locale_len] +
1355 ' ' * (locale_len - len(timestr)))
1355 ' ' * (locale_len - len(timestr)))
1356 else:
1356 else:
1357 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1357 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1358 time.localtime(ent[3]))
1358 time.localtime(ent[3]))
1359 if ent[1] & 020000:
1359 if ent[1] & 020000:
1360 mode = 'lnk'
1360 mode = 'lnk'
1361 else:
1361 else:
1362 mode = '%3o' % (ent[1] & 0777)
1362 mode = '%3o' % (ent[1] & 0777)
1363 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1363 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1364 for f in repo.dirstate.copies():
1364 for f in repo.dirstate.copies():
1365 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1365 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1366
1366
1367 def debugsub(ui, repo, rev=None):
1367 def debugsub(ui, repo, rev=None):
1368 ctx = cmdutil.revsingle(repo, rev, None)
1368 ctx = cmdutil.revsingle(repo, rev, None)
1369 for k, v in sorted(ctx.substate.items()):
1369 for k, v in sorted(ctx.substate.items()):
1370 ui.write('path %s\n' % k)
1370 ui.write('path %s\n' % k)
1371 ui.write(' source %s\n' % v[0])
1371 ui.write(' source %s\n' % v[0])
1372 ui.write(' revision %s\n' % v[1])
1372 ui.write(' revision %s\n' % v[1])
1373
1373
1374 def debugdag(ui, repo, file_=None, *revs, **opts):
1374 def debugdag(ui, repo, file_=None, *revs, **opts):
1375 """format the changelog or an index DAG as a concise textual description
1375 """format the changelog or an index DAG as a concise textual description
1376
1376
1377 If you pass a revlog index, the revlog's DAG is emitted. If you list
1377 If you pass a revlog index, the revlog's DAG is emitted. If you list
1378 revision numbers, they get labelled in the output as rN.
1378 revision numbers, they get labelled in the output as rN.
1379
1379
1380 Otherwise, the changelog DAG of the current repo is emitted.
1380 Otherwise, the changelog DAG of the current repo is emitted.
1381 """
1381 """
1382 spaces = opts.get('spaces')
1382 spaces = opts.get('spaces')
1383 dots = opts.get('dots')
1383 dots = opts.get('dots')
1384 if file_:
1384 if file_:
1385 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1385 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1386 revs = set((int(r) for r in revs))
1386 revs = set((int(r) for r in revs))
1387 def events():
1387 def events():
1388 for r in rlog:
1388 for r in rlog:
1389 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1389 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1390 if r in revs:
1390 if r in revs:
1391 yield 'l', (r, "r%i" % r)
1391 yield 'l', (r, "r%i" % r)
1392 elif repo:
1392 elif repo:
1393 cl = repo.changelog
1393 cl = repo.changelog
1394 tags = opts.get('tags')
1394 tags = opts.get('tags')
1395 branches = opts.get('branches')
1395 branches = opts.get('branches')
1396 if tags:
1396 if tags:
1397 labels = {}
1397 labels = {}
1398 for l, n in repo.tags().items():
1398 for l, n in repo.tags().items():
1399 labels.setdefault(cl.rev(n), []).append(l)
1399 labels.setdefault(cl.rev(n), []).append(l)
1400 def events():
1400 def events():
1401 b = "default"
1401 b = "default"
1402 for r in cl:
1402 for r in cl:
1403 if branches:
1403 if branches:
1404 newb = cl.read(cl.node(r))[5]['branch']
1404 newb = cl.read(cl.node(r))[5]['branch']
1405 if newb != b:
1405 if newb != b:
1406 yield 'a', newb
1406 yield 'a', newb
1407 b = newb
1407 b = newb
1408 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1408 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1409 if tags:
1409 if tags:
1410 ls = labels.get(r)
1410 ls = labels.get(r)
1411 if ls:
1411 if ls:
1412 for l in ls:
1412 for l in ls:
1413 yield 'l', (r, l)
1413 yield 'l', (r, l)
1414 else:
1414 else:
1415 raise util.Abort(_('need repo for changelog dag'))
1415 raise util.Abort(_('need repo for changelog dag'))
1416
1416
1417 for line in dagparser.dagtextlines(events(),
1417 for line in dagparser.dagtextlines(events(),
1418 addspaces=spaces,
1418 addspaces=spaces,
1419 wraplabels=True,
1419 wraplabels=True,
1420 wrapannotations=True,
1420 wrapannotations=True,
1421 wrapnonlinear=dots,
1421 wrapnonlinear=dots,
1422 usedots=dots,
1422 usedots=dots,
1423 maxlinewidth=70):
1423 maxlinewidth=70):
1424 ui.write(line)
1424 ui.write(line)
1425 ui.write("\n")
1425 ui.write("\n")
1426
1426
1427 def debugdata(ui, repo, file_, rev):
1427 def debugdata(ui, repo, file_, rev):
1428 """dump the contents of a data file revision"""
1428 """dump the contents of a data file revision"""
1429 r = None
1429 r = None
1430 if repo:
1430 if repo:
1431 filelog = repo.file(file_)
1431 filelog = repo.file(file_)
1432 if len(filelog):
1432 if len(filelog):
1433 r = filelog
1433 r = filelog
1434 if not r:
1434 if not r:
1435 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1435 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1436 try:
1436 try:
1437 ui.write(r.revision(r.lookup(rev)))
1437 ui.write(r.revision(r.lookup(rev)))
1438 except KeyError:
1438 except KeyError:
1439 raise util.Abort(_('invalid revision identifier %s') % rev)
1439 raise util.Abort(_('invalid revision identifier %s') % rev)
1440
1440
1441 def debugdate(ui, date, range=None, **opts):
1441 def debugdate(ui, date, range=None, **opts):
1442 """parse and display a date"""
1442 """parse and display a date"""
1443 if opts["extended"]:
1443 if opts["extended"]:
1444 d = util.parsedate(date, util.extendeddateformats)
1444 d = util.parsedate(date, util.extendeddateformats)
1445 else:
1445 else:
1446 d = util.parsedate(date)
1446 d = util.parsedate(date)
1447 ui.write("internal: %s %s\n" % d)
1447 ui.write("internal: %s %s\n" % d)
1448 ui.write("standard: %s\n" % util.datestr(d))
1448 ui.write("standard: %s\n" % util.datestr(d))
1449 if range:
1449 if range:
1450 m = util.matchdate(range)
1450 m = util.matchdate(range)
1451 ui.write("match: %s\n" % m(d[0]))
1451 ui.write("match: %s\n" % m(d[0]))
1452
1452
1453 def debugignore(ui, repo, *values, **opts):
1453 def debugignore(ui, repo, *values, **opts):
1454 """display the combined ignore pattern"""
1454 """display the combined ignore pattern"""
1455 ignore = repo.dirstate._ignore
1455 ignore = repo.dirstate._ignore
1456 if hasattr(ignore, 'includepat'):
1456 if hasattr(ignore, 'includepat'):
1457 ui.write("%s\n" % ignore.includepat)
1457 ui.write("%s\n" % ignore.includepat)
1458 else:
1458 else:
1459 raise util.Abort(_("no ignore patterns found"))
1459 raise util.Abort(_("no ignore patterns found"))
1460
1460
1461 def debugindex(ui, repo, file_, **opts):
1461 def debugindex(ui, repo, file_, **opts):
1462 """dump the contents of an index file"""
1462 """dump the contents of an index file"""
1463 r = None
1463 r = None
1464 if repo:
1464 if repo:
1465 filelog = repo.file(file_)
1465 filelog = repo.file(file_)
1466 if len(filelog):
1466 if len(filelog):
1467 r = filelog
1467 r = filelog
1468
1468
1469 format = opts.get('format', 0)
1469 format = opts.get('format', 0)
1470 if format not in (0, 1):
1470 if format not in (0, 1):
1471 raise util.Abort(_("unknown format %d") % format)
1471 raise util.Abort(_("unknown format %d") % format)
1472
1472
1473 if not r:
1473 if not r:
1474 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1474 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1475
1475
1476 if format == 0:
1476 if format == 0:
1477 ui.write(" rev offset length base linkrev"
1477 ui.write(" rev offset length base linkrev"
1478 " nodeid p1 p2\n")
1478 " nodeid p1 p2\n")
1479 elif format == 1:
1479 elif format == 1:
1480 ui.write(" rev flag offset length"
1480 ui.write(" rev flag offset length"
1481 " size base link p1 p2 nodeid\n")
1481 " size base link p1 p2 nodeid\n")
1482
1482
1483 for i in r:
1483 for i in r:
1484 node = r.node(i)
1484 node = r.node(i)
1485 if format == 0:
1485 if format == 0:
1486 try:
1486 try:
1487 pp = r.parents(node)
1487 pp = r.parents(node)
1488 except:
1488 except:
1489 pp = [nullid, nullid]
1489 pp = [nullid, nullid]
1490 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1490 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1491 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1491 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1492 short(node), short(pp[0]), short(pp[1])))
1492 short(node), short(pp[0]), short(pp[1])))
1493 elif format == 1:
1493 elif format == 1:
1494 pr = r.parentrevs(i)
1494 pr = r.parentrevs(i)
1495 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1495 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1496 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1496 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1497 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1497 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1498
1498
1499 def debugindexdot(ui, repo, file_):
1499 def debugindexdot(ui, repo, file_):
1500 """dump an index DAG as a graphviz dot file"""
1500 """dump an index DAG as a graphviz dot file"""
1501 r = None
1501 r = None
1502 if repo:
1502 if repo:
1503 filelog = repo.file(file_)
1503 filelog = repo.file(file_)
1504 if len(filelog):
1504 if len(filelog):
1505 r = filelog
1505 r = filelog
1506 if not r:
1506 if not r:
1507 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1507 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1508 ui.write("digraph G {\n")
1508 ui.write("digraph G {\n")
1509 for i in r:
1509 for i in r:
1510 node = r.node(i)
1510 node = r.node(i)
1511 pp = r.parents(node)
1511 pp = r.parents(node)
1512 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1512 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1513 if pp[1] != nullid:
1513 if pp[1] != nullid:
1514 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1514 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1515 ui.write("}\n")
1515 ui.write("}\n")
1516
1516
1517 def debuginstall(ui):
1517 def debuginstall(ui):
1518 '''test Mercurial installation
1518 '''test Mercurial installation
1519
1519
1520 Returns 0 on success.
1520 Returns 0 on success.
1521 '''
1521 '''
1522
1522
1523 def writetemp(contents):
1523 def writetemp(contents):
1524 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1524 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1525 f = os.fdopen(fd, "wb")
1525 f = os.fdopen(fd, "wb")
1526 f.write(contents)
1526 f.write(contents)
1527 f.close()
1527 f.close()
1528 return name
1528 return name
1529
1529
1530 problems = 0
1530 problems = 0
1531
1531
1532 # encoding
1532 # encoding
1533 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1533 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1534 try:
1534 try:
1535 encoding.fromlocal("test")
1535 encoding.fromlocal("test")
1536 except util.Abort, inst:
1536 except util.Abort, inst:
1537 ui.write(" %s\n" % inst)
1537 ui.write(" %s\n" % inst)
1538 ui.write(_(" (check that your locale is properly set)\n"))
1538 ui.write(_(" (check that your locale is properly set)\n"))
1539 problems += 1
1539 problems += 1
1540
1540
1541 # compiled modules
1541 # compiled modules
1542 ui.status(_("Checking installed modules (%s)...\n")
1542 ui.status(_("Checking installed modules (%s)...\n")
1543 % os.path.dirname(__file__))
1543 % os.path.dirname(__file__))
1544 try:
1544 try:
1545 import bdiff, mpatch, base85, osutil
1545 import bdiff, mpatch, base85, osutil
1546 except Exception, inst:
1546 except Exception, inst:
1547 ui.write(" %s\n" % inst)
1547 ui.write(" %s\n" % inst)
1548 ui.write(_(" One or more extensions could not be found"))
1548 ui.write(_(" One or more extensions could not be found"))
1549 ui.write(_(" (check that you compiled the extensions)\n"))
1549 ui.write(_(" (check that you compiled the extensions)\n"))
1550 problems += 1
1550 problems += 1
1551
1551
1552 # templates
1552 # templates
1553 ui.status(_("Checking templates...\n"))
1553 ui.status(_("Checking templates...\n"))
1554 try:
1554 try:
1555 import templater
1555 import templater
1556 templater.templater(templater.templatepath("map-cmdline.default"))
1556 templater.templater(templater.templatepath("map-cmdline.default"))
1557 except Exception, inst:
1557 except Exception, inst:
1558 ui.write(" %s\n" % inst)
1558 ui.write(" %s\n" % inst)
1559 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1559 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1560 problems += 1
1560 problems += 1
1561
1561
1562 # patch
1562 # patch
1563 ui.status(_("Checking patch...\n"))
1563 ui.status(_("Checking patch...\n"))
1564 patchproblems = 0
1564 patchproblems = 0
1565 a = "1\n2\n3\n4\n"
1565 a = "1\n2\n3\n4\n"
1566 b = "1\n2\n3\ninsert\n4\n"
1566 b = "1\n2\n3\ninsert\n4\n"
1567 fa = writetemp(a)
1567 fa = writetemp(a)
1568 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1568 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1569 os.path.basename(fa))
1569 os.path.basename(fa))
1570 fd = writetemp(d)
1570 fd = writetemp(d)
1571
1571
1572 files = {}
1572 files = {}
1573 try:
1573 try:
1574 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1574 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1575 except util.Abort, e:
1575 except util.Abort, e:
1576 ui.write(_(" patch call failed:\n"))
1576 ui.write(_(" patch call failed:\n"))
1577 ui.write(" " + str(e) + "\n")
1577 ui.write(" " + str(e) + "\n")
1578 patchproblems += 1
1578 patchproblems += 1
1579 else:
1579 else:
1580 if list(files) != [os.path.basename(fa)]:
1580 if list(files) != [os.path.basename(fa)]:
1581 ui.write(_(" unexpected patch output!\n"))
1581 ui.write(_(" unexpected patch output!\n"))
1582 patchproblems += 1
1582 patchproblems += 1
1583 a = open(fa).read()
1583 a = open(fa).read()
1584 if a != b:
1584 if a != b:
1585 ui.write(_(" patch test failed!\n"))
1585 ui.write(_(" patch test failed!\n"))
1586 patchproblems += 1
1586 patchproblems += 1
1587
1587
1588 if patchproblems:
1588 if patchproblems:
1589 if ui.config('ui', 'patch'):
1589 if ui.config('ui', 'patch'):
1590 ui.write(_(" (Current patch tool may be incompatible with patch,"
1590 ui.write(_(" (Current patch tool may be incompatible with patch,"
1591 " or misconfigured. Please check your configuration"
1591 " or misconfigured. Please check your configuration"
1592 " file)\n"))
1592 " file)\n"))
1593 else:
1593 else:
1594 ui.write(_(" Internal patcher failure, please report this error"
1594 ui.write(_(" Internal patcher failure, please report this error"
1595 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1595 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1596 problems += patchproblems
1596 problems += patchproblems
1597
1597
1598 os.unlink(fa)
1598 os.unlink(fa)
1599 os.unlink(fd)
1599 os.unlink(fd)
1600
1600
1601 # editor
1601 # editor
1602 ui.status(_("Checking commit editor...\n"))
1602 ui.status(_("Checking commit editor...\n"))
1603 editor = ui.geteditor()
1603 editor = ui.geteditor()
1604 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1604 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1605 if not cmdpath:
1605 if not cmdpath:
1606 if editor == 'vi':
1606 if editor == 'vi':
1607 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1607 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1608 ui.write(_(" (specify a commit editor in your configuration"
1608 ui.write(_(" (specify a commit editor in your configuration"
1609 " file)\n"))
1609 " file)\n"))
1610 else:
1610 else:
1611 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1611 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1612 ui.write(_(" (specify a commit editor in your configuration"
1612 ui.write(_(" (specify a commit editor in your configuration"
1613 " file)\n"))
1613 " file)\n"))
1614 problems += 1
1614 problems += 1
1615
1615
1616 # check username
1616 # check username
1617 ui.status(_("Checking username...\n"))
1617 ui.status(_("Checking username...\n"))
1618 try:
1618 try:
1619 ui.username()
1619 ui.username()
1620 except util.Abort, e:
1620 except util.Abort, e:
1621 ui.write(" %s\n" % e)
1621 ui.write(" %s\n" % e)
1622 ui.write(_(" (specify a username in your configuration file)\n"))
1622 ui.write(_(" (specify a username in your configuration file)\n"))
1623 problems += 1
1623 problems += 1
1624
1624
1625 if not problems:
1625 if not problems:
1626 ui.status(_("No problems detected\n"))
1626 ui.status(_("No problems detected\n"))
1627 else:
1627 else:
1628 ui.write(_("%s problems detected,"
1628 ui.write(_("%s problems detected,"
1629 " please check your install!\n") % problems)
1629 " please check your install!\n") % problems)
1630
1630
1631 return problems
1631 return problems
1632
1632
1633 def debugrename(ui, repo, file1, *pats, **opts):
1633 def debugrename(ui, repo, file1, *pats, **opts):
1634 """dump rename information"""
1634 """dump rename information"""
1635
1635
1636 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1636 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1637 m = cmdutil.match(repo, (file1,) + pats, opts)
1637 m = cmdutil.match(repo, (file1,) + pats, opts)
1638 for abs in ctx.walk(m):
1638 for abs in ctx.walk(m):
1639 fctx = ctx[abs]
1639 fctx = ctx[abs]
1640 o = fctx.filelog().renamed(fctx.filenode())
1640 o = fctx.filelog().renamed(fctx.filenode())
1641 rel = m.rel(abs)
1641 rel = m.rel(abs)
1642 if o:
1642 if o:
1643 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1643 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1644 else:
1644 else:
1645 ui.write(_("%s not renamed\n") % rel)
1645 ui.write(_("%s not renamed\n") % rel)
1646
1646
1647 def debugwalk(ui, repo, *pats, **opts):
1647 def debugwalk(ui, repo, *pats, **opts):
1648 """show how files match on given patterns"""
1648 """show how files match on given patterns"""
1649 m = cmdutil.match(repo, pats, opts)
1649 m = cmdutil.match(repo, pats, opts)
1650 items = list(repo.walk(m))
1650 items = list(repo.walk(m))
1651 if not items:
1651 if not items:
1652 return
1652 return
1653 fmt = 'f %%-%ds %%-%ds %%s' % (
1653 fmt = 'f %%-%ds %%-%ds %%s' % (
1654 max([len(abs) for abs in items]),
1654 max([len(abs) for abs in items]),
1655 max([len(m.rel(abs)) for abs in items]))
1655 max([len(m.rel(abs)) for abs in items]))
1656 for abs in items:
1656 for abs in items:
1657 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1657 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1658 ui.write("%s\n" % line.rstrip())
1658 ui.write("%s\n" % line.rstrip())
1659
1659
1660 def debugwireargs(ui, repopath, *vals, **opts):
1660 def debugwireargs(ui, repopath, *vals, **opts):
1661 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1661 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1662 for opt in remoteopts:
1662 for opt in remoteopts:
1663 del opts[opt[1]]
1663 del opts[opt[1]]
1664 args = {}
1664 args = {}
1665 for k, v in opts.iteritems():
1665 for k, v in opts.iteritems():
1666 if v:
1666 if v:
1667 args[k] = v
1667 args[k] = v
1668 # run twice to check that we don't mess up the stream for the next command
1668 # run twice to check that we don't mess up the stream for the next command
1669 res1 = repo.debugwireargs(*vals, **args)
1669 res1 = repo.debugwireargs(*vals, **args)
1670 res2 = repo.debugwireargs(*vals, **args)
1670 res2 = repo.debugwireargs(*vals, **args)
1671 ui.write("%s\n" % res1)
1671 ui.write("%s\n" % res1)
1672 if res1 != res2:
1672 if res1 != res2:
1673 ui.warn("%s\n" % res2)
1673 ui.warn("%s\n" % res2)
1674
1674
1675 def diff(ui, repo, *pats, **opts):
1675 def diff(ui, repo, *pats, **opts):
1676 """diff repository (or selected files)
1676 """diff repository (or selected files)
1677
1677
1678 Show differences between revisions for the specified files.
1678 Show differences between revisions for the specified files.
1679
1679
1680 Differences between files are shown using the unified diff format.
1680 Differences between files are shown using the unified diff format.
1681
1681
1682 .. note::
1682 .. note::
1683 diff may generate unexpected results for merges, as it will
1683 diff may generate unexpected results for merges, as it will
1684 default to comparing against the working directory's first
1684 default to comparing against the working directory's first
1685 parent changeset if no revisions are specified.
1685 parent changeset if no revisions are specified.
1686
1686
1687 When two revision arguments are given, then changes are shown
1687 When two revision arguments are given, then changes are shown
1688 between those revisions. If only one revision is specified then
1688 between those revisions. If only one revision is specified then
1689 that revision is compared to the working directory, and, when no
1689 that revision is compared to the working directory, and, when no
1690 revisions are specified, the working directory files are compared
1690 revisions are specified, the working directory files are compared
1691 to its parent.
1691 to its parent.
1692
1692
1693 Alternatively you can specify -c/--change with a revision to see
1693 Alternatively you can specify -c/--change with a revision to see
1694 the changes in that changeset relative to its first parent.
1694 the changes in that changeset relative to its first parent.
1695
1695
1696 Without the -a/--text option, diff will avoid generating diffs of
1696 Without the -a/--text option, diff will avoid generating diffs of
1697 files it detects as binary. With -a, diff will generate a diff
1697 files it detects as binary. With -a, diff will generate a diff
1698 anyway, probably with undesirable results.
1698 anyway, probably with undesirable results.
1699
1699
1700 Use the -g/--git option to generate diffs in the git extended diff
1700 Use the -g/--git option to generate diffs in the git extended diff
1701 format. For more information, read :hg:`help diffs`.
1701 format. For more information, read :hg:`help diffs`.
1702
1702
1703 Returns 0 on success.
1703 Returns 0 on success.
1704 """
1704 """
1705
1705
1706 revs = opts.get('rev')
1706 revs = opts.get('rev')
1707 change = opts.get('change')
1707 change = opts.get('change')
1708 stat = opts.get('stat')
1708 stat = opts.get('stat')
1709 reverse = opts.get('reverse')
1709 reverse = opts.get('reverse')
1710
1710
1711 if revs and change:
1711 if revs and change:
1712 msg = _('cannot specify --rev and --change at the same time')
1712 msg = _('cannot specify --rev and --change at the same time')
1713 raise util.Abort(msg)
1713 raise util.Abort(msg)
1714 elif change:
1714 elif change:
1715 node2 = cmdutil.revsingle(repo, change, None).node()
1715 node2 = cmdutil.revsingle(repo, change, None).node()
1716 node1 = repo[node2].parents()[0].node()
1716 node1 = repo[node2].parents()[0].node()
1717 else:
1717 else:
1718 node1, node2 = cmdutil.revpair(repo, revs)
1718 node1, node2 = cmdutil.revpair(repo, revs)
1719
1719
1720 if reverse:
1720 if reverse:
1721 node1, node2 = node2, node1
1721 node1, node2 = node2, node1
1722
1722
1723 diffopts = patch.diffopts(ui, opts)
1723 diffopts = patch.diffopts(ui, opts)
1724 m = cmdutil.match(repo, pats, opts)
1724 m = cmdutil.match(repo, pats, opts)
1725 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1725 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1726 listsubrepos=opts.get('subrepos'))
1726 listsubrepos=opts.get('subrepos'))
1727
1727
1728 def export(ui, repo, *changesets, **opts):
1728 def export(ui, repo, *changesets, **opts):
1729 """dump the header and diffs for one or more changesets
1729 """dump the header and diffs for one or more changesets
1730
1730
1731 Print the changeset header and diffs for one or more revisions.
1731 Print the changeset header and diffs for one or more revisions.
1732
1732
1733 The information shown in the changeset header is: author, date,
1733 The information shown in the changeset header is: author, date,
1734 branch name (if non-default), changeset hash, parent(s) and commit
1734 branch name (if non-default), changeset hash, parent(s) and commit
1735 comment.
1735 comment.
1736
1736
1737 .. note::
1737 .. note::
1738 export may generate unexpected diff output for merge
1738 export may generate unexpected diff output for merge
1739 changesets, as it will compare the merge changeset against its
1739 changesets, as it will compare the merge changeset against its
1740 first parent only.
1740 first parent only.
1741
1741
1742 Output may be to a file, in which case the name of the file is
1742 Output may be to a file, in which case the name of the file is
1743 given using a format string. The formatting rules are as follows:
1743 given using a format string. The formatting rules are as follows:
1744
1744
1745 :``%%``: literal "%" character
1745 :``%%``: literal "%" character
1746 :``%H``: changeset hash (40 hexadecimal digits)
1746 :``%H``: changeset hash (40 hexadecimal digits)
1747 :``%N``: number of patches being generated
1747 :``%N``: number of patches being generated
1748 :``%R``: changeset revision number
1748 :``%R``: changeset revision number
1749 :``%b``: basename of the exporting repository
1749 :``%b``: basename of the exporting repository
1750 :``%h``: short-form changeset hash (12 hexadecimal digits)
1750 :``%h``: short-form changeset hash (12 hexadecimal digits)
1751 :``%n``: zero-padded sequence number, starting at 1
1751 :``%n``: zero-padded sequence number, starting at 1
1752 :``%r``: zero-padded changeset revision number
1752 :``%r``: zero-padded changeset revision number
1753
1753
1754 Without the -a/--text option, export will avoid generating diffs
1754 Without the -a/--text option, export will avoid generating diffs
1755 of files it detects as binary. With -a, export will generate a
1755 of files it detects as binary. With -a, export will generate a
1756 diff anyway, probably with undesirable results.
1756 diff anyway, probably with undesirable results.
1757
1757
1758 Use the -g/--git option to generate diffs in the git extended diff
1758 Use the -g/--git option to generate diffs in the git extended diff
1759 format. See :hg:`help diffs` for more information.
1759 format. See :hg:`help diffs` for more information.
1760
1760
1761 With the --switch-parent option, the diff will be against the
1761 With the --switch-parent option, the diff will be against the
1762 second parent. It can be useful to review a merge.
1762 second parent. It can be useful to review a merge.
1763
1763
1764 Returns 0 on success.
1764 Returns 0 on success.
1765 """
1765 """
1766 changesets += tuple(opts.get('rev', []))
1766 changesets += tuple(opts.get('rev', []))
1767 if not changesets:
1767 if not changesets:
1768 raise util.Abort(_("export requires at least one changeset"))
1768 raise util.Abort(_("export requires at least one changeset"))
1769 revs = cmdutil.revrange(repo, changesets)
1769 revs = cmdutil.revrange(repo, changesets)
1770 if len(revs) > 1:
1770 if len(revs) > 1:
1771 ui.note(_('exporting patches:\n'))
1771 ui.note(_('exporting patches:\n'))
1772 else:
1772 else:
1773 ui.note(_('exporting patch:\n'))
1773 ui.note(_('exporting patch:\n'))
1774 cmdutil.export(repo, revs, template=opts.get('output'),
1774 cmdutil.export(repo, revs, template=opts.get('output'),
1775 switch_parent=opts.get('switch_parent'),
1775 switch_parent=opts.get('switch_parent'),
1776 opts=patch.diffopts(ui, opts))
1776 opts=patch.diffopts(ui, opts))
1777
1777
1778 def forget(ui, repo, *pats, **opts):
1778 def forget(ui, repo, *pats, **opts):
1779 """forget the specified files on the next commit
1779 """forget the specified files on the next commit
1780
1780
1781 Mark the specified files so they will no longer be tracked
1781 Mark the specified files so they will no longer be tracked
1782 after the next commit.
1782 after the next commit.
1783
1783
1784 This only removes files from the current branch, not from the
1784 This only removes files from the current branch, not from the
1785 entire project history, and it does not delete them from the
1785 entire project history, and it does not delete them from the
1786 working directory.
1786 working directory.
1787
1787
1788 To undo a forget before the next commit, see :hg:`add`.
1788 To undo a forget before the next commit, see :hg:`add`.
1789
1789
1790 Returns 0 on success.
1790 Returns 0 on success.
1791 """
1791 """
1792
1792
1793 if not pats:
1793 if not pats:
1794 raise util.Abort(_('no files specified'))
1794 raise util.Abort(_('no files specified'))
1795
1795
1796 m = cmdutil.match(repo, pats, opts)
1796 m = cmdutil.match(repo, pats, opts)
1797 s = repo.status(match=m, clean=True)
1797 s = repo.status(match=m, clean=True)
1798 forget = sorted(s[0] + s[1] + s[3] + s[6])
1798 forget = sorted(s[0] + s[1] + s[3] + s[6])
1799 errs = 0
1799 errs = 0
1800
1800
1801 for f in m.files():
1801 for f in m.files():
1802 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1802 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1803 ui.warn(_('not removing %s: file is already untracked\n')
1803 ui.warn(_('not removing %s: file is already untracked\n')
1804 % m.rel(f))
1804 % m.rel(f))
1805 errs = 1
1805 errs = 1
1806
1806
1807 for f in forget:
1807 for f in forget:
1808 if ui.verbose or not m.exact(f):
1808 if ui.verbose or not m.exact(f):
1809 ui.status(_('removing %s\n') % m.rel(f))
1809 ui.status(_('removing %s\n') % m.rel(f))
1810
1810
1811 repo[None].remove(forget, unlink=False)
1811 repo[None].remove(forget, unlink=False)
1812 return errs
1812 return errs
1813
1813
1814 def grep(ui, repo, pattern, *pats, **opts):
1814 def grep(ui, repo, pattern, *pats, **opts):
1815 """search for a pattern in specified files and revisions
1815 """search for a pattern in specified files and revisions
1816
1816
1817 Search revisions of files for a regular expression.
1817 Search revisions of files for a regular expression.
1818
1818
1819 This command behaves differently than Unix grep. It only accepts
1819 This command behaves differently than Unix grep. It only accepts
1820 Python/Perl regexps. It searches repository history, not the
1820 Python/Perl regexps. It searches repository history, not the
1821 working directory. It always prints the revision number in which a
1821 working directory. It always prints the revision number in which a
1822 match appears.
1822 match appears.
1823
1823
1824 By default, grep only prints output for the first revision of a
1824 By default, grep only prints output for the first revision of a
1825 file in which it finds a match. To get it to print every revision
1825 file in which it finds a match. To get it to print every revision
1826 that contains a change in match status ("-" for a match that
1826 that contains a change in match status ("-" for a match that
1827 becomes a non-match, or "+" for a non-match that becomes a match),
1827 becomes a non-match, or "+" for a non-match that becomes a match),
1828 use the --all flag.
1828 use the --all flag.
1829
1829
1830 Returns 0 if a match is found, 1 otherwise.
1830 Returns 0 if a match is found, 1 otherwise.
1831 """
1831 """
1832 reflags = 0
1832 reflags = 0
1833 if opts.get('ignore_case'):
1833 if opts.get('ignore_case'):
1834 reflags |= re.I
1834 reflags |= re.I
1835 try:
1835 try:
1836 regexp = re.compile(pattern, reflags)
1836 regexp = re.compile(pattern, reflags)
1837 except re.error, inst:
1837 except re.error, inst:
1838 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1838 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1839 return 1
1839 return 1
1840 sep, eol = ':', '\n'
1840 sep, eol = ':', '\n'
1841 if opts.get('print0'):
1841 if opts.get('print0'):
1842 sep = eol = '\0'
1842 sep = eol = '\0'
1843
1843
1844 getfile = util.lrucachefunc(repo.file)
1844 getfile = util.lrucachefunc(repo.file)
1845
1845
1846 def matchlines(body):
1846 def matchlines(body):
1847 begin = 0
1847 begin = 0
1848 linenum = 0
1848 linenum = 0
1849 while True:
1849 while True:
1850 match = regexp.search(body, begin)
1850 match = regexp.search(body, begin)
1851 if not match:
1851 if not match:
1852 break
1852 break
1853 mstart, mend = match.span()
1853 mstart, mend = match.span()
1854 linenum += body.count('\n', begin, mstart) + 1
1854 linenum += body.count('\n', begin, mstart) + 1
1855 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1855 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1856 begin = body.find('\n', mend) + 1 or len(body)
1856 begin = body.find('\n', mend) + 1 or len(body)
1857 lend = begin - 1
1857 lend = begin - 1
1858 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1858 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1859
1859
1860 class linestate(object):
1860 class linestate(object):
1861 def __init__(self, line, linenum, colstart, colend):
1861 def __init__(self, line, linenum, colstart, colend):
1862 self.line = line
1862 self.line = line
1863 self.linenum = linenum
1863 self.linenum = linenum
1864 self.colstart = colstart
1864 self.colstart = colstart
1865 self.colend = colend
1865 self.colend = colend
1866
1866
1867 def __hash__(self):
1867 def __hash__(self):
1868 return hash((self.linenum, self.line))
1868 return hash((self.linenum, self.line))
1869
1869
1870 def __eq__(self, other):
1870 def __eq__(self, other):
1871 return self.line == other.line
1871 return self.line == other.line
1872
1872
1873 matches = {}
1873 matches = {}
1874 copies = {}
1874 copies = {}
1875 def grepbody(fn, rev, body):
1875 def grepbody(fn, rev, body):
1876 matches[rev].setdefault(fn, [])
1876 matches[rev].setdefault(fn, [])
1877 m = matches[rev][fn]
1877 m = matches[rev][fn]
1878 for lnum, cstart, cend, line in matchlines(body):
1878 for lnum, cstart, cend, line in matchlines(body):
1879 s = linestate(line, lnum, cstart, cend)
1879 s = linestate(line, lnum, cstart, cend)
1880 m.append(s)
1880 m.append(s)
1881
1881
1882 def difflinestates(a, b):
1882 def difflinestates(a, b):
1883 sm = difflib.SequenceMatcher(None, a, b)
1883 sm = difflib.SequenceMatcher(None, a, b)
1884 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1884 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1885 if tag == 'insert':
1885 if tag == 'insert':
1886 for i in xrange(blo, bhi):
1886 for i in xrange(blo, bhi):
1887 yield ('+', b[i])
1887 yield ('+', b[i])
1888 elif tag == 'delete':
1888 elif tag == 'delete':
1889 for i in xrange(alo, ahi):
1889 for i in xrange(alo, ahi):
1890 yield ('-', a[i])
1890 yield ('-', a[i])
1891 elif tag == 'replace':
1891 elif tag == 'replace':
1892 for i in xrange(alo, ahi):
1892 for i in xrange(alo, ahi):
1893 yield ('-', a[i])
1893 yield ('-', a[i])
1894 for i in xrange(blo, bhi):
1894 for i in xrange(blo, bhi):
1895 yield ('+', b[i])
1895 yield ('+', b[i])
1896
1896
1897 def display(fn, ctx, pstates, states):
1897 def display(fn, ctx, pstates, states):
1898 rev = ctx.rev()
1898 rev = ctx.rev()
1899 datefunc = ui.quiet and util.shortdate or util.datestr
1899 datefunc = ui.quiet and util.shortdate or util.datestr
1900 found = False
1900 found = False
1901 filerevmatches = {}
1901 filerevmatches = {}
1902 if opts.get('all'):
1902 if opts.get('all'):
1903 iter = difflinestates(pstates, states)
1903 iter = difflinestates(pstates, states)
1904 else:
1904 else:
1905 iter = [('', l) for l in states]
1905 iter = [('', l) for l in states]
1906 for change, l in iter:
1906 for change, l in iter:
1907 cols = [fn, str(rev)]
1907 cols = [fn, str(rev)]
1908 before, match, after = None, None, None
1908 before, match, after = None, None, None
1909 if opts.get('line_number'):
1909 if opts.get('line_number'):
1910 cols.append(str(l.linenum))
1910 cols.append(str(l.linenum))
1911 if opts.get('all'):
1911 if opts.get('all'):
1912 cols.append(change)
1912 cols.append(change)
1913 if opts.get('user'):
1913 if opts.get('user'):
1914 cols.append(ui.shortuser(ctx.user()))
1914 cols.append(ui.shortuser(ctx.user()))
1915 if opts.get('date'):
1915 if opts.get('date'):
1916 cols.append(datefunc(ctx.date()))
1916 cols.append(datefunc(ctx.date()))
1917 if opts.get('files_with_matches'):
1917 if opts.get('files_with_matches'):
1918 c = (fn, rev)
1918 c = (fn, rev)
1919 if c in filerevmatches:
1919 if c in filerevmatches:
1920 continue
1920 continue
1921 filerevmatches[c] = 1
1921 filerevmatches[c] = 1
1922 else:
1922 else:
1923 before = l.line[:l.colstart]
1923 before = l.line[:l.colstart]
1924 match = l.line[l.colstart:l.colend]
1924 match = l.line[l.colstart:l.colend]
1925 after = l.line[l.colend:]
1925 after = l.line[l.colend:]
1926 ui.write(sep.join(cols))
1926 ui.write(sep.join(cols))
1927 if before is not None:
1927 if before is not None:
1928 ui.write(sep + before)
1928 ui.write(sep + before)
1929 ui.write(match, label='grep.match')
1929 ui.write(match, label='grep.match')
1930 ui.write(after)
1930 ui.write(after)
1931 ui.write(eol)
1931 ui.write(eol)
1932 found = True
1932 found = True
1933 return found
1933 return found
1934
1934
1935 skip = {}
1935 skip = {}
1936 revfiles = {}
1936 revfiles = {}
1937 matchfn = cmdutil.match(repo, pats, opts)
1937 matchfn = cmdutil.match(repo, pats, opts)
1938 found = False
1938 found = False
1939 follow = opts.get('follow')
1939 follow = opts.get('follow')
1940
1940
1941 def prep(ctx, fns):
1941 def prep(ctx, fns):
1942 rev = ctx.rev()
1942 rev = ctx.rev()
1943 pctx = ctx.parents()[0]
1943 pctx = ctx.parents()[0]
1944 parent = pctx.rev()
1944 parent = pctx.rev()
1945 matches.setdefault(rev, {})
1945 matches.setdefault(rev, {})
1946 matches.setdefault(parent, {})
1946 matches.setdefault(parent, {})
1947 files = revfiles.setdefault(rev, [])
1947 files = revfiles.setdefault(rev, [])
1948 for fn in fns:
1948 for fn in fns:
1949 flog = getfile(fn)
1949 flog = getfile(fn)
1950 try:
1950 try:
1951 fnode = ctx.filenode(fn)
1951 fnode = ctx.filenode(fn)
1952 except error.LookupError:
1952 except error.LookupError:
1953 continue
1953 continue
1954
1954
1955 copied = flog.renamed(fnode)
1955 copied = flog.renamed(fnode)
1956 copy = follow and copied and copied[0]
1956 copy = follow and copied and copied[0]
1957 if copy:
1957 if copy:
1958 copies.setdefault(rev, {})[fn] = copy
1958 copies.setdefault(rev, {})[fn] = copy
1959 if fn in skip:
1959 if fn in skip:
1960 if copy:
1960 if copy:
1961 skip[copy] = True
1961 skip[copy] = True
1962 continue
1962 continue
1963 files.append(fn)
1963 files.append(fn)
1964
1964
1965 if fn not in matches[rev]:
1965 if fn not in matches[rev]:
1966 grepbody(fn, rev, flog.read(fnode))
1966 grepbody(fn, rev, flog.read(fnode))
1967
1967
1968 pfn = copy or fn
1968 pfn = copy or fn
1969 if pfn not in matches[parent]:
1969 if pfn not in matches[parent]:
1970 try:
1970 try:
1971 fnode = pctx.filenode(pfn)
1971 fnode = pctx.filenode(pfn)
1972 grepbody(pfn, parent, flog.read(fnode))
1972 grepbody(pfn, parent, flog.read(fnode))
1973 except error.LookupError:
1973 except error.LookupError:
1974 pass
1974 pass
1975
1975
1976 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1976 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1977 rev = ctx.rev()
1977 rev = ctx.rev()
1978 parent = ctx.parents()[0].rev()
1978 parent = ctx.parents()[0].rev()
1979 for fn in sorted(revfiles.get(rev, [])):
1979 for fn in sorted(revfiles.get(rev, [])):
1980 states = matches[rev][fn]
1980 states = matches[rev][fn]
1981 copy = copies.get(rev, {}).get(fn)
1981 copy = copies.get(rev, {}).get(fn)
1982 if fn in skip:
1982 if fn in skip:
1983 if copy:
1983 if copy:
1984 skip[copy] = True
1984 skip[copy] = True
1985 continue
1985 continue
1986 pstates = matches.get(parent, {}).get(copy or fn, [])
1986 pstates = matches.get(parent, {}).get(copy or fn, [])
1987 if pstates or states:
1987 if pstates or states:
1988 r = display(fn, ctx, pstates, states)
1988 r = display(fn, ctx, pstates, states)
1989 found = found or r
1989 found = found or r
1990 if r and not opts.get('all'):
1990 if r and not opts.get('all'):
1991 skip[fn] = True
1991 skip[fn] = True
1992 if copy:
1992 if copy:
1993 skip[copy] = True
1993 skip[copy] = True
1994 del matches[rev]
1994 del matches[rev]
1995 del revfiles[rev]
1995 del revfiles[rev]
1996
1996
1997 return not found
1997 return not found
1998
1998
1999 def heads(ui, repo, *branchrevs, **opts):
1999 def heads(ui, repo, *branchrevs, **opts):
2000 """show current repository heads or show branch heads
2000 """show current repository heads or show branch heads
2001
2001
2002 With no arguments, show all repository branch heads.
2002 With no arguments, show all repository branch heads.
2003
2003
2004 Repository "heads" are changesets with no child changesets. They are
2004 Repository "heads" are changesets with no child changesets. They are
2005 where development generally takes place and are the usual targets
2005 where development generally takes place and are the usual targets
2006 for update and merge operations. Branch heads are changesets that have
2006 for update and merge operations. Branch heads are changesets that have
2007 no child changeset on the same branch.
2007 no child changeset on the same branch.
2008
2008
2009 If one or more REVs are given, only branch heads on the branches
2009 If one or more REVs are given, only branch heads on the branches
2010 associated with the specified changesets are shown.
2010 associated with the specified changesets are shown.
2011
2011
2012 If -c/--closed is specified, also show branch heads marked closed
2012 If -c/--closed is specified, also show branch heads marked closed
2013 (see :hg:`commit --close-branch`).
2013 (see :hg:`commit --close-branch`).
2014
2014
2015 If STARTREV is specified, only those heads that are descendants of
2015 If STARTREV is specified, only those heads that are descendants of
2016 STARTREV will be displayed.
2016 STARTREV will be displayed.
2017
2017
2018 If -t/--topo is specified, named branch mechanics will be ignored and only
2018 If -t/--topo is specified, named branch mechanics will be ignored and only
2019 changesets without children will be shown.
2019 changesets without children will be shown.
2020
2020
2021 Returns 0 if matching heads are found, 1 if not.
2021 Returns 0 if matching heads are found, 1 if not.
2022 """
2022 """
2023
2023
2024 start = None
2024 start = None
2025 if 'rev' in opts:
2025 if 'rev' in opts:
2026 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2026 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2027
2027
2028 if opts.get('topo'):
2028 if opts.get('topo'):
2029 heads = [repo[h] for h in repo.heads(start)]
2029 heads = [repo[h] for h in repo.heads(start)]
2030 else:
2030 else:
2031 heads = []
2031 heads = []
2032 for b, ls in repo.branchmap().iteritems():
2032 for b, ls in repo.branchmap().iteritems():
2033 if start is None:
2033 if start is None:
2034 heads += [repo[h] for h in ls]
2034 heads += [repo[h] for h in ls]
2035 continue
2035 continue
2036 startrev = repo.changelog.rev(start)
2036 startrev = repo.changelog.rev(start)
2037 descendants = set(repo.changelog.descendants(startrev))
2037 descendants = set(repo.changelog.descendants(startrev))
2038 descendants.add(startrev)
2038 descendants.add(startrev)
2039 rev = repo.changelog.rev
2039 rev = repo.changelog.rev
2040 heads += [repo[h] for h in ls if rev(h) in descendants]
2040 heads += [repo[h] for h in ls if rev(h) in descendants]
2041
2041
2042 if branchrevs:
2042 if branchrevs:
2043 branches = set(repo[br].branch() for br in branchrevs)
2043 branches = set(repo[br].branch() for br in branchrevs)
2044 heads = [h for h in heads if h.branch() in branches]
2044 heads = [h for h in heads if h.branch() in branches]
2045
2045
2046 if not opts.get('closed'):
2046 if not opts.get('closed'):
2047 heads = [h for h in heads if not h.extra().get('close')]
2047 heads = [h for h in heads if not h.extra().get('close')]
2048
2048
2049 if opts.get('active') and branchrevs:
2049 if opts.get('active') and branchrevs:
2050 dagheads = repo.heads(start)
2050 dagheads = repo.heads(start)
2051 heads = [h for h in heads if h.node() in dagheads]
2051 heads = [h for h in heads if h.node() in dagheads]
2052
2052
2053 if branchrevs:
2053 if branchrevs:
2054 haveheads = set(h.branch() for h in heads)
2054 haveheads = set(h.branch() for h in heads)
2055 if branches - haveheads:
2055 if branches - haveheads:
2056 headless = ', '.join(b for b in branches - haveheads)
2056 headless = ', '.join(b for b in branches - haveheads)
2057 msg = _('no open branch heads found on branches %s')
2057 msg = _('no open branch heads found on branches %s')
2058 if opts.get('rev'):
2058 if opts.get('rev'):
2059 msg += _(' (started at %s)' % opts['rev'])
2059 msg += _(' (started at %s)' % opts['rev'])
2060 ui.warn((msg + '\n') % headless)
2060 ui.warn((msg + '\n') % headless)
2061
2061
2062 if not heads:
2062 if not heads:
2063 return 1
2063 return 1
2064
2064
2065 heads = sorted(heads, key=lambda x: -x.rev())
2065 heads = sorted(heads, key=lambda x: -x.rev())
2066 displayer = cmdutil.show_changeset(ui, repo, opts)
2066 displayer = cmdutil.show_changeset(ui, repo, opts)
2067 for ctx in heads:
2067 for ctx in heads:
2068 displayer.show(ctx)
2068 displayer.show(ctx)
2069 displayer.close()
2069 displayer.close()
2070
2070
2071 def help_(ui, name=None, with_version=False, unknowncmd=False):
2071 def help_(ui, name=None, with_version=False, unknowncmd=False):
2072 """show help for a given topic or a help overview
2072 """show help for a given topic or a help overview
2073
2073
2074 With no arguments, print a list of commands with short help messages.
2074 With no arguments, print a list of commands with short help messages.
2075
2075
2076 Given a topic, extension, or command name, print help for that
2076 Given a topic, extension, or command name, print help for that
2077 topic.
2077 topic.
2078
2078
2079 Returns 0 if successful.
2079 Returns 0 if successful.
2080 """
2080 """
2081 option_lists = []
2081 option_lists = []
2082 textwidth = min(ui.termwidth(), 80) - 2
2082 textwidth = min(ui.termwidth(), 80) - 2
2083
2083
2084 def addglobalopts(aliases):
2084 def addglobalopts(aliases):
2085 if ui.verbose:
2085 if ui.verbose:
2086 option_lists.append((_("global options:"), globalopts))
2086 option_lists.append((_("global options:"), globalopts))
2087 if name == 'shortlist':
2087 if name == 'shortlist':
2088 option_lists.append((_('use "hg help" for the full list '
2088 option_lists.append((_('use "hg help" for the full list '
2089 'of commands'), ()))
2089 'of commands'), ()))
2090 else:
2090 else:
2091 if name == 'shortlist':
2091 if name == 'shortlist':
2092 msg = _('use "hg help" for the full list of commands '
2092 msg = _('use "hg help" for the full list of commands '
2093 'or "hg -v" for details')
2093 'or "hg -v" for details')
2094 elif aliases:
2094 elif aliases:
2095 msg = _('use "hg -v help%s" to show builtin aliases and '
2095 msg = _('use "hg -v help%s" to show builtin aliases and '
2096 'global options') % (name and " " + name or "")
2096 'global options') % (name and " " + name or "")
2097 else:
2097 else:
2098 msg = _('use "hg -v help %s" to show global options') % name
2098 msg = _('use "hg -v help %s" to show global options') % name
2099 option_lists.append((msg, ()))
2099 option_lists.append((msg, ()))
2100
2100
2101 def helpcmd(name):
2101 def helpcmd(name):
2102 if with_version:
2102 if with_version:
2103 version_(ui)
2103 version_(ui)
2104 ui.write('\n')
2104 ui.write('\n')
2105
2105
2106 try:
2106 try:
2107 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2107 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2108 except error.AmbiguousCommand, inst:
2108 except error.AmbiguousCommand, inst:
2109 # py3k fix: except vars can't be used outside the scope of the
2109 # py3k fix: except vars can't be used outside the scope of the
2110 # except block, nor can be used inside a lambda. python issue4617
2110 # except block, nor can be used inside a lambda. python issue4617
2111 prefix = inst.args[0]
2111 prefix = inst.args[0]
2112 select = lambda c: c.lstrip('^').startswith(prefix)
2112 select = lambda c: c.lstrip('^').startswith(prefix)
2113 helplist(_('list of commands:\n\n'), select)
2113 helplist(_('list of commands:\n\n'), select)
2114 return
2114 return
2115
2115
2116 # check if it's an invalid alias and display its error if it is
2116 # check if it's an invalid alias and display its error if it is
2117 if getattr(entry[0], 'badalias', False):
2117 if getattr(entry[0], 'badalias', False):
2118 if not unknowncmd:
2118 if not unknowncmd:
2119 entry[0](ui)
2119 entry[0](ui)
2120 return
2120 return
2121
2121
2122 # synopsis
2122 # synopsis
2123 if len(entry) > 2:
2123 if len(entry) > 2:
2124 if entry[2].startswith('hg'):
2124 if entry[2].startswith('hg'):
2125 ui.write("%s\n" % entry[2])
2125 ui.write("%s\n" % entry[2])
2126 else:
2126 else:
2127 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2127 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2128 else:
2128 else:
2129 ui.write('hg %s\n' % aliases[0])
2129 ui.write('hg %s\n' % aliases[0])
2130
2130
2131 # aliases
2131 # aliases
2132 if not ui.quiet and len(aliases) > 1:
2132 if not ui.quiet and len(aliases) > 1:
2133 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2133 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2134
2134
2135 # description
2135 # description
2136 doc = gettext(entry[0].__doc__)
2136 doc = gettext(entry[0].__doc__)
2137 if not doc:
2137 if not doc:
2138 doc = _("(no help text available)")
2138 doc = _("(no help text available)")
2139 if hasattr(entry[0], 'definition'): # aliased command
2139 if hasattr(entry[0], 'definition'): # aliased command
2140 if entry[0].definition.startswith('!'): # shell alias
2140 if entry[0].definition.startswith('!'): # shell alias
2141 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2141 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2142 else:
2142 else:
2143 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2143 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2144 if ui.quiet:
2144 if ui.quiet:
2145 doc = doc.splitlines()[0]
2145 doc = doc.splitlines()[0]
2146 keep = ui.verbose and ['verbose'] or []
2146 keep = ui.verbose and ['verbose'] or []
2147 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2147 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2148 ui.write("\n%s\n" % formatted)
2148 ui.write("\n%s\n" % formatted)
2149 if pruned:
2149 if pruned:
2150 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2150 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2151
2151
2152 if not ui.quiet:
2152 if not ui.quiet:
2153 # options
2153 # options
2154 if entry[1]:
2154 if entry[1]:
2155 option_lists.append((_("options:\n"), entry[1]))
2155 option_lists.append((_("options:\n"), entry[1]))
2156
2156
2157 addglobalopts(False)
2157 addglobalopts(False)
2158
2158
2159 def helplist(header, select=None):
2159 def helplist(header, select=None):
2160 h = {}
2160 h = {}
2161 cmds = {}
2161 cmds = {}
2162 for c, e in table.iteritems():
2162 for c, e in table.iteritems():
2163 f = c.split("|", 1)[0]
2163 f = c.split("|", 1)[0]
2164 if select and not select(f):
2164 if select and not select(f):
2165 continue
2165 continue
2166 if (not select and name != 'shortlist' and
2166 if (not select and name != 'shortlist' and
2167 e[0].__module__ != __name__):
2167 e[0].__module__ != __name__):
2168 continue
2168 continue
2169 if name == "shortlist" and not f.startswith("^"):
2169 if name == "shortlist" and not f.startswith("^"):
2170 continue
2170 continue
2171 f = f.lstrip("^")
2171 f = f.lstrip("^")
2172 if not ui.debugflag and f.startswith("debug"):
2172 if not ui.debugflag and f.startswith("debug"):
2173 continue
2173 continue
2174 doc = e[0].__doc__
2174 doc = e[0].__doc__
2175 if doc and 'DEPRECATED' in doc and not ui.verbose:
2175 if doc and 'DEPRECATED' in doc and not ui.verbose:
2176 continue
2176 continue
2177 doc = gettext(doc)
2177 doc = gettext(doc)
2178 if not doc:
2178 if not doc:
2179 doc = _("(no help text available)")
2179 doc = _("(no help text available)")
2180 h[f] = doc.splitlines()[0].rstrip()
2180 h[f] = doc.splitlines()[0].rstrip()
2181 cmds[f] = c.lstrip("^")
2181 cmds[f] = c.lstrip("^")
2182
2182
2183 if not h:
2183 if not h:
2184 ui.status(_('no commands defined\n'))
2184 ui.status(_('no commands defined\n'))
2185 return
2185 return
2186
2186
2187 ui.status(header)
2187 ui.status(header)
2188 fns = sorted(h)
2188 fns = sorted(h)
2189 m = max(map(len, fns))
2189 m = max(map(len, fns))
2190 for f in fns:
2190 for f in fns:
2191 if ui.verbose:
2191 if ui.verbose:
2192 commands = cmds[f].replace("|",", ")
2192 commands = cmds[f].replace("|",", ")
2193 ui.write(" %s:\n %s\n"%(commands, h[f]))
2193 ui.write(" %s:\n %s\n"%(commands, h[f]))
2194 else:
2194 else:
2195 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2195 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2196 initindent=' %-*s ' % (m, f),
2196 initindent=' %-*s ' % (m, f),
2197 hangindent=' ' * (m + 4))))
2197 hangindent=' ' * (m + 4))))
2198
2198
2199 if not ui.quiet:
2199 if not ui.quiet:
2200 addglobalopts(True)
2200 addglobalopts(True)
2201
2201
2202 def helptopic(name):
2202 def helptopic(name):
2203 for names, header, doc in help.helptable:
2203 for names, header, doc in help.helptable:
2204 if name in names:
2204 if name in names:
2205 break
2205 break
2206 else:
2206 else:
2207 raise error.UnknownCommand(name)
2207 raise error.UnknownCommand(name)
2208
2208
2209 # description
2209 # description
2210 if not doc:
2210 if not doc:
2211 doc = _("(no help text available)")
2211 doc = _("(no help text available)")
2212 if hasattr(doc, '__call__'):
2212 if hasattr(doc, '__call__'):
2213 doc = doc()
2213 doc = doc()
2214
2214
2215 ui.write("%s\n\n" % header)
2215 ui.write("%s\n\n" % header)
2216 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2216 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2217
2217
2218 def helpext(name):
2218 def helpext(name):
2219 try:
2219 try:
2220 mod = extensions.find(name)
2220 mod = extensions.find(name)
2221 doc = gettext(mod.__doc__) or _('no help text available')
2221 doc = gettext(mod.__doc__) or _('no help text available')
2222 except KeyError:
2222 except KeyError:
2223 mod = None
2223 mod = None
2224 doc = extensions.disabledext(name)
2224 doc = extensions.disabledext(name)
2225 if not doc:
2225 if not doc:
2226 raise error.UnknownCommand(name)
2226 raise error.UnknownCommand(name)
2227
2227
2228 if '\n' not in doc:
2228 if '\n' not in doc:
2229 head, tail = doc, ""
2229 head, tail = doc, ""
2230 else:
2230 else:
2231 head, tail = doc.split('\n', 1)
2231 head, tail = doc.split('\n', 1)
2232 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2232 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2233 if tail:
2233 if tail:
2234 ui.write(minirst.format(tail, textwidth))
2234 ui.write(minirst.format(tail, textwidth))
2235 ui.status('\n\n')
2235 ui.status('\n\n')
2236
2236
2237 if mod:
2237 if mod:
2238 try:
2238 try:
2239 ct = mod.cmdtable
2239 ct = mod.cmdtable
2240 except AttributeError:
2240 except AttributeError:
2241 ct = {}
2241 ct = {}
2242 modcmds = set([c.split('|', 1)[0] for c in ct])
2242 modcmds = set([c.split('|', 1)[0] for c in ct])
2243 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2243 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2244 else:
2244 else:
2245 ui.write(_('use "hg help extensions" for information on enabling '
2245 ui.write(_('use "hg help extensions" for information on enabling '
2246 'extensions\n'))
2246 'extensions\n'))
2247
2247
2248 def helpextcmd(name):
2248 def helpextcmd(name):
2249 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2249 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2250 doc = gettext(mod.__doc__).splitlines()[0]
2250 doc = gettext(mod.__doc__).splitlines()[0]
2251
2251
2252 msg = help.listexts(_("'%s' is provided by the following "
2252 msg = help.listexts(_("'%s' is provided by the following "
2253 "extension:") % cmd, {ext: doc}, len(ext),
2253 "extension:") % cmd, {ext: doc}, len(ext),
2254 indent=4)
2254 indent=4)
2255 ui.write(minirst.format(msg, textwidth))
2255 ui.write(minirst.format(msg, textwidth))
2256 ui.write('\n\n')
2256 ui.write('\n\n')
2257 ui.write(_('use "hg help extensions" for information on enabling '
2257 ui.write(_('use "hg help extensions" for information on enabling '
2258 'extensions\n'))
2258 'extensions\n'))
2259
2259
2260 help.addtopichook('revsets', revset.makedoc)
2260 help.addtopichook('revsets', revset.makedoc)
2261 help.addtopichook('templates', templatekw.makedoc)
2261 help.addtopichook('templates', templatekw.makedoc)
2262 help.addtopichook('templates', templatefilters.makedoc)
2262 help.addtopichook('templates', templatefilters.makedoc)
2263
2263
2264 if name and name != 'shortlist':
2264 if name and name != 'shortlist':
2265 i = None
2265 i = None
2266 if unknowncmd:
2266 if unknowncmd:
2267 queries = (helpextcmd,)
2267 queries = (helpextcmd,)
2268 else:
2268 else:
2269 queries = (helptopic, helpcmd, helpext, helpextcmd)
2269 queries = (helptopic, helpcmd, helpext, helpextcmd)
2270 for f in queries:
2270 for f in queries:
2271 try:
2271 try:
2272 f(name)
2272 f(name)
2273 i = None
2273 i = None
2274 break
2274 break
2275 except error.UnknownCommand, inst:
2275 except error.UnknownCommand, inst:
2276 i = inst
2276 i = inst
2277 if i:
2277 if i:
2278 raise i
2278 raise i
2279
2279
2280 else:
2280 else:
2281 # program name
2281 # program name
2282 if ui.verbose or with_version:
2282 if ui.verbose or with_version:
2283 version_(ui)
2283 version_(ui)
2284 else:
2284 else:
2285 ui.status(_("Mercurial Distributed SCM\n"))
2285 ui.status(_("Mercurial Distributed SCM\n"))
2286 ui.status('\n')
2286 ui.status('\n')
2287
2287
2288 # list of commands
2288 # list of commands
2289 if name == "shortlist":
2289 if name == "shortlist":
2290 header = _('basic commands:\n\n')
2290 header = _('basic commands:\n\n')
2291 else:
2291 else:
2292 header = _('list of commands:\n\n')
2292 header = _('list of commands:\n\n')
2293
2293
2294 helplist(header)
2294 helplist(header)
2295 if name != 'shortlist':
2295 if name != 'shortlist':
2296 exts, maxlength = extensions.enabled()
2296 exts, maxlength = extensions.enabled()
2297 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2297 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2298 if text:
2298 if text:
2299 ui.write("\n%s\n" % minirst.format(text, textwidth))
2299 ui.write("\n%s\n" % minirst.format(text, textwidth))
2300
2300
2301 # list all option lists
2301 # list all option lists
2302 opt_output = []
2302 opt_output = []
2303 multioccur = False
2303 multioccur = False
2304 for title, options in option_lists:
2304 for title, options in option_lists:
2305 opt_output.append(("\n%s" % title, None))
2305 opt_output.append(("\n%s" % title, None))
2306 for option in options:
2306 for option in options:
2307 if len(option) == 5:
2307 if len(option) == 5:
2308 shortopt, longopt, default, desc, optlabel = option
2308 shortopt, longopt, default, desc, optlabel = option
2309 else:
2309 else:
2310 shortopt, longopt, default, desc = option
2310 shortopt, longopt, default, desc = option
2311 optlabel = _("VALUE") # default label
2311 optlabel = _("VALUE") # default label
2312
2312
2313 if _("DEPRECATED") in desc and not ui.verbose:
2313 if _("DEPRECATED") in desc and not ui.verbose:
2314 continue
2314 continue
2315 if isinstance(default, list):
2315 if isinstance(default, list):
2316 numqualifier = " %s [+]" % optlabel
2316 numqualifier = " %s [+]" % optlabel
2317 multioccur = True
2317 multioccur = True
2318 elif (default is not None) and not isinstance(default, bool):
2318 elif (default is not None) and not isinstance(default, bool):
2319 numqualifier = " %s" % optlabel
2319 numqualifier = " %s" % optlabel
2320 else:
2320 else:
2321 numqualifier = ""
2321 numqualifier = ""
2322 opt_output.append(("%2s%s" %
2322 opt_output.append(("%2s%s" %
2323 (shortopt and "-%s" % shortopt,
2323 (shortopt and "-%s" % shortopt,
2324 longopt and " --%s%s" %
2324 longopt and " --%s%s" %
2325 (longopt, numqualifier)),
2325 (longopt, numqualifier)),
2326 "%s%s" % (desc,
2326 "%s%s" % (desc,
2327 default
2327 default
2328 and _(" (default: %s)") % default
2328 and _(" (default: %s)") % default
2329 or "")))
2329 or "")))
2330 if multioccur:
2330 if multioccur:
2331 msg = _("\n[+] marked option can be specified multiple times")
2331 msg = _("\n[+] marked option can be specified multiple times")
2332 if ui.verbose and name != 'shortlist':
2332 if ui.verbose and name != 'shortlist':
2333 opt_output.append((msg, None))
2333 opt_output.append((msg, None))
2334 else:
2334 else:
2335 opt_output.insert(-1, (msg, None))
2335 opt_output.insert(-1, (msg, None))
2336
2336
2337 if not name:
2337 if not name:
2338 ui.write(_("\nadditional help topics:\n\n"))
2338 ui.write(_("\nadditional help topics:\n\n"))
2339 topics = []
2339 topics = []
2340 for names, header, doc in help.helptable:
2340 for names, header, doc in help.helptable:
2341 topics.append((sorted(names, key=len, reverse=True)[0], header))
2341 topics.append((sorted(names, key=len, reverse=True)[0], header))
2342 topics_len = max([len(s[0]) for s in topics])
2342 topics_len = max([len(s[0]) for s in topics])
2343 for t, desc in topics:
2343 for t, desc in topics:
2344 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2344 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2345
2345
2346 if opt_output:
2346 if opt_output:
2347 colwidth = encoding.colwidth
2347 colwidth = encoding.colwidth
2348 # normalize: (opt or message, desc or None, width of opt)
2348 # normalize: (opt or message, desc or None, width of opt)
2349 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2349 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2350 for opt, desc in opt_output]
2350 for opt, desc in opt_output]
2351 hanging = max([e[2] for e in entries])
2351 hanging = max([e[2] for e in entries])
2352 for opt, desc, width in entries:
2352 for opt, desc, width in entries:
2353 if desc:
2353 if desc:
2354 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2354 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2355 hangindent = ' ' * (hanging + 3)
2355 hangindent = ' ' * (hanging + 3)
2356 ui.write('%s\n' % (util.wrap(desc, textwidth,
2356 ui.write('%s\n' % (util.wrap(desc, textwidth,
2357 initindent=initindent,
2357 initindent=initindent,
2358 hangindent=hangindent)))
2358 hangindent=hangindent)))
2359 else:
2359 else:
2360 ui.write("%s\n" % opt)
2360 ui.write("%s\n" % opt)
2361
2361
2362 def identify(ui, repo, source=None, rev=None,
2362 def identify(ui, repo, source=None, rev=None,
2363 num=None, id=None, branch=None, tags=None, bookmarks=None):
2363 num=None, id=None, branch=None, tags=None, bookmarks=None):
2364 """identify the working copy or specified revision
2364 """identify the working copy or specified revision
2365
2365
2366 With no revision, print a summary of the current state of the
2366 With no revision, print a summary of the current state of the
2367 repository.
2367 repository.
2368
2368
2369 Specifying a path to a repository root or Mercurial bundle will
2369 Specifying a path to a repository root or Mercurial bundle will
2370 cause lookup to operate on that repository/bundle.
2370 cause lookup to operate on that repository/bundle.
2371
2371
2372 This summary identifies the repository state using one or two
2372 This summary identifies the repository state using one or two
2373 parent hash identifiers, followed by a "+" if there are
2373 parent hash identifiers, followed by a "+" if there are
2374 uncommitted changes in the working directory, a list of tags for
2374 uncommitted changes in the working directory, a list of tags for
2375 this revision and a branch name for non-default branches.
2375 this revision and a branch name for non-default branches.
2376
2376
2377 Returns 0 if successful.
2377 Returns 0 if successful.
2378 """
2378 """
2379
2379
2380 if not repo and not source:
2380 if not repo and not source:
2381 raise util.Abort(_("there is no Mercurial repository here "
2381 raise util.Abort(_("there is no Mercurial repository here "
2382 "(.hg not found)"))
2382 "(.hg not found)"))
2383
2383
2384 hexfunc = ui.debugflag and hex or short
2384 hexfunc = ui.debugflag and hex or short
2385 default = not (num or id or branch or tags or bookmarks)
2385 default = not (num or id or branch or tags or bookmarks)
2386 output = []
2386 output = []
2387
2387
2388 revs = []
2388 revs = []
2389 bms = []
2389 bms = []
2390 if source:
2390 if source:
2391 source, branches = hg.parseurl(ui.expandpath(source))
2391 source, branches = hg.parseurl(ui.expandpath(source))
2392 repo = hg.repository(ui, source)
2392 repo = hg.repository(ui, source)
2393 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2393 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2394
2394
2395 if not repo.local():
2395 if not repo.local():
2396 if not rev and revs:
2396 if not rev and revs:
2397 rev = revs[0]
2397 rev = revs[0]
2398 if not rev:
2398 if not rev:
2399 rev = "tip"
2399 rev = "tip"
2400 if num or branch or tags:
2400 if num or branch or tags:
2401 raise util.Abort(
2401 raise util.Abort(
2402 _("can't query remote revision number, branch, or tags"))
2402 _("can't query remote revision number, branch, or tags"))
2403
2403
2404 remoterev = repo.lookup(rev)
2404 remoterev = repo.lookup(rev)
2405 if default or id:
2405 if default or id:
2406 output = [hexfunc(remoterev)]
2406 output = [hexfunc(remoterev)]
2407
2407
2408 if 'bookmarks' in repo.listkeys('namespaces'):
2408 if 'bookmarks' in repo.listkeys('namespaces'):
2409 hexremoterev = hex(remoterev)
2409 hexremoterev = hex(remoterev)
2410 bms = [bm for bm, bmrev in repo.listkeys('bookmarks').iteritems()
2410 bms = [bm for bm, bmrev in repo.listkeys('bookmarks').iteritems()
2411 if bmrev == hexremoterev]
2411 if bmrev == hexremoterev]
2412
2412
2413 elif not rev:
2413 elif not rev:
2414 ctx = repo[None]
2414 ctx = repo[None]
2415 parents = ctx.parents()
2415 parents = ctx.parents()
2416 changed = False
2416 changed = False
2417 if default or id or num:
2417 if default or id or num:
2418 changed = util.any(repo.status())
2418 changed = util.any(repo.status())
2419 if default or id:
2419 if default or id:
2420 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2420 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2421 (changed) and "+" or "")]
2421 (changed) and "+" or "")]
2422 if num:
2422 if num:
2423 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2423 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2424 (changed) and "+" or ""))
2424 (changed) and "+" or ""))
2425 else:
2425 else:
2426 ctx = cmdutil.revsingle(repo, rev)
2426 ctx = cmdutil.revsingle(repo, rev)
2427 if default or id:
2427 if default or id:
2428 output = [hexfunc(ctx.node())]
2428 output = [hexfunc(ctx.node())]
2429 if num:
2429 if num:
2430 output.append(str(ctx.rev()))
2430 output.append(str(ctx.rev()))
2431
2431
2432 if repo.local():
2432 if repo.local():
2433 bms = ctx.bookmarks()
2433 bms = ctx.bookmarks()
2434
2434
2435 if repo.local() and default and not ui.quiet:
2435 if repo.local() and default and not ui.quiet:
2436 b = ctx.branch()
2436 b = ctx.branch()
2437 if b != 'default':
2437 if b != 'default':
2438 output.append("(%s)" % b)
2438 output.append("(%s)" % b)
2439
2439
2440 # multiple tags for a single parent separated by '/'
2440 # multiple tags for a single parent separated by '/'
2441 t = "/".join(ctx.tags())
2441 t = "/".join(ctx.tags())
2442 if t:
2442 if t:
2443 output.append(t)
2443 output.append(t)
2444
2444
2445 if default and not ui.quiet:
2445 if default and not ui.quiet:
2446 # multiple bookmarks for a single parent separated by '/'
2446 # multiple bookmarks for a single parent separated by '/'
2447 bm = '/'.join(bms)
2447 bm = '/'.join(bms)
2448 if bm:
2448 if bm:
2449 output.append(bm)
2449 output.append(bm)
2450
2450
2451 if branch:
2451 if branch:
2452 output.append(ctx.branch())
2452 output.append(ctx.branch())
2453
2453
2454 if tags:
2454 if tags:
2455 output.extend(ctx.tags())
2455 output.extend(ctx.tags())
2456
2456
2457 if bookmarks:
2457 if bookmarks:
2458 output.extend(bms)
2458 output.extend(bms)
2459
2459
2460 ui.write("%s\n" % ' '.join(output))
2460 ui.write("%s\n" % ' '.join(output))
2461
2461
2462 def import_(ui, repo, patch1, *patches, **opts):
2462 def import_(ui, repo, patch1, *patches, **opts):
2463 """import an ordered set of patches
2463 """import an ordered set of patches
2464
2464
2465 Import a list of patches and commit them individually (unless
2465 Import a list of patches and commit them individually (unless
2466 --no-commit is specified).
2466 --no-commit is specified).
2467
2467
2468 If there are outstanding changes in the working directory, import
2468 If there are outstanding changes in the working directory, import
2469 will abort unless given the -f/--force flag.
2469 will abort unless given the -f/--force flag.
2470
2470
2471 You can import a patch straight from a mail message. Even patches
2471 You can import a patch straight from a mail message. Even patches
2472 as attachments work (to use the body part, it must have type
2472 as attachments work (to use the body part, it must have type
2473 text/plain or text/x-patch). From and Subject headers of email
2473 text/plain or text/x-patch). From and Subject headers of email
2474 message are used as default committer and commit message. All
2474 message are used as default committer and commit message. All
2475 text/plain body parts before first diff are added to commit
2475 text/plain body parts before first diff are added to commit
2476 message.
2476 message.
2477
2477
2478 If the imported patch was generated by :hg:`export`, user and
2478 If the imported patch was generated by :hg:`export`, user and
2479 description from patch override values from message headers and
2479 description from patch override values from message headers and
2480 body. Values given on command line with -m/--message and -u/--user
2480 body. Values given on command line with -m/--message and -u/--user
2481 override these.
2481 override these.
2482
2482
2483 If --exact is specified, import will set the working directory to
2483 If --exact is specified, import will set the working directory to
2484 the parent of each patch before applying it, and will abort if the
2484 the parent of each patch before applying it, and will abort if the
2485 resulting changeset has a different ID than the one recorded in
2485 resulting changeset has a different ID than the one recorded in
2486 the patch. This may happen due to character set problems or other
2486 the patch. This may happen due to character set problems or other
2487 deficiencies in the text patch format.
2487 deficiencies in the text patch format.
2488
2488
2489 With -s/--similarity, hg will attempt to discover renames and
2489 With -s/--similarity, hg will attempt to discover renames and
2490 copies in the patch in the same way as 'addremove'.
2490 copies in the patch in the same way as 'addremove'.
2491
2491
2492 To read a patch from standard input, use "-" as the patch name. If
2492 To read a patch from standard input, use "-" as the patch name. If
2493 a URL is specified, the patch will be downloaded from it.
2493 a URL is specified, the patch will be downloaded from it.
2494 See :hg:`help dates` for a list of formats valid for -d/--date.
2494 See :hg:`help dates` for a list of formats valid for -d/--date.
2495
2495
2496 Returns 0 on success.
2496 Returns 0 on success.
2497 """
2497 """
2498 patches = (patch1,) + patches
2498 patches = (patch1,) + patches
2499
2499
2500 date = opts.get('date')
2500 date = opts.get('date')
2501 if date:
2501 if date:
2502 opts['date'] = util.parsedate(date)
2502 opts['date'] = util.parsedate(date)
2503
2503
2504 try:
2504 try:
2505 sim = float(opts.get('similarity') or 0)
2505 sim = float(opts.get('similarity') or 0)
2506 except ValueError:
2506 except ValueError:
2507 raise util.Abort(_('similarity must be a number'))
2507 raise util.Abort(_('similarity must be a number'))
2508 if sim < 0 or sim > 100:
2508 if sim < 0 or sim > 100:
2509 raise util.Abort(_('similarity must be between 0 and 100'))
2509 raise util.Abort(_('similarity must be between 0 and 100'))
2510
2510
2511 if opts.get('exact') or not opts.get('force'):
2511 if opts.get('exact') or not opts.get('force'):
2512 cmdutil.bail_if_changed(repo)
2512 cmdutil.bail_if_changed(repo)
2513
2513
2514 d = opts["base"]
2514 d = opts["base"]
2515 strip = opts["strip"]
2515 strip = opts["strip"]
2516 wlock = lock = None
2516 wlock = lock = None
2517 msgs = []
2517 msgs = []
2518
2518
2519 def tryone(ui, hunk):
2519 def tryone(ui, hunk):
2520 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2520 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2521 patch.extract(ui, hunk)
2521 patch.extract(ui, hunk)
2522
2522
2523 if not tmpname:
2523 if not tmpname:
2524 return None
2524 return None
2525 commitid = _('to working directory')
2525 commitid = _('to working directory')
2526
2526
2527 try:
2527 try:
2528 cmdline_message = cmdutil.logmessage(opts)
2528 cmdline_message = cmdutil.logmessage(opts)
2529 if cmdline_message:
2529 if cmdline_message:
2530 # pickup the cmdline msg
2530 # pickup the cmdline msg
2531 message = cmdline_message
2531 message = cmdline_message
2532 elif message:
2532 elif message:
2533 # pickup the patch msg
2533 # pickup the patch msg
2534 message = message.strip()
2534 message = message.strip()
2535 else:
2535 else:
2536 # launch the editor
2536 # launch the editor
2537 message = None
2537 message = None
2538 ui.debug('message:\n%s\n' % message)
2538 ui.debug('message:\n%s\n' % message)
2539
2539
2540 wp = repo.parents()
2540 wp = repo.parents()
2541 if opts.get('exact'):
2541 if opts.get('exact'):
2542 if not nodeid or not p1:
2542 if not nodeid or not p1:
2543 raise util.Abort(_('not a Mercurial patch'))
2543 raise util.Abort(_('not a Mercurial patch'))
2544 p1 = repo.lookup(p1)
2544 p1 = repo.lookup(p1)
2545 p2 = repo.lookup(p2 or hex(nullid))
2545 p2 = repo.lookup(p2 or hex(nullid))
2546
2546
2547 if p1 != wp[0].node():
2547 if p1 != wp[0].node():
2548 hg.clean(repo, p1)
2548 hg.clean(repo, p1)
2549 repo.dirstate.setparents(p1, p2)
2549 repo.dirstate.setparents(p1, p2)
2550 elif p2:
2550 elif p2:
2551 try:
2551 try:
2552 p1 = repo.lookup(p1)
2552 p1 = repo.lookup(p1)
2553 p2 = repo.lookup(p2)
2553 p2 = repo.lookup(p2)
2554 if p1 == wp[0].node():
2554 if p1 == wp[0].node():
2555 repo.dirstate.setparents(p1, p2)
2555 repo.dirstate.setparents(p1, p2)
2556 except error.RepoError:
2556 except error.RepoError:
2557 pass
2557 pass
2558 if opts.get('exact') or opts.get('import_branch'):
2558 if opts.get('exact') or opts.get('import_branch'):
2559 repo.dirstate.setbranch(branch or 'default')
2559 repo.dirstate.setbranch(branch or 'default')
2560
2560
2561 files = {}
2561 files = {}
2562 try:
2562 try:
2563 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2563 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2564 files=files, eolmode=None)
2564 files=files, eolmode=None)
2565 finally:
2565 finally:
2566 files = cmdutil.updatedir(ui, repo, files,
2566 files = cmdutil.updatedir(ui, repo, files,
2567 similarity=sim / 100.0)
2567 similarity=sim / 100.0)
2568 if opts.get('no_commit'):
2568 if opts.get('no_commit'):
2569 if message:
2569 if message:
2570 msgs.append(message)
2570 msgs.append(message)
2571 else:
2571 else:
2572 if opts.get('exact'):
2572 if opts.get('exact'):
2573 m = None
2573 m = None
2574 else:
2574 else:
2575 m = cmdutil.matchfiles(repo, files or [])
2575 m = cmdutil.matchfiles(repo, files or [])
2576 n = repo.commit(message, opts.get('user') or user,
2576 n = repo.commit(message, opts.get('user') or user,
2577 opts.get('date') or date, match=m,
2577 opts.get('date') or date, match=m,
2578 editor=cmdutil.commiteditor)
2578 editor=cmdutil.commiteditor)
2579 if opts.get('exact'):
2579 if opts.get('exact'):
2580 if hex(n) != nodeid:
2580 if hex(n) != nodeid:
2581 repo.rollback()
2581 repo.rollback()
2582 raise util.Abort(_('patch is damaged'
2582 raise util.Abort(_('patch is damaged'
2583 ' or loses information'))
2583 ' or loses information'))
2584 # Force a dirstate write so that the next transaction
2584 # Force a dirstate write so that the next transaction
2585 # backups an up-do-date file.
2585 # backups an up-do-date file.
2586 repo.dirstate.write()
2586 repo.dirstate.write()
2587 if n:
2587 if n:
2588 commitid = short(n)
2588 commitid = short(n)
2589
2589
2590 return commitid
2590 return commitid
2591 finally:
2591 finally:
2592 os.unlink(tmpname)
2592 os.unlink(tmpname)
2593
2593
2594 try:
2594 try:
2595 wlock = repo.wlock()
2595 wlock = repo.wlock()
2596 lock = repo.lock()
2596 lock = repo.lock()
2597 lastcommit = None
2597 lastcommit = None
2598 for p in patches:
2598 for p in patches:
2599 pf = os.path.join(d, p)
2599 pf = os.path.join(d, p)
2600
2600
2601 if pf == '-':
2601 if pf == '-':
2602 ui.status(_("applying patch from stdin\n"))
2602 ui.status(_("applying patch from stdin\n"))
2603 pf = sys.stdin
2603 pf = sys.stdin
2604 else:
2604 else:
2605 ui.status(_("applying %s\n") % p)
2605 ui.status(_("applying %s\n") % p)
2606 pf = url.open(ui, pf)
2606 pf = url.open(ui, pf)
2607
2607
2608 haspatch = False
2608 haspatch = False
2609 for hunk in patch.split(pf):
2609 for hunk in patch.split(pf):
2610 commitid = tryone(ui, hunk)
2610 commitid = tryone(ui, hunk)
2611 if commitid:
2611 if commitid:
2612 haspatch = True
2612 haspatch = True
2613 if lastcommit:
2613 if lastcommit:
2614 ui.status(_('applied %s\n') % lastcommit)
2614 ui.status(_('applied %s\n') % lastcommit)
2615 lastcommit = commitid
2615 lastcommit = commitid
2616
2616
2617 if not haspatch:
2617 if not haspatch:
2618 raise util.Abort(_('no diffs found'))
2618 raise util.Abort(_('no diffs found'))
2619
2619
2620 if msgs:
2620 if msgs:
2621 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2621 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2622 finally:
2622 finally:
2623 release(lock, wlock)
2623 release(lock, wlock)
2624
2624
2625 def incoming(ui, repo, source="default", **opts):
2625 def incoming(ui, repo, source="default", **opts):
2626 """show new changesets found in source
2626 """show new changesets found in source
2627
2627
2628 Show new changesets found in the specified path/URL or the default
2628 Show new changesets found in the specified path/URL or the default
2629 pull location. These are the changesets that would have been pulled
2629 pull location. These are the changesets that would have been pulled
2630 if a pull at the time you issued this command.
2630 if a pull at the time you issued this command.
2631
2631
2632 For remote repository, using --bundle avoids downloading the
2632 For remote repository, using --bundle avoids downloading the
2633 changesets twice if the incoming is followed by a pull.
2633 changesets twice if the incoming is followed by a pull.
2634
2634
2635 See pull for valid source format details.
2635 See pull for valid source format details.
2636
2636
2637 Returns 0 if there are incoming changes, 1 otherwise.
2637 Returns 0 if there are incoming changes, 1 otherwise.
2638 """
2638 """
2639 if opts.get('bundle') and opts.get('subrepos'):
2639 if opts.get('bundle') and opts.get('subrepos'):
2640 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2640 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2641
2641
2642 if opts.get('bookmarks'):
2642 if opts.get('bookmarks'):
2643 source, branches = hg.parseurl(ui.expandpath(source),
2643 source, branches = hg.parseurl(ui.expandpath(source),
2644 opts.get('branch'))
2644 opts.get('branch'))
2645 other = hg.repository(hg.remoteui(repo, opts), source)
2645 other = hg.repository(hg.remoteui(repo, opts), source)
2646 if 'bookmarks' not in other.listkeys('namespaces'):
2646 if 'bookmarks' not in other.listkeys('namespaces'):
2647 ui.warn(_("remote doesn't support bookmarks\n"))
2647 ui.warn(_("remote doesn't support bookmarks\n"))
2648 return 0
2648 return 0
2649 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2649 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2650 return bookmarks.diff(ui, repo, other)
2650 return bookmarks.diff(ui, repo, other)
2651
2651
2652 ret = hg.incoming(ui, repo, source, opts)
2652 ret = hg.incoming(ui, repo, source, opts)
2653 return ret
2653 return ret
2654
2654
2655 def init(ui, dest=".", **opts):
2655 def init(ui, dest=".", **opts):
2656 """create a new repository in the given directory
2656 """create a new repository in the given directory
2657
2657
2658 Initialize a new repository in the given directory. If the given
2658 Initialize a new repository in the given directory. If the given
2659 directory does not exist, it will be created.
2659 directory does not exist, it will be created.
2660
2660
2661 If no directory is given, the current directory is used.
2661 If no directory is given, the current directory is used.
2662
2662
2663 It is possible to specify an ``ssh://`` URL as the destination.
2663 It is possible to specify an ``ssh://`` URL as the destination.
2664 See :hg:`help urls` for more information.
2664 See :hg:`help urls` for more information.
2665
2665
2666 Returns 0 on success.
2666 Returns 0 on success.
2667 """
2667 """
2668 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2668 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2669
2669
2670 def locate(ui, repo, *pats, **opts):
2670 def locate(ui, repo, *pats, **opts):
2671 """locate files matching specific patterns
2671 """locate files matching specific patterns
2672
2672
2673 Print files under Mercurial control in the working directory whose
2673 Print files under Mercurial control in the working directory whose
2674 names match the given patterns.
2674 names match the given patterns.
2675
2675
2676 By default, this command searches all directories in the working
2676 By default, this command searches all directories in the working
2677 directory. To search just the current directory and its
2677 directory. To search just the current directory and its
2678 subdirectories, use "--include .".
2678 subdirectories, use "--include .".
2679
2679
2680 If no patterns are given to match, this command prints the names
2680 If no patterns are given to match, this command prints the names
2681 of all files under Mercurial control in the working directory.
2681 of all files under Mercurial control in the working directory.
2682
2682
2683 If you want to feed the output of this command into the "xargs"
2683 If you want to feed the output of this command into the "xargs"
2684 command, use the -0 option to both this command and "xargs". This
2684 command, use the -0 option to both this command and "xargs". This
2685 will avoid the problem of "xargs" treating single filenames that
2685 will avoid the problem of "xargs" treating single filenames that
2686 contain whitespace as multiple filenames.
2686 contain whitespace as multiple filenames.
2687
2687
2688 Returns 0 if a match is found, 1 otherwise.
2688 Returns 0 if a match is found, 1 otherwise.
2689 """
2689 """
2690 end = opts.get('print0') and '\0' or '\n'
2690 end = opts.get('print0') and '\0' or '\n'
2691 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2691 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2692
2692
2693 ret = 1
2693 ret = 1
2694 m = cmdutil.match(repo, pats, opts, default='relglob')
2694 m = cmdutil.match(repo, pats, opts, default='relglob')
2695 m.bad = lambda x, y: False
2695 m.bad = lambda x, y: False
2696 for abs in repo[rev].walk(m):
2696 for abs in repo[rev].walk(m):
2697 if not rev and abs not in repo.dirstate:
2697 if not rev and abs not in repo.dirstate:
2698 continue
2698 continue
2699 if opts.get('fullpath'):
2699 if opts.get('fullpath'):
2700 ui.write(repo.wjoin(abs), end)
2700 ui.write(repo.wjoin(abs), end)
2701 else:
2701 else:
2702 ui.write(((pats and m.rel(abs)) or abs), end)
2702 ui.write(((pats and m.rel(abs)) or abs), end)
2703 ret = 0
2703 ret = 0
2704
2704
2705 return ret
2705 return ret
2706
2706
2707 def log(ui, repo, *pats, **opts):
2707 def log(ui, repo, *pats, **opts):
2708 """show revision history of entire repository or files
2708 """show revision history of entire repository or files
2709
2709
2710 Print the revision history of the specified files or the entire
2710 Print the revision history of the specified files or the entire
2711 project.
2711 project.
2712
2712
2713 File history is shown without following rename or copy history of
2713 File history is shown without following rename or copy history of
2714 files. Use -f/--follow with a filename to follow history across
2714 files. Use -f/--follow with a filename to follow history across
2715 renames and copies. --follow without a filename will only show
2715 renames and copies. --follow without a filename will only show
2716 ancestors or descendants of the starting revision. --follow-first
2716 ancestors or descendants of the starting revision. --follow-first
2717 only follows the first parent of merge revisions.
2717 only follows the first parent of merge revisions.
2718
2718
2719 If no revision range is specified, the default is ``tip:0`` unless
2719 If no revision range is specified, the default is ``tip:0`` unless
2720 --follow is set, in which case the working directory parent is
2720 --follow is set, in which case the working directory parent is
2721 used as the starting revision. You can specify a revision set for
2721 used as the starting revision. You can specify a revision set for
2722 log, see :hg:`help revsets` for more information.
2722 log, see :hg:`help revsets` for more information.
2723
2723
2724 See :hg:`help dates` for a list of formats valid for -d/--date.
2724 See :hg:`help dates` for a list of formats valid for -d/--date.
2725
2725
2726 By default this command prints revision number and changeset id,
2726 By default this command prints revision number and changeset id,
2727 tags, non-trivial parents, user, date and time, and a summary for
2727 tags, non-trivial parents, user, date and time, and a summary for
2728 each commit. When the -v/--verbose switch is used, the list of
2728 each commit. When the -v/--verbose switch is used, the list of
2729 changed files and full commit message are shown.
2729 changed files and full commit message are shown.
2730
2730
2731 .. note::
2731 .. note::
2732 log -p/--patch may generate unexpected diff output for merge
2732 log -p/--patch may generate unexpected diff output for merge
2733 changesets, as it will only compare the merge changeset against
2733 changesets, as it will only compare the merge changeset against
2734 its first parent. Also, only files different from BOTH parents
2734 its first parent. Also, only files different from BOTH parents
2735 will appear in files:.
2735 will appear in files:.
2736
2736
2737 Returns 0 on success.
2737 Returns 0 on success.
2738 """
2738 """
2739
2739
2740 matchfn = cmdutil.match(repo, pats, opts)
2740 matchfn = cmdutil.match(repo, pats, opts)
2741 limit = cmdutil.loglimit(opts)
2741 limit = cmdutil.loglimit(opts)
2742 count = 0
2742 count = 0
2743
2743
2744 endrev = None
2744 endrev = None
2745 if opts.get('copies') and opts.get('rev'):
2745 if opts.get('copies') and opts.get('rev'):
2746 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2746 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2747
2747
2748 df = False
2748 df = False
2749 if opts["date"]:
2749 if opts["date"]:
2750 df = util.matchdate(opts["date"])
2750 df = util.matchdate(opts["date"])
2751
2751
2752 branches = opts.get('branch', []) + opts.get('only_branch', [])
2752 branches = opts.get('branch', []) + opts.get('only_branch', [])
2753 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2753 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2754
2754
2755 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2755 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2756 def prep(ctx, fns):
2756 def prep(ctx, fns):
2757 rev = ctx.rev()
2757 rev = ctx.rev()
2758 parents = [p for p in repo.changelog.parentrevs(rev)
2758 parents = [p for p in repo.changelog.parentrevs(rev)
2759 if p != nullrev]
2759 if p != nullrev]
2760 if opts.get('no_merges') and len(parents) == 2:
2760 if opts.get('no_merges') and len(parents) == 2:
2761 return
2761 return
2762 if opts.get('only_merges') and len(parents) != 2:
2762 if opts.get('only_merges') and len(parents) != 2:
2763 return
2763 return
2764 if opts.get('branch') and ctx.branch() not in opts['branch']:
2764 if opts.get('branch') and ctx.branch() not in opts['branch']:
2765 return
2765 return
2766 if df and not df(ctx.date()[0]):
2766 if df and not df(ctx.date()[0]):
2767 return
2767 return
2768 if opts['user'] and not [k for k in opts['user']
2768 if opts['user'] and not [k for k in opts['user']
2769 if k.lower() in ctx.user().lower()]:
2769 if k.lower() in ctx.user().lower()]:
2770 return
2770 return
2771 if opts.get('keyword'):
2771 if opts.get('keyword'):
2772 for k in [kw.lower() for kw in opts['keyword']]:
2772 for k in [kw.lower() for kw in opts['keyword']]:
2773 if (k in ctx.user().lower() or
2773 if (k in ctx.user().lower() or
2774 k in ctx.description().lower() or
2774 k in ctx.description().lower() or
2775 k in " ".join(ctx.files()).lower()):
2775 k in " ".join(ctx.files()).lower()):
2776 break
2776 break
2777 else:
2777 else:
2778 return
2778 return
2779
2779
2780 copies = None
2780 copies = None
2781 if opts.get('copies') and rev:
2781 if opts.get('copies') and rev:
2782 copies = []
2782 copies = []
2783 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2783 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2784 for fn in ctx.files():
2784 for fn in ctx.files():
2785 rename = getrenamed(fn, rev)
2785 rename = getrenamed(fn, rev)
2786 if rename:
2786 if rename:
2787 copies.append((fn, rename[0]))
2787 copies.append((fn, rename[0]))
2788
2788
2789 revmatchfn = None
2789 revmatchfn = None
2790 if opts.get('patch') or opts.get('stat'):
2790 if opts.get('patch') or opts.get('stat'):
2791 if opts.get('follow') or opts.get('follow_first'):
2791 if opts.get('follow') or opts.get('follow_first'):
2792 # note: this might be wrong when following through merges
2792 # note: this might be wrong when following through merges
2793 revmatchfn = cmdutil.match(repo, fns, default='path')
2793 revmatchfn = cmdutil.match(repo, fns, default='path')
2794 else:
2794 else:
2795 revmatchfn = matchfn
2795 revmatchfn = matchfn
2796
2796
2797 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2797 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2798
2798
2799 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2799 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2800 if count == limit:
2800 if count == limit:
2801 break
2801 break
2802 if displayer.flush(ctx.rev()):
2802 if displayer.flush(ctx.rev()):
2803 count += 1
2803 count += 1
2804 displayer.close()
2804 displayer.close()
2805
2805
2806 def manifest(ui, repo, node=None, rev=None):
2806 def manifest(ui, repo, node=None, rev=None):
2807 """output the current or given revision of the project manifest
2807 """output the current or given revision of the project manifest
2808
2808
2809 Print a list of version controlled files for the given revision.
2809 Print a list of version controlled files for the given revision.
2810 If no revision is given, the first parent of the working directory
2810 If no revision is given, the first parent of the working directory
2811 is used, or the null revision if no revision is checked out.
2811 is used, or the null revision if no revision is checked out.
2812
2812
2813 With -v, print file permissions, symlink and executable bits.
2813 With -v, print file permissions, symlink and executable bits.
2814 With --debug, print file revision hashes.
2814 With --debug, print file revision hashes.
2815
2815
2816 Returns 0 on success.
2816 Returns 0 on success.
2817 """
2817 """
2818
2818
2819 if rev and node:
2819 if rev and node:
2820 raise util.Abort(_("please specify just one revision"))
2820 raise util.Abort(_("please specify just one revision"))
2821
2821
2822 if not node:
2822 if not node:
2823 node = rev
2823 node = rev
2824
2824
2825 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2825 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2826 ctx = cmdutil.revsingle(repo, node)
2826 ctx = cmdutil.revsingle(repo, node)
2827 for f in ctx:
2827 for f in ctx:
2828 if ui.debugflag:
2828 if ui.debugflag:
2829 ui.write("%40s " % hex(ctx.manifest()[f]))
2829 ui.write("%40s " % hex(ctx.manifest()[f]))
2830 if ui.verbose:
2830 if ui.verbose:
2831 ui.write(decor[ctx.flags(f)])
2831 ui.write(decor[ctx.flags(f)])
2832 ui.write("%s\n" % f)
2832 ui.write("%s\n" % f)
2833
2833
2834 def merge(ui, repo, node=None, **opts):
2834 def merge(ui, repo, node=None, **opts):
2835 """merge working directory with another revision
2835 """merge working directory with another revision
2836
2836
2837 The current working directory is updated with all changes made in
2837 The current working directory is updated with all changes made in
2838 the requested revision since the last common predecessor revision.
2838 the requested revision since the last common predecessor revision.
2839
2839
2840 Files that changed between either parent are marked as changed for
2840 Files that changed between either parent are marked as changed for
2841 the next commit and a commit must be performed before any further
2841 the next commit and a commit must be performed before any further
2842 updates to the repository are allowed. The next commit will have
2842 updates to the repository are allowed. The next commit will have
2843 two parents.
2843 two parents.
2844
2844
2845 ``--tool`` can be used to specify the merge tool used for file
2845 ``--tool`` can be used to specify the merge tool used for file
2846 merges. It overrides the HGMERGE environment variable and your
2846 merges. It overrides the HGMERGE environment variable and your
2847 configuration files.
2847 configuration files.
2848
2848
2849 If no revision is specified, the working directory's parent is a
2849 If no revision is specified, the working directory's parent is a
2850 head revision, and the current branch contains exactly one other
2850 head revision, and the current branch contains exactly one other
2851 head, the other head is merged with by default. Otherwise, an
2851 head, the other head is merged with by default. Otherwise, an
2852 explicit revision with which to merge with must be provided.
2852 explicit revision with which to merge with must be provided.
2853
2853
2854 :hg:`resolve` must be used to resolve unresolved files.
2854 :hg:`resolve` must be used to resolve unresolved files.
2855
2855
2856 To undo an uncommitted merge, use :hg:`update --clean .` which
2856 To undo an uncommitted merge, use :hg:`update --clean .` which
2857 will check out a clean copy of the original merge parent, losing
2857 will check out a clean copy of the original merge parent, losing
2858 all changes.
2858 all changes.
2859
2859
2860 Returns 0 on success, 1 if there are unresolved files.
2860 Returns 0 on success, 1 if there are unresolved files.
2861 """
2861 """
2862
2862
2863 if opts.get('rev') and node:
2863 if opts.get('rev') and node:
2864 raise util.Abort(_("please specify just one revision"))
2864 raise util.Abort(_("please specify just one revision"))
2865 if not node:
2865 if not node:
2866 node = opts.get('rev')
2866 node = opts.get('rev')
2867
2867
2868 if not node:
2868 if not node:
2869 branch = repo[None].branch()
2869 branch = repo[None].branch()
2870 bheads = repo.branchheads(branch)
2870 bheads = repo.branchheads(branch)
2871 if len(bheads) > 2:
2871 if len(bheads) > 2:
2872 raise util.Abort(_(
2872 raise util.Abort(_(
2873 'branch \'%s\' has %d heads - '
2873 'branch \'%s\' has %d heads - '
2874 'please merge with an explicit rev\n'
2874 'please merge with an explicit rev\n'
2875 '(run \'hg heads .\' to see heads)')
2875 '(run \'hg heads .\' to see heads)')
2876 % (branch, len(bheads)))
2876 % (branch, len(bheads)))
2877
2877
2878 parent = repo.dirstate.parents()[0]
2878 parent = repo.dirstate.parents()[0]
2879 if len(bheads) == 1:
2879 if len(bheads) == 1:
2880 if len(repo.heads()) > 1:
2880 if len(repo.heads()) > 1:
2881 raise util.Abort(_(
2881 raise util.Abort(_(
2882 'branch \'%s\' has one head - '
2882 'branch \'%s\' has one head - '
2883 'please merge with an explicit rev\n'
2883 'please merge with an explicit rev\n'
2884 '(run \'hg heads\' to see all heads)')
2884 '(run \'hg heads\' to see all heads)')
2885 % branch)
2885 % branch)
2886 msg = _('there is nothing to merge')
2886 msg = _('there is nothing to merge')
2887 if parent != repo.lookup(repo[None].branch()):
2887 if parent != repo.lookup(repo[None].branch()):
2888 msg = _('%s - use "hg update" instead') % msg
2888 msg = _('%s - use "hg update" instead') % msg
2889 raise util.Abort(msg)
2889 raise util.Abort(msg)
2890
2890
2891 if parent not in bheads:
2891 if parent not in bheads:
2892 raise util.Abort(_('working dir not at a head rev - '
2892 raise util.Abort(_('working dir not at a head rev - '
2893 'use "hg update" or merge with an explicit rev'))
2893 'use "hg update" or merge with an explicit rev'))
2894 node = parent == bheads[0] and bheads[-1] or bheads[0]
2894 node = parent == bheads[0] and bheads[-1] or bheads[0]
2895 else:
2895 else:
2896 node = cmdutil.revsingle(repo, node).node()
2896 node = cmdutil.revsingle(repo, node).node()
2897
2897
2898 if opts.get('preview'):
2898 if opts.get('preview'):
2899 # find nodes that are ancestors of p2 but not of p1
2899 # find nodes that are ancestors of p2 but not of p1
2900 p1 = repo.lookup('.')
2900 p1 = repo.lookup('.')
2901 p2 = repo.lookup(node)
2901 p2 = repo.lookup(node)
2902 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2902 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2903
2903
2904 displayer = cmdutil.show_changeset(ui, repo, opts)
2904 displayer = cmdutil.show_changeset(ui, repo, opts)
2905 for node in nodes:
2905 for node in nodes:
2906 displayer.show(repo[node])
2906 displayer.show(repo[node])
2907 displayer.close()
2907 displayer.close()
2908 return 0
2908 return 0
2909
2909
2910 try:
2910 try:
2911 # ui.forcemerge is an internal variable, do not document
2911 # ui.forcemerge is an internal variable, do not document
2912 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2912 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2913 return hg.merge(repo, node, force=opts.get('force'))
2913 return hg.merge(repo, node, force=opts.get('force'))
2914 finally:
2914 finally:
2915 ui.setconfig('ui', 'forcemerge', '')
2915 ui.setconfig('ui', 'forcemerge', '')
2916
2916
2917 def outgoing(ui, repo, dest=None, **opts):
2917 def outgoing(ui, repo, dest=None, **opts):
2918 """show changesets not found in the destination
2918 """show changesets not found in the destination
2919
2919
2920 Show changesets not found in the specified destination repository
2920 Show changesets not found in the specified destination repository
2921 or the default push location. These are the changesets that would
2921 or the default push location. These are the changesets that would
2922 be pushed if a push was requested.
2922 be pushed if a push was requested.
2923
2923
2924 See pull for details of valid destination formats.
2924 See pull for details of valid destination formats.
2925
2925
2926 Returns 0 if there are outgoing changes, 1 otherwise.
2926 Returns 0 if there are outgoing changes, 1 otherwise.
2927 """
2927 """
2928
2928
2929 if opts.get('bookmarks'):
2929 if opts.get('bookmarks'):
2930 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2930 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2931 dest, branches = hg.parseurl(dest, opts.get('branch'))
2931 dest, branches = hg.parseurl(dest, opts.get('branch'))
2932 other = hg.repository(hg.remoteui(repo, opts), dest)
2932 other = hg.repository(hg.remoteui(repo, opts), dest)
2933 if 'bookmarks' not in other.listkeys('namespaces'):
2933 if 'bookmarks' not in other.listkeys('namespaces'):
2934 ui.warn(_("remote doesn't support bookmarks\n"))
2934 ui.warn(_("remote doesn't support bookmarks\n"))
2935 return 0
2935 return 0
2936 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2936 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2937 return bookmarks.diff(ui, other, repo)
2937 return bookmarks.diff(ui, other, repo)
2938
2938
2939 ret = hg.outgoing(ui, repo, dest, opts)
2939 ret = hg.outgoing(ui, repo, dest, opts)
2940 return ret
2940 return ret
2941
2941
2942 def parents(ui, repo, file_=None, **opts):
2942 def parents(ui, repo, file_=None, **opts):
2943 """show the parents of the working directory or revision
2943 """show the parents of the working directory or revision
2944
2944
2945 Print the working directory's parent revisions. If a revision is
2945 Print the working directory's parent revisions. If a revision is
2946 given via -r/--rev, the parent of that revision will be printed.
2946 given via -r/--rev, the parent of that revision will be printed.
2947 If a file argument is given, the revision in which the file was
2947 If a file argument is given, the revision in which the file was
2948 last changed (before the working directory revision or the
2948 last changed (before the working directory revision or the
2949 argument to --rev if given) is printed.
2949 argument to --rev if given) is printed.
2950
2950
2951 Returns 0 on success.
2951 Returns 0 on success.
2952 """
2952 """
2953
2953
2954 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2954 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2955
2955
2956 if file_:
2956 if file_:
2957 m = cmdutil.match(repo, (file_,), opts)
2957 m = cmdutil.match(repo, (file_,), opts)
2958 if m.anypats() or len(m.files()) != 1:
2958 if m.anypats() or len(m.files()) != 1:
2959 raise util.Abort(_('can only specify an explicit filename'))
2959 raise util.Abort(_('can only specify an explicit filename'))
2960 file_ = m.files()[0]
2960 file_ = m.files()[0]
2961 filenodes = []
2961 filenodes = []
2962 for cp in ctx.parents():
2962 for cp in ctx.parents():
2963 if not cp:
2963 if not cp:
2964 continue
2964 continue
2965 try:
2965 try:
2966 filenodes.append(cp.filenode(file_))
2966 filenodes.append(cp.filenode(file_))
2967 except error.LookupError:
2967 except error.LookupError:
2968 pass
2968 pass
2969 if not filenodes:
2969 if not filenodes:
2970 raise util.Abort(_("'%s' not found in manifest!") % file_)
2970 raise util.Abort(_("'%s' not found in manifest!") % file_)
2971 fl = repo.file(file_)
2971 fl = repo.file(file_)
2972 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2972 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2973 else:
2973 else:
2974 p = [cp.node() for cp in ctx.parents()]
2974 p = [cp.node() for cp in ctx.parents()]
2975
2975
2976 displayer = cmdutil.show_changeset(ui, repo, opts)
2976 displayer = cmdutil.show_changeset(ui, repo, opts)
2977 for n in p:
2977 for n in p:
2978 if n != nullid:
2978 if n != nullid:
2979 displayer.show(repo[n])
2979 displayer.show(repo[n])
2980 displayer.close()
2980 displayer.close()
2981
2981
2982 def paths(ui, repo, search=None):
2982 def paths(ui, repo, search=None):
2983 """show aliases for remote repositories
2983 """show aliases for remote repositories
2984
2984
2985 Show definition of symbolic path name NAME. If no name is given,
2985 Show definition of symbolic path name NAME. If no name is given,
2986 show definition of all available names.
2986 show definition of all available names.
2987
2987
2988 Path names are defined in the [paths] section of your
2988 Path names are defined in the [paths] section of your
2989 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2989 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2990 repository, ``.hg/hgrc`` is used, too.
2990 repository, ``.hg/hgrc`` is used, too.
2991
2991
2992 The path names ``default`` and ``default-push`` have a special
2992 The path names ``default`` and ``default-push`` have a special
2993 meaning. When performing a push or pull operation, they are used
2993 meaning. When performing a push or pull operation, they are used
2994 as fallbacks if no location is specified on the command-line.
2994 as fallbacks if no location is specified on the command-line.
2995 When ``default-push`` is set, it will be used for push and
2995 When ``default-push`` is set, it will be used for push and
2996 ``default`` will be used for pull; otherwise ``default`` is used
2996 ``default`` will be used for pull; otherwise ``default`` is used
2997 as the fallback for both. When cloning a repository, the clone
2997 as the fallback for both. When cloning a repository, the clone
2998 source is written as ``default`` in ``.hg/hgrc``. Note that
2998 source is written as ``default`` in ``.hg/hgrc``. Note that
2999 ``default`` and ``default-push`` apply to all inbound (e.g.
2999 ``default`` and ``default-push`` apply to all inbound (e.g.
3000 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3000 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3001 :hg:`bundle`) operations.
3001 :hg:`bundle`) operations.
3002
3002
3003 See :hg:`help urls` for more information.
3003 See :hg:`help urls` for more information.
3004
3004
3005 Returns 0 on success.
3005 Returns 0 on success.
3006 """
3006 """
3007 if search:
3007 if search:
3008 for name, path in ui.configitems("paths"):
3008 for name, path in ui.configitems("paths"):
3009 if name == search:
3009 if name == search:
3010 ui.write("%s\n" % url.hidepassword(path))
3010 ui.write("%s\n" % url.hidepassword(path))
3011 return
3011 return
3012 ui.warn(_("not found!\n"))
3012 ui.warn(_("not found!\n"))
3013 return 1
3013 return 1
3014 else:
3014 else:
3015 for name, path in ui.configitems("paths"):
3015 for name, path in ui.configitems("paths"):
3016 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
3016 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
3017
3017
3018 def postincoming(ui, repo, modheads, optupdate, checkout):
3018 def postincoming(ui, repo, modheads, optupdate, checkout):
3019 if modheads == 0:
3019 if modheads == 0:
3020 return
3020 return
3021 if optupdate:
3021 if optupdate:
3022 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3022 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3023 return hg.update(repo, checkout)
3023 return hg.update(repo, checkout)
3024 else:
3024 else:
3025 ui.status(_("not updating, since new heads added\n"))
3025 ui.status(_("not updating, since new heads added\n"))
3026 if modheads > 1:
3026 if modheads > 1:
3027 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3027 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3028 else:
3028 else:
3029 ui.status(_("(run 'hg update' to get a working copy)\n"))
3029 ui.status(_("(run 'hg update' to get a working copy)\n"))
3030
3030
3031 def pull(ui, repo, source="default", **opts):
3031 def pull(ui, repo, source="default", **opts):
3032 """pull changes from the specified source
3032 """pull changes from the specified source
3033
3033
3034 Pull changes from a remote repository to a local one.
3034 Pull changes from a remote repository to a local one.
3035
3035
3036 This finds all changes from the repository at the specified path
3036 This finds all changes from the repository at the specified path
3037 or URL and adds them to a local repository (the current one unless
3037 or URL and adds them to a local repository (the current one unless
3038 -R is specified). By default, this does not update the copy of the
3038 -R is specified). By default, this does not update the copy of the
3039 project in the working directory.
3039 project in the working directory.
3040
3040
3041 Use :hg:`incoming` if you want to see what would have been added
3041 Use :hg:`incoming` if you want to see what would have been added
3042 by a pull at the time you issued this command. If you then decide
3042 by a pull at the time you issued this command. If you then decide
3043 to add those changes to the repository, you should use :hg:`pull
3043 to add those changes to the repository, you should use :hg:`pull
3044 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3044 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3045
3045
3046 If SOURCE is omitted, the 'default' path will be used.
3046 If SOURCE is omitted, the 'default' path will be used.
3047 See :hg:`help urls` for more information.
3047 See :hg:`help urls` for more information.
3048
3048
3049 Returns 0 on success, 1 if an update had unresolved files.
3049 Returns 0 on success, 1 if an update had unresolved files.
3050 """
3050 """
3051 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3051 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3052 other = hg.repository(hg.remoteui(repo, opts), source)
3052 other = hg.repository(hg.remoteui(repo, opts), source)
3053 ui.status(_('pulling from %s\n') % url.hidepassword(source))
3053 ui.status(_('pulling from %s\n') % url.hidepassword(source))
3054 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3054 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3055
3055
3056 if opts.get('bookmark'):
3056 if opts.get('bookmark'):
3057 if not revs:
3057 if not revs:
3058 revs = []
3058 revs = []
3059 rb = other.listkeys('bookmarks')
3059 rb = other.listkeys('bookmarks')
3060 for b in opts['bookmark']:
3060 for b in opts['bookmark']:
3061 if b not in rb:
3061 if b not in rb:
3062 raise util.Abort(_('remote bookmark %s not found!') % b)
3062 raise util.Abort(_('remote bookmark %s not found!') % b)
3063 revs.append(rb[b])
3063 revs.append(rb[b])
3064
3064
3065 if revs:
3065 if revs:
3066 try:
3066 try:
3067 revs = [other.lookup(rev) for rev in revs]
3067 revs = [other.lookup(rev) for rev in revs]
3068 except error.CapabilityError:
3068 except error.CapabilityError:
3069 err = _("other repository doesn't support revision lookup, "
3069 err = _("other repository doesn't support revision lookup, "
3070 "so a rev cannot be specified.")
3070 "so a rev cannot be specified.")
3071 raise util.Abort(err)
3071 raise util.Abort(err)
3072
3072
3073 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3073 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3074 bookmarks.updatefromremote(ui, repo, other)
3074 bookmarks.updatefromremote(ui, repo, other)
3075 if checkout:
3075 if checkout:
3076 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3076 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3077 repo._subtoppath = source
3077 repo._subtoppath = source
3078 try:
3078 try:
3079 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3079 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3080
3080
3081 finally:
3081 finally:
3082 del repo._subtoppath
3082 del repo._subtoppath
3083
3083
3084 # update specified bookmarks
3084 # update specified bookmarks
3085 if opts.get('bookmark'):
3085 if opts.get('bookmark'):
3086 for b in opts['bookmark']:
3086 for b in opts['bookmark']:
3087 # explicit pull overrides local bookmark if any
3087 # explicit pull overrides local bookmark if any
3088 ui.status(_("importing bookmark %s\n") % b)
3088 ui.status(_("importing bookmark %s\n") % b)
3089 repo._bookmarks[b] = repo[rb[b]].node()
3089 repo._bookmarks[b] = repo[rb[b]].node()
3090 bookmarks.write(repo)
3090 bookmarks.write(repo)
3091
3091
3092 return ret
3092 return ret
3093
3093
3094 def push(ui, repo, dest=None, **opts):
3094 def push(ui, repo, dest=None, **opts):
3095 """push changes to the specified destination
3095 """push changes to the specified destination
3096
3096
3097 Push changesets from the local repository to the specified
3097 Push changesets from the local repository to the specified
3098 destination.
3098 destination.
3099
3099
3100 This operation is symmetrical to pull: it is identical to a pull
3100 This operation is symmetrical to pull: it is identical to a pull
3101 in the destination repository from the current one.
3101 in the destination repository from the current one.
3102
3102
3103 By default, push will not allow creation of new heads at the
3103 By default, push will not allow creation of new heads at the
3104 destination, since multiple heads would make it unclear which head
3104 destination, since multiple heads would make it unclear which head
3105 to use. In this situation, it is recommended to pull and merge
3105 to use. In this situation, it is recommended to pull and merge
3106 before pushing.
3106 before pushing.
3107
3107
3108 Use --new-branch if you want to allow push to create a new named
3108 Use --new-branch if you want to allow push to create a new named
3109 branch that is not present at the destination. This allows you to
3109 branch that is not present at the destination. This allows you to
3110 only create a new branch without forcing other changes.
3110 only create a new branch without forcing other changes.
3111
3111
3112 Use -f/--force to override the default behavior and push all
3112 Use -f/--force to override the default behavior and push all
3113 changesets on all branches.
3113 changesets on all branches.
3114
3114
3115 If -r/--rev is used, the specified revision and all its ancestors
3115 If -r/--rev is used, the specified revision and all its ancestors
3116 will be pushed to the remote repository.
3116 will be pushed to the remote repository.
3117
3117
3118 Please see :hg:`help urls` for important details about ``ssh://``
3118 Please see :hg:`help urls` for important details about ``ssh://``
3119 URLs. If DESTINATION is omitted, a default path will be used.
3119 URLs. If DESTINATION is omitted, a default path will be used.
3120
3120
3121 Returns 0 if push was successful, 1 if nothing to push.
3121 Returns 0 if push was successful, 1 if nothing to push.
3122 """
3122 """
3123
3123
3124 if opts.get('bookmark'):
3124 if opts.get('bookmark'):
3125 for b in opts['bookmark']:
3125 for b in opts['bookmark']:
3126 # translate -B options to -r so changesets get pushed
3126 # translate -B options to -r so changesets get pushed
3127 if b in repo._bookmarks:
3127 if b in repo._bookmarks:
3128 opts.setdefault('rev', []).append(b)
3128 opts.setdefault('rev', []).append(b)
3129 else:
3129 else:
3130 # if we try to push a deleted bookmark, translate it to null
3130 # if we try to push a deleted bookmark, translate it to null
3131 # this lets simultaneous -r, -b options continue working
3131 # this lets simultaneous -r, -b options continue working
3132 opts.setdefault('rev', []).append("null")
3132 opts.setdefault('rev', []).append("null")
3133
3133
3134 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3134 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3135 dest, branches = hg.parseurl(dest, opts.get('branch'))
3135 dest, branches = hg.parseurl(dest, opts.get('branch'))
3136 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
3136 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
3137 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3137 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3138 other = hg.repository(hg.remoteui(repo, opts), dest)
3138 other = hg.repository(hg.remoteui(repo, opts), dest)
3139 if revs:
3139 if revs:
3140 revs = [repo.lookup(rev) for rev in revs]
3140 revs = [repo.lookup(rev) for rev in revs]
3141
3141
3142 repo._subtoppath = dest
3142 repo._subtoppath = dest
3143 try:
3143 try:
3144 # push subrepos depth-first for coherent ordering
3144 # push subrepos depth-first for coherent ordering
3145 c = repo['']
3145 c = repo['']
3146 subs = c.substate # only repos that are committed
3146 subs = c.substate # only repos that are committed
3147 for s in sorted(subs):
3147 for s in sorted(subs):
3148 if not c.sub(s).push(opts.get('force')):
3148 if not c.sub(s).push(opts.get('force')):
3149 return False
3149 return False
3150 finally:
3150 finally:
3151 del repo._subtoppath
3151 del repo._subtoppath
3152 result = repo.push(other, opts.get('force'), revs=revs,
3152 result = repo.push(other, opts.get('force'), revs=revs,
3153 newbranch=opts.get('new_branch'))
3153 newbranch=opts.get('new_branch'))
3154
3154
3155 result = (result == 0)
3155 result = (result == 0)
3156
3156
3157 if opts.get('bookmark'):
3157 if opts.get('bookmark'):
3158 rb = other.listkeys('bookmarks')
3158 rb = other.listkeys('bookmarks')
3159 for b in opts['bookmark']:
3159 for b in opts['bookmark']:
3160 # explicit push overrides remote bookmark if any
3160 # explicit push overrides remote bookmark if any
3161 if b in repo._bookmarks:
3161 if b in repo._bookmarks:
3162 ui.status(_("exporting bookmark %s\n") % b)
3162 ui.status(_("exporting bookmark %s\n") % b)
3163 new = repo[b].hex()
3163 new = repo[b].hex()
3164 elif b in rb:
3164 elif b in rb:
3165 ui.status(_("deleting remote bookmark %s\n") % b)
3165 ui.status(_("deleting remote bookmark %s\n") % b)
3166 new = '' # delete
3166 new = '' # delete
3167 else:
3167 else:
3168 ui.warn(_('bookmark %s does not exist on the local '
3168 ui.warn(_('bookmark %s does not exist on the local '
3169 'or remote repository!\n') % b)
3169 'or remote repository!\n') % b)
3170 return 2
3170 return 2
3171 old = rb.get(b, '')
3171 old = rb.get(b, '')
3172 r = other.pushkey('bookmarks', b, old, new)
3172 r = other.pushkey('bookmarks', b, old, new)
3173 if not r:
3173 if not r:
3174 ui.warn(_('updating bookmark %s failed!\n') % b)
3174 ui.warn(_('updating bookmark %s failed!\n') % b)
3175 if not result:
3175 if not result:
3176 result = 2
3176 result = 2
3177
3177
3178 return result
3178 return result
3179
3179
3180 def recover(ui, repo):
3180 def recover(ui, repo):
3181 """roll back an interrupted transaction
3181 """roll back an interrupted transaction
3182
3182
3183 Recover from an interrupted commit or pull.
3183 Recover from an interrupted commit or pull.
3184
3184
3185 This command tries to fix the repository status after an
3185 This command tries to fix the repository status after an
3186 interrupted operation. It should only be necessary when Mercurial
3186 interrupted operation. It should only be necessary when Mercurial
3187 suggests it.
3187 suggests it.
3188
3188
3189 Returns 0 if successful, 1 if nothing to recover or verify fails.
3189 Returns 0 if successful, 1 if nothing to recover or verify fails.
3190 """
3190 """
3191 if repo.recover():
3191 if repo.recover():
3192 return hg.verify(repo)
3192 return hg.verify(repo)
3193 return 1
3193 return 1
3194
3194
3195 def remove(ui, repo, *pats, **opts):
3195 def remove(ui, repo, *pats, **opts):
3196 """remove the specified files on the next commit
3196 """remove the specified files on the next commit
3197
3197
3198 Schedule the indicated files for removal from the repository.
3198 Schedule the indicated files for removal from the repository.
3199
3199
3200 This only removes files from the current branch, not from the
3200 This only removes files from the current branch, not from the
3201 entire project history. -A/--after can be used to remove only
3201 entire project history. -A/--after can be used to remove only
3202 files that have already been deleted, -f/--force can be used to
3202 files that have already been deleted, -f/--force can be used to
3203 force deletion, and -Af can be used to remove files from the next
3203 force deletion, and -Af can be used to remove files from the next
3204 revision without deleting them from the working directory.
3204 revision without deleting them from the working directory.
3205
3205
3206 The following table details the behavior of remove for different
3206 The following table details the behavior of remove for different
3207 file states (columns) and option combinations (rows). The file
3207 file states (columns) and option combinations (rows). The file
3208 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3208 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3209 reported by :hg:`status`). The actions are Warn, Remove (from
3209 reported by :hg:`status`). The actions are Warn, Remove (from
3210 branch) and Delete (from disk)::
3210 branch) and Delete (from disk)::
3211
3211
3212 A C M !
3212 A C M !
3213 none W RD W R
3213 none W RD W R
3214 -f R RD RD R
3214 -f R RD RD R
3215 -A W W W R
3215 -A W W W R
3216 -Af R R R R
3216 -Af R R R R
3217
3217
3218 This command schedules the files to be removed at the next commit.
3218 This command schedules the files to be removed at the next commit.
3219 To undo a remove before that, see :hg:`revert`.
3219 To undo a remove before that, see :hg:`revert`.
3220
3220
3221 Returns 0 on success, 1 if any warnings encountered.
3221 Returns 0 on success, 1 if any warnings encountered.
3222 """
3222 """
3223
3223
3224 ret = 0
3224 ret = 0
3225 after, force = opts.get('after'), opts.get('force')
3225 after, force = opts.get('after'), opts.get('force')
3226 if not pats and not after:
3226 if not pats and not after:
3227 raise util.Abort(_('no files specified'))
3227 raise util.Abort(_('no files specified'))
3228
3228
3229 m = cmdutil.match(repo, pats, opts)
3229 m = cmdutil.match(repo, pats, opts)
3230 s = repo.status(match=m, clean=True)
3230 s = repo.status(match=m, clean=True)
3231 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3231 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3232
3232
3233 for f in m.files():
3233 for f in m.files():
3234 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3234 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3235 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3235 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3236 ret = 1
3236 ret = 1
3237
3237
3238 if force:
3238 if force:
3239 remove, forget = modified + deleted + clean, added
3239 remove, forget = modified + deleted + clean, added
3240 elif after:
3240 elif after:
3241 remove, forget = deleted, []
3241 remove, forget = deleted, []
3242 for f in modified + added + clean:
3242 for f in modified + added + clean:
3243 ui.warn(_('not removing %s: file still exists (use -f'
3243 ui.warn(_('not removing %s: file still exists (use -f'
3244 ' to force removal)\n') % m.rel(f))
3244 ' to force removal)\n') % m.rel(f))
3245 ret = 1
3245 ret = 1
3246 else:
3246 else:
3247 remove, forget = deleted + clean, []
3247 remove, forget = deleted + clean, []
3248 for f in modified:
3248 for f in modified:
3249 ui.warn(_('not removing %s: file is modified (use -f'
3249 ui.warn(_('not removing %s: file is modified (use -f'
3250 ' to force removal)\n') % m.rel(f))
3250 ' to force removal)\n') % m.rel(f))
3251 ret = 1
3251 ret = 1
3252 for f in added:
3252 for f in added:
3253 ui.warn(_('not removing %s: file has been marked for add (use -f'
3253 ui.warn(_('not removing %s: file has been marked for add (use -f'
3254 ' to force removal)\n') % m.rel(f))
3254 ' to force removal)\n') % m.rel(f))
3255 ret = 1
3255 ret = 1
3256
3256
3257 for f in sorted(remove + forget):
3257 for f in sorted(remove + forget):
3258 if ui.verbose or not m.exact(f):
3258 if ui.verbose or not m.exact(f):
3259 ui.status(_('removing %s\n') % m.rel(f))
3259 ui.status(_('removing %s\n') % m.rel(f))
3260
3260
3261 repo[None].forget(forget)
3261 repo[None].forget(forget)
3262 repo[None].remove(remove, unlink=not after)
3262 repo[None].remove(remove, unlink=not after)
3263 return ret
3263 return ret
3264
3264
3265 def rename(ui, repo, *pats, **opts):
3265 def rename(ui, repo, *pats, **opts):
3266 """rename files; equivalent of copy + remove
3266 """rename files; equivalent of copy + remove
3267
3267
3268 Mark dest as copies of sources; mark sources for deletion. If dest
3268 Mark dest as copies of sources; mark sources for deletion. If dest
3269 is a directory, copies are put in that directory. If dest is a
3269 is a directory, copies are put in that directory. If dest is a
3270 file, there can only be one source.
3270 file, there can only be one source.
3271
3271
3272 By default, this command copies the contents of files as they
3272 By default, this command copies the contents of files as they
3273 exist in the working directory. If invoked with -A/--after, the
3273 exist in the working directory. If invoked with -A/--after, the
3274 operation is recorded, but no copying is performed.
3274 operation is recorded, but no copying is performed.
3275
3275
3276 This command takes effect at the next commit. To undo a rename
3276 This command takes effect at the next commit. To undo a rename
3277 before that, see :hg:`revert`.
3277 before that, see :hg:`revert`.
3278
3278
3279 Returns 0 on success, 1 if errors are encountered.
3279 Returns 0 on success, 1 if errors are encountered.
3280 """
3280 """
3281 wlock = repo.wlock(False)
3281 wlock = repo.wlock(False)
3282 try:
3282 try:
3283 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3283 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3284 finally:
3284 finally:
3285 wlock.release()
3285 wlock.release()
3286
3286
3287 def resolve(ui, repo, *pats, **opts):
3287 def resolve(ui, repo, *pats, **opts):
3288 """redo merges or set/view the merge status of files
3288 """redo merges or set/view the merge status of files
3289
3289
3290 Merges with unresolved conflicts are often the result of
3290 Merges with unresolved conflicts are often the result of
3291 non-interactive merging using the ``internal:merge`` configuration
3291 non-interactive merging using the ``internal:merge`` configuration
3292 setting, or a command-line merge tool like ``diff3``. The resolve
3292 setting, or a command-line merge tool like ``diff3``. The resolve
3293 command is used to manage the files involved in a merge, after
3293 command is used to manage the files involved in a merge, after
3294 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3294 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3295 working directory must have two parents).
3295 working directory must have two parents).
3296
3296
3297 The resolve command can be used in the following ways:
3297 The resolve command can be used in the following ways:
3298
3298
3299 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3299 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3300 files, discarding any previous merge attempts. Re-merging is not
3300 files, discarding any previous merge attempts. Re-merging is not
3301 performed for files already marked as resolved. Use ``--all/-a``
3301 performed for files already marked as resolved. Use ``--all/-a``
3302 to selects all unresolved files. ``--tool`` can be used to specify
3302 to selects all unresolved files. ``--tool`` can be used to specify
3303 the merge tool used for the given files. It overrides the HGMERGE
3303 the merge tool used for the given files. It overrides the HGMERGE
3304 environment variable and your configuration files.
3304 environment variable and your configuration files.
3305
3305
3306 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3306 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3307 (e.g. after having manually fixed-up the files). The default is
3307 (e.g. after having manually fixed-up the files). The default is
3308 to mark all unresolved files.
3308 to mark all unresolved files.
3309
3309
3310 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3310 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3311 default is to mark all resolved files.
3311 default is to mark all resolved files.
3312
3312
3313 - :hg:`resolve -l`: list files which had or still have conflicts.
3313 - :hg:`resolve -l`: list files which had or still have conflicts.
3314 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3314 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3315
3315
3316 Note that Mercurial will not let you commit files with unresolved
3316 Note that Mercurial will not let you commit files with unresolved
3317 merge conflicts. You must use :hg:`resolve -m ...` before you can
3317 merge conflicts. You must use :hg:`resolve -m ...` before you can
3318 commit after a conflicting merge.
3318 commit after a conflicting merge.
3319
3319
3320 Returns 0 on success, 1 if any files fail a resolve attempt.
3320 Returns 0 on success, 1 if any files fail a resolve attempt.
3321 """
3321 """
3322
3322
3323 all, mark, unmark, show, nostatus = \
3323 all, mark, unmark, show, nostatus = \
3324 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3324 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3325
3325
3326 if (show and (mark or unmark)) or (mark and unmark):
3326 if (show and (mark or unmark)) or (mark and unmark):
3327 raise util.Abort(_("too many options specified"))
3327 raise util.Abort(_("too many options specified"))
3328 if pats and all:
3328 if pats and all:
3329 raise util.Abort(_("can't specify --all and patterns"))
3329 raise util.Abort(_("can't specify --all and patterns"))
3330 if not (all or pats or show or mark or unmark):
3330 if not (all or pats or show or mark or unmark):
3331 raise util.Abort(_('no files or directories specified; '
3331 raise util.Abort(_('no files or directories specified; '
3332 'use --all to remerge all files'))
3332 'use --all to remerge all files'))
3333
3333
3334 ms = mergemod.mergestate(repo)
3334 ms = mergemod.mergestate(repo)
3335 m = cmdutil.match(repo, pats, opts)
3335 m = cmdutil.match(repo, pats, opts)
3336 ret = 0
3336 ret = 0
3337
3337
3338 for f in ms:
3338 for f in ms:
3339 if m(f):
3339 if m(f):
3340 if show:
3340 if show:
3341 if nostatus:
3341 if nostatus:
3342 ui.write("%s\n" % f)
3342 ui.write("%s\n" % f)
3343 else:
3343 else:
3344 ui.write("%s %s\n" % (ms[f].upper(), f),
3344 ui.write("%s %s\n" % (ms[f].upper(), f),
3345 label='resolve.' +
3345 label='resolve.' +
3346 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3346 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3347 elif mark:
3347 elif mark:
3348 ms.mark(f, "r")
3348 ms.mark(f, "r")
3349 elif unmark:
3349 elif unmark:
3350 ms.mark(f, "u")
3350 ms.mark(f, "u")
3351 else:
3351 else:
3352 wctx = repo[None]
3352 wctx = repo[None]
3353 mctx = wctx.parents()[-1]
3353 mctx = wctx.parents()[-1]
3354
3354
3355 # backup pre-resolve (merge uses .orig for its own purposes)
3355 # backup pre-resolve (merge uses .orig for its own purposes)
3356 a = repo.wjoin(f)
3356 a = repo.wjoin(f)
3357 util.copyfile(a, a + ".resolve")
3357 util.copyfile(a, a + ".resolve")
3358
3358
3359 try:
3359 try:
3360 # resolve file
3360 # resolve file
3361 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3361 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3362 if ms.resolve(f, wctx, mctx):
3362 if ms.resolve(f, wctx, mctx):
3363 ret = 1
3363 ret = 1
3364 finally:
3364 finally:
3365 ui.setconfig('ui', 'forcemerge', '')
3365 ui.setconfig('ui', 'forcemerge', '')
3366
3366
3367 # replace filemerge's .orig file with our resolve file
3367 # replace filemerge's .orig file with our resolve file
3368 util.rename(a + ".resolve", a + ".orig")
3368 util.rename(a + ".resolve", a + ".orig")
3369
3369
3370 ms.commit()
3370 ms.commit()
3371 return ret
3371 return ret
3372
3372
3373 def revert(ui, repo, *pats, **opts):
3373 def revert(ui, repo, *pats, **opts):
3374 """restore individual files or directories to an earlier state
3374 """restore individual files or directories to an earlier state
3375
3375
3376 .. note::
3376 .. note::
3377 This command is most likely not what you are looking for.
3377 This command is most likely not what you are looking for.
3378 Revert will partially overwrite content in the working
3378 Revert will partially overwrite content in the working
3379 directory without changing the working directory parents. Use
3379 directory without changing the working directory parents. Use
3380 :hg:`update -r rev` to check out earlier revisions, or
3380 :hg:`update -r rev` to check out earlier revisions, or
3381 :hg:`update --clean .` to undo a merge which has added another
3381 :hg:`update --clean .` to undo a merge which has added another
3382 parent.
3382 parent.
3383
3383
3384 With no revision specified, revert the named files or directories
3384 With no revision specified, revert the named files or directories
3385 to the contents they had in the parent of the working directory.
3385 to the contents they had in the parent of the working directory.
3386 This restores the contents of the affected files to an unmodified
3386 This restores the contents of the affected files to an unmodified
3387 state and unschedules adds, removes, copies, and renames. If the
3387 state and unschedules adds, removes, copies, and renames. If the
3388 working directory has two parents, you must explicitly specify a
3388 working directory has two parents, you must explicitly specify a
3389 revision.
3389 revision.
3390
3390
3391 Using the -r/--rev option, revert the given files or directories
3391 Using the -r/--rev option, revert the given files or directories
3392 to their contents as of a specific revision. This can be helpful
3392 to their contents as of a specific revision. This can be helpful
3393 to "roll back" some or all of an earlier change. See :hg:`help
3393 to "roll back" some or all of an earlier change. See :hg:`help
3394 dates` for a list of formats valid for -d/--date.
3394 dates` for a list of formats valid for -d/--date.
3395
3395
3396 Revert modifies the working directory. It does not commit any
3396 Revert modifies the working directory. It does not commit any
3397 changes, or change the parent of the working directory. If you
3397 changes, or change the parent of the working directory. If you
3398 revert to a revision other than the parent of the working
3398 revert to a revision other than the parent of the working
3399 directory, the reverted files will thus appear modified
3399 directory, the reverted files will thus appear modified
3400 afterwards.
3400 afterwards.
3401
3401
3402 If a file has been deleted, it is restored. If the executable mode
3402 If a file has been deleted, it is restored. If the executable mode
3403 of a file was changed, it is reset.
3403 of a file was changed, it is reset.
3404
3404
3405 If names are given, all files matching the names are reverted.
3405 If names are given, all files matching the names are reverted.
3406 If no arguments are given, no files are reverted.
3406 If no arguments are given, no files are reverted.
3407
3407
3408 Modified files are saved with a .orig suffix before reverting.
3408 Modified files are saved with a .orig suffix before reverting.
3409 To disable these backups, use --no-backup.
3409 To disable these backups, use --no-backup.
3410
3410
3411 Returns 0 on success.
3411 Returns 0 on success.
3412 """
3412 """
3413
3413
3414 if opts.get("date"):
3414 if opts.get("date"):
3415 if opts.get("rev"):
3415 if opts.get("rev"):
3416 raise util.Abort(_("you can't specify a revision and a date"))
3416 raise util.Abort(_("you can't specify a revision and a date"))
3417 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3417 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3418
3418
3419 parent, p2 = repo.dirstate.parents()
3419 parent, p2 = repo.dirstate.parents()
3420 if not opts.get('rev') and p2 != nullid:
3420 if not opts.get('rev') and p2 != nullid:
3421 raise util.Abort(_('uncommitted merge - '
3421 raise util.Abort(_('uncommitted merge - '
3422 'use "hg update", see "hg help revert"'))
3422 'use "hg update", see "hg help revert"'))
3423
3423
3424 if not pats and not opts.get('all'):
3424 if not pats and not opts.get('all'):
3425 raise util.Abort(_('no files or directories specified; '
3425 raise util.Abort(_('no files or directories specified; '
3426 'use --all to revert the whole repo'))
3426 'use --all to revert the whole repo'))
3427
3427
3428 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3428 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3429 node = ctx.node()
3429 node = ctx.node()
3430 mf = ctx.manifest()
3430 mf = ctx.manifest()
3431 if node == parent:
3431 if node == parent:
3432 pmf = mf
3432 pmf = mf
3433 else:
3433 else:
3434 pmf = None
3434 pmf = None
3435
3435
3436 # need all matching names in dirstate and manifest of target rev,
3436 # need all matching names in dirstate and manifest of target rev,
3437 # so have to walk both. do not print errors if files exist in one
3437 # so have to walk both. do not print errors if files exist in one
3438 # but not other.
3438 # but not other.
3439
3439
3440 names = {}
3440 names = {}
3441
3441
3442 wlock = repo.wlock()
3442 wlock = repo.wlock()
3443 try:
3443 try:
3444 # walk dirstate.
3444 # walk dirstate.
3445
3445
3446 m = cmdutil.match(repo, pats, opts)
3446 m = cmdutil.match(repo, pats, opts)
3447 m.bad = lambda x, y: False
3447 m.bad = lambda x, y: False
3448 for abs in repo.walk(m):
3448 for abs in repo.walk(m):
3449 names[abs] = m.rel(abs), m.exact(abs)
3449 names[abs] = m.rel(abs), m.exact(abs)
3450
3450
3451 # walk target manifest.
3451 # walk target manifest.
3452
3452
3453 def badfn(path, msg):
3453 def badfn(path, msg):
3454 if path in names:
3454 if path in names:
3455 return
3455 return
3456 path_ = path + '/'
3456 path_ = path + '/'
3457 for f in names:
3457 for f in names:
3458 if f.startswith(path_):
3458 if f.startswith(path_):
3459 return
3459 return
3460 ui.warn("%s: %s\n" % (m.rel(path), msg))
3460 ui.warn("%s: %s\n" % (m.rel(path), msg))
3461
3461
3462 m = cmdutil.match(repo, pats, opts)
3462 m = cmdutil.match(repo, pats, opts)
3463 m.bad = badfn
3463 m.bad = badfn
3464 for abs in repo[node].walk(m):
3464 for abs in repo[node].walk(m):
3465 if abs not in names:
3465 if abs not in names:
3466 names[abs] = m.rel(abs), m.exact(abs)
3466 names[abs] = m.rel(abs), m.exact(abs)
3467
3467
3468 m = cmdutil.matchfiles(repo, names)
3468 m = cmdutil.matchfiles(repo, names)
3469 changes = repo.status(match=m)[:4]
3469 changes = repo.status(match=m)[:4]
3470 modified, added, removed, deleted = map(set, changes)
3470 modified, added, removed, deleted = map(set, changes)
3471
3471
3472 # if f is a rename, also revert the source
3472 # if f is a rename, also revert the source
3473 cwd = repo.getcwd()
3473 cwd = repo.getcwd()
3474 for f in added:
3474 for f in added:
3475 src = repo.dirstate.copied(f)
3475 src = repo.dirstate.copied(f)
3476 if src and src not in names and repo.dirstate[src] == 'r':
3476 if src and src not in names and repo.dirstate[src] == 'r':
3477 removed.add(src)
3477 removed.add(src)
3478 names[src] = (repo.pathto(src, cwd), True)
3478 names[src] = (repo.pathto(src, cwd), True)
3479
3479
3480 def removeforget(abs):
3480 def removeforget(abs):
3481 if repo.dirstate[abs] == 'a':
3481 if repo.dirstate[abs] == 'a':
3482 return _('forgetting %s\n')
3482 return _('forgetting %s\n')
3483 return _('removing %s\n')
3483 return _('removing %s\n')
3484
3484
3485 revert = ([], _('reverting %s\n'))
3485 revert = ([], _('reverting %s\n'))
3486 add = ([], _('adding %s\n'))
3486 add = ([], _('adding %s\n'))
3487 remove = ([], removeforget)
3487 remove = ([], removeforget)
3488 undelete = ([], _('undeleting %s\n'))
3488 undelete = ([], _('undeleting %s\n'))
3489
3489
3490 disptable = (
3490 disptable = (
3491 # dispatch table:
3491 # dispatch table:
3492 # file state
3492 # file state
3493 # action if in target manifest
3493 # action if in target manifest
3494 # action if not in target manifest
3494 # action if not in target manifest
3495 # make backup if in target manifest
3495 # make backup if in target manifest
3496 # make backup if not in target manifest
3496 # make backup if not in target manifest
3497 (modified, revert, remove, True, True),
3497 (modified, revert, remove, True, True),
3498 (added, revert, remove, True, False),
3498 (added, revert, remove, True, False),
3499 (removed, undelete, None, False, False),
3499 (removed, undelete, None, False, False),
3500 (deleted, revert, remove, False, False),
3500 (deleted, revert, remove, False, False),
3501 )
3501 )
3502
3502
3503 for abs, (rel, exact) in sorted(names.items()):
3503 for abs, (rel, exact) in sorted(names.items()):
3504 mfentry = mf.get(abs)
3504 mfentry = mf.get(abs)
3505 target = repo.wjoin(abs)
3505 target = repo.wjoin(abs)
3506 def handle(xlist, dobackup):
3506 def handle(xlist, dobackup):
3507 xlist[0].append(abs)
3507 xlist[0].append(abs)
3508 if (dobackup and not opts.get('no_backup') and
3508 if (dobackup and not opts.get('no_backup') and
3509 os.path.lexists(target)):
3509 os.path.lexists(target)):
3510 bakname = "%s.orig" % rel
3510 bakname = "%s.orig" % rel
3511 ui.note(_('saving current version of %s as %s\n') %
3511 ui.note(_('saving current version of %s as %s\n') %
3512 (rel, bakname))
3512 (rel, bakname))
3513 if not opts.get('dry_run'):
3513 if not opts.get('dry_run'):
3514 util.rename(target, bakname)
3514 util.rename(target, bakname)
3515 if ui.verbose or not exact:
3515 if ui.verbose or not exact:
3516 msg = xlist[1]
3516 msg = xlist[1]
3517 if not isinstance(msg, basestring):
3517 if not isinstance(msg, basestring):
3518 msg = msg(abs)
3518 msg = msg(abs)
3519 ui.status(msg % rel)
3519 ui.status(msg % rel)
3520 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3520 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3521 if abs not in table:
3521 if abs not in table:
3522 continue
3522 continue
3523 # file has changed in dirstate
3523 # file has changed in dirstate
3524 if mfentry:
3524 if mfentry:
3525 handle(hitlist, backuphit)
3525 handle(hitlist, backuphit)
3526 elif misslist is not None:
3526 elif misslist is not None:
3527 handle(misslist, backupmiss)
3527 handle(misslist, backupmiss)
3528 break
3528 break
3529 else:
3529 else:
3530 if abs not in repo.dirstate:
3530 if abs not in repo.dirstate:
3531 if mfentry:
3531 if mfentry:
3532 handle(add, True)
3532 handle(add, True)
3533 elif exact:
3533 elif exact:
3534 ui.warn(_('file not managed: %s\n') % rel)
3534 ui.warn(_('file not managed: %s\n') % rel)
3535 continue
3535 continue
3536 # file has not changed in dirstate
3536 # file has not changed in dirstate
3537 if node == parent:
3537 if node == parent:
3538 if exact:
3538 if exact:
3539 ui.warn(_('no changes needed to %s\n') % rel)
3539 ui.warn(_('no changes needed to %s\n') % rel)
3540 continue
3540 continue
3541 if pmf is None:
3541 if pmf is None:
3542 # only need parent manifest in this unlikely case,
3542 # only need parent manifest in this unlikely case,
3543 # so do not read by default
3543 # so do not read by default
3544 pmf = repo[parent].manifest()
3544 pmf = repo[parent].manifest()
3545 if abs in pmf:
3545 if abs in pmf:
3546 if mfentry:
3546 if mfentry:
3547 # if version of file is same in parent and target
3547 # if version of file is same in parent and target
3548 # manifests, do nothing
3548 # manifests, do nothing
3549 if (pmf[abs] != mfentry or
3549 if (pmf[abs] != mfentry or
3550 pmf.flags(abs) != mf.flags(abs)):
3550 pmf.flags(abs) != mf.flags(abs)):
3551 handle(revert, False)
3551 handle(revert, False)
3552 else:
3552 else:
3553 handle(remove, False)
3553 handle(remove, False)
3554
3554
3555 if not opts.get('dry_run'):
3555 if not opts.get('dry_run'):
3556 def checkout(f):
3556 def checkout(f):
3557 fc = ctx[f]
3557 fc = ctx[f]
3558 repo.wwrite(f, fc.data(), fc.flags())
3558 repo.wwrite(f, fc.data(), fc.flags())
3559
3559
3560 audit_path = util.path_auditor(repo.root)
3560 audit_path = util.path_auditor(repo.root)
3561 for f in remove[0]:
3561 for f in remove[0]:
3562 if repo.dirstate[f] == 'a':
3562 if repo.dirstate[f] == 'a':
3563 repo.dirstate.forget(f)
3563 repo.dirstate.forget(f)
3564 continue
3564 continue
3565 audit_path(f)
3565 audit_path(f)
3566 try:
3566 try:
3567 util.unlinkpath(repo.wjoin(f))
3567 util.unlinkpath(repo.wjoin(f))
3568 except OSError:
3568 except OSError:
3569 pass
3569 pass
3570 repo.dirstate.remove(f)
3570 repo.dirstate.remove(f)
3571
3571
3572 normal = None
3572 normal = None
3573 if node == parent:
3573 if node == parent:
3574 # We're reverting to our parent. If possible, we'd like status
3574 # We're reverting to our parent. If possible, we'd like status
3575 # to report the file as clean. We have to use normallookup for
3575 # to report the file as clean. We have to use normallookup for
3576 # merges to avoid losing information about merged/dirty files.
3576 # merges to avoid losing information about merged/dirty files.
3577 if p2 != nullid:
3577 if p2 != nullid:
3578 normal = repo.dirstate.normallookup
3578 normal = repo.dirstate.normallookup
3579 else:
3579 else:
3580 normal = repo.dirstate.normal
3580 normal = repo.dirstate.normal
3581 for f in revert[0]:
3581 for f in revert[0]:
3582 checkout(f)
3582 checkout(f)
3583 if normal:
3583 if normal:
3584 normal(f)
3584 normal(f)
3585
3585
3586 for f in add[0]:
3586 for f in add[0]:
3587 checkout(f)
3587 checkout(f)
3588 repo.dirstate.add(f)
3588 repo.dirstate.add(f)
3589
3589
3590 normal = repo.dirstate.normallookup
3590 normal = repo.dirstate.normallookup
3591 if node == parent and p2 == nullid:
3591 if node == parent and p2 == nullid:
3592 normal = repo.dirstate.normal
3592 normal = repo.dirstate.normal
3593 for f in undelete[0]:
3593 for f in undelete[0]:
3594 checkout(f)
3594 checkout(f)
3595 normal(f)
3595 normal(f)
3596
3596
3597 finally:
3597 finally:
3598 wlock.release()
3598 wlock.release()
3599
3599
3600 def rollback(ui, repo, **opts):
3600 def rollback(ui, repo, **opts):
3601 """roll back the last transaction (dangerous)
3601 """roll back the last transaction (dangerous)
3602
3602
3603 This command should be used with care. There is only one level of
3603 This command should be used with care. There is only one level of
3604 rollback, and there is no way to undo a rollback. It will also
3604 rollback, and there is no way to undo a rollback. It will also
3605 restore the dirstate at the time of the last transaction, losing
3605 restore the dirstate at the time of the last transaction, losing
3606 any dirstate changes since that time. This command does not alter
3606 any dirstate changes since that time. This command does not alter
3607 the working directory.
3607 the working directory.
3608
3608
3609 Transactions are used to encapsulate the effects of all commands
3609 Transactions are used to encapsulate the effects of all commands
3610 that create new changesets or propagate existing changesets into a
3610 that create new changesets or propagate existing changesets into a
3611 repository. For example, the following commands are transactional,
3611 repository. For example, the following commands are transactional,
3612 and their effects can be rolled back:
3612 and their effects can be rolled back:
3613
3613
3614 - commit
3614 - commit
3615 - import
3615 - import
3616 - pull
3616 - pull
3617 - push (with this repository as the destination)
3617 - push (with this repository as the destination)
3618 - unbundle
3618 - unbundle
3619
3619
3620 This command is not intended for use on public repositories. Once
3620 This command is not intended for use on public repositories. Once
3621 changes are visible for pull by other users, rolling a transaction
3621 changes are visible for pull by other users, rolling a transaction
3622 back locally is ineffective (someone else may already have pulled
3622 back locally is ineffective (someone else may already have pulled
3623 the changes). Furthermore, a race is possible with readers of the
3623 the changes). Furthermore, a race is possible with readers of the
3624 repository; for example an in-progress pull from the repository
3624 repository; for example an in-progress pull from the repository
3625 may fail if a rollback is performed.
3625 may fail if a rollback is performed.
3626
3626
3627 Returns 0 on success, 1 if no rollback data is available.
3627 Returns 0 on success, 1 if no rollback data is available.
3628 """
3628 """
3629 return repo.rollback(opts.get('dry_run'))
3629 return repo.rollback(opts.get('dry_run'))
3630
3630
3631 def root(ui, repo):
3631 def root(ui, repo):
3632 """print the root (top) of the current working directory
3632 """print the root (top) of the current working directory
3633
3633
3634 Print the root directory of the current repository.
3634 Print the root directory of the current repository.
3635
3635
3636 Returns 0 on success.
3636 Returns 0 on success.
3637 """
3637 """
3638 ui.write(repo.root + "\n")
3638 ui.write(repo.root + "\n")
3639
3639
3640 def serve(ui, repo, **opts):
3640 def serve(ui, repo, **opts):
3641 """start stand-alone webserver
3641 """start stand-alone webserver
3642
3642
3643 Start a local HTTP repository browser and pull server. You can use
3643 Start a local HTTP repository browser and pull server. You can use
3644 this for ad-hoc sharing and browsing of repositories. It is
3644 this for ad-hoc sharing and browsing of repositories. It is
3645 recommended to use a real web server to serve a repository for
3645 recommended to use a real web server to serve a repository for
3646 longer periods of time.
3646 longer periods of time.
3647
3647
3648 Please note that the server does not implement access control.
3648 Please note that the server does not implement access control.
3649 This means that, by default, anybody can read from the server and
3649 This means that, by default, anybody can read from the server and
3650 nobody can write to it by default. Set the ``web.allow_push``
3650 nobody can write to it by default. Set the ``web.allow_push``
3651 option to ``*`` to allow everybody to push to the server. You
3651 option to ``*`` to allow everybody to push to the server. You
3652 should use a real web server if you need to authenticate users.
3652 should use a real web server if you need to authenticate users.
3653
3653
3654 By default, the server logs accesses to stdout and errors to
3654 By default, the server logs accesses to stdout and errors to
3655 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3655 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3656 files.
3656 files.
3657
3657
3658 To have the server choose a free port number to listen on, specify
3658 To have the server choose a free port number to listen on, specify
3659 a port number of 0; in this case, the server will print the port
3659 a port number of 0; in this case, the server will print the port
3660 number it uses.
3660 number it uses.
3661
3661
3662 Returns 0 on success.
3662 Returns 0 on success.
3663 """
3663 """
3664
3664
3665 if opts["stdio"]:
3665 if opts["stdio"]:
3666 if repo is None:
3666 if repo is None:
3667 raise error.RepoError(_("There is no Mercurial repository here"
3667 raise error.RepoError(_("There is no Mercurial repository here"
3668 " (.hg not found)"))
3668 " (.hg not found)"))
3669 s = sshserver.sshserver(ui, repo)
3669 s = sshserver.sshserver(ui, repo)
3670 s.serve_forever()
3670 s.serve_forever()
3671
3671
3672 # this way we can check if something was given in the command-line
3672 # this way we can check if something was given in the command-line
3673 if opts.get('port'):
3673 if opts.get('port'):
3674 opts['port'] = util.getport(opts.get('port'))
3674 opts['port'] = util.getport(opts.get('port'))
3675
3675
3676 baseui = repo and repo.baseui or ui
3676 baseui = repo and repo.baseui or ui
3677 optlist = ("name templates style address port prefix ipv6"
3677 optlist = ("name templates style address port prefix ipv6"
3678 " accesslog errorlog certificate encoding")
3678 " accesslog errorlog certificate encoding")
3679 for o in optlist.split():
3679 for o in optlist.split():
3680 val = opts.get(o, '')
3680 val = opts.get(o, '')
3681 if val in (None, ''): # should check against default options instead
3681 if val in (None, ''): # should check against default options instead
3682 continue
3682 continue
3683 baseui.setconfig("web", o, val)
3683 baseui.setconfig("web", o, val)
3684 if repo and repo.ui != baseui:
3684 if repo and repo.ui != baseui:
3685 repo.ui.setconfig("web", o, val)
3685 repo.ui.setconfig("web", o, val)
3686
3686
3687 o = opts.get('web_conf') or opts.get('webdir_conf')
3687 o = opts.get('web_conf') or opts.get('webdir_conf')
3688 if not o:
3688 if not o:
3689 if not repo:
3689 if not repo:
3690 raise error.RepoError(_("There is no Mercurial repository"
3690 raise error.RepoError(_("There is no Mercurial repository"
3691 " here (.hg not found)"))
3691 " here (.hg not found)"))
3692 o = repo.root
3692 o = repo.root
3693
3693
3694 app = hgweb.hgweb(o, baseui=ui)
3694 app = hgweb.hgweb(o, baseui=ui)
3695
3695
3696 class service(object):
3696 class service(object):
3697 def init(self):
3697 def init(self):
3698 util.set_signal_handler()
3698 util.set_signal_handler()
3699 self.httpd = hgweb.server.create_server(ui, app)
3699 self.httpd = hgweb.server.create_server(ui, app)
3700
3700
3701 if opts['port'] and not ui.verbose:
3701 if opts['port'] and not ui.verbose:
3702 return
3702 return
3703
3703
3704 if self.httpd.prefix:
3704 if self.httpd.prefix:
3705 prefix = self.httpd.prefix.strip('/') + '/'
3705 prefix = self.httpd.prefix.strip('/') + '/'
3706 else:
3706 else:
3707 prefix = ''
3707 prefix = ''
3708
3708
3709 port = ':%d' % self.httpd.port
3709 port = ':%d' % self.httpd.port
3710 if port == ':80':
3710 if port == ':80':
3711 port = ''
3711 port = ''
3712
3712
3713 bindaddr = self.httpd.addr
3713 bindaddr = self.httpd.addr
3714 if bindaddr == '0.0.0.0':
3714 if bindaddr == '0.0.0.0':
3715 bindaddr = '*'
3715 bindaddr = '*'
3716 elif ':' in bindaddr: # IPv6
3716 elif ':' in bindaddr: # IPv6
3717 bindaddr = '[%s]' % bindaddr
3717 bindaddr = '[%s]' % bindaddr
3718
3718
3719 fqaddr = self.httpd.fqaddr
3719 fqaddr = self.httpd.fqaddr
3720 if ':' in fqaddr:
3720 if ':' in fqaddr:
3721 fqaddr = '[%s]' % fqaddr
3721 fqaddr = '[%s]' % fqaddr
3722 if opts['port']:
3722 if opts['port']:
3723 write = ui.status
3723 write = ui.status
3724 else:
3724 else:
3725 write = ui.write
3725 write = ui.write
3726 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3726 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3727 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3727 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3728
3728
3729 def run(self):
3729 def run(self):
3730 self.httpd.serve_forever()
3730 self.httpd.serve_forever()
3731
3731
3732 service = service()
3732 service = service()
3733
3733
3734 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3734 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3735
3735
3736 def status(ui, repo, *pats, **opts):
3736 def status(ui, repo, *pats, **opts):
3737 """show changed files in the working directory
3737 """show changed files in the working directory
3738
3738
3739 Show status of files in the repository. If names are given, only
3739 Show status of files in the repository. If names are given, only
3740 files that match are shown. Files that are clean or ignored or
3740 files that match are shown. Files that are clean or ignored or
3741 the source of a copy/move operation, are not listed unless
3741 the source of a copy/move operation, are not listed unless
3742 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3742 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3743 Unless options described with "show only ..." are given, the
3743 Unless options described with "show only ..." are given, the
3744 options -mardu are used.
3744 options -mardu are used.
3745
3745
3746 Option -q/--quiet hides untracked (unknown and ignored) files
3746 Option -q/--quiet hides untracked (unknown and ignored) files
3747 unless explicitly requested with -u/--unknown or -i/--ignored.
3747 unless explicitly requested with -u/--unknown or -i/--ignored.
3748
3748
3749 .. note::
3749 .. note::
3750 status may appear to disagree with diff if permissions have
3750 status may appear to disagree with diff if permissions have
3751 changed or a merge has occurred. The standard diff format does
3751 changed or a merge has occurred. The standard diff format does
3752 not report permission changes and diff only reports changes
3752 not report permission changes and diff only reports changes
3753 relative to one merge parent.
3753 relative to one merge parent.
3754
3754
3755 If one revision is given, it is used as the base revision.
3755 If one revision is given, it is used as the base revision.
3756 If two revisions are given, the differences between them are
3756 If two revisions are given, the differences between them are
3757 shown. The --change option can also be used as a shortcut to list
3757 shown. The --change option can also be used as a shortcut to list
3758 the changed files of a revision from its first parent.
3758 the changed files of a revision from its first parent.
3759
3759
3760 The codes used to show the status of files are::
3760 The codes used to show the status of files are::
3761
3761
3762 M = modified
3762 M = modified
3763 A = added
3763 A = added
3764 R = removed
3764 R = removed
3765 C = clean
3765 C = clean
3766 ! = missing (deleted by non-hg command, but still tracked)
3766 ! = missing (deleted by non-hg command, but still tracked)
3767 ? = not tracked
3767 ? = not tracked
3768 I = ignored
3768 I = ignored
3769 = origin of the previous file listed as A (added)
3769 = origin of the previous file listed as A (added)
3770
3770
3771 Returns 0 on success.
3771 Returns 0 on success.
3772 """
3772 """
3773
3773
3774 revs = opts.get('rev')
3774 revs = opts.get('rev')
3775 change = opts.get('change')
3775 change = opts.get('change')
3776
3776
3777 if revs and change:
3777 if revs and change:
3778 msg = _('cannot specify --rev and --change at the same time')
3778 msg = _('cannot specify --rev and --change at the same time')
3779 raise util.Abort(msg)
3779 raise util.Abort(msg)
3780 elif change:
3780 elif change:
3781 node2 = repo.lookup(change)
3781 node2 = repo.lookup(change)
3782 node1 = repo[node2].parents()[0].node()
3782 node1 = repo[node2].parents()[0].node()
3783 else:
3783 else:
3784 node1, node2 = cmdutil.revpair(repo, revs)
3784 node1, node2 = cmdutil.revpair(repo, revs)
3785
3785
3786 cwd = (pats and repo.getcwd()) or ''
3786 cwd = (pats and repo.getcwd()) or ''
3787 end = opts.get('print0') and '\0' or '\n'
3787 end = opts.get('print0') and '\0' or '\n'
3788 copy = {}
3788 copy = {}
3789 states = 'modified added removed deleted unknown ignored clean'.split()
3789 states = 'modified added removed deleted unknown ignored clean'.split()
3790 show = [k for k in states if opts.get(k)]
3790 show = [k for k in states if opts.get(k)]
3791 if opts.get('all'):
3791 if opts.get('all'):
3792 show += ui.quiet and (states[:4] + ['clean']) or states
3792 show += ui.quiet and (states[:4] + ['clean']) or states
3793 if not show:
3793 if not show:
3794 show = ui.quiet and states[:4] or states[:5]
3794 show = ui.quiet and states[:4] or states[:5]
3795
3795
3796 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3796 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3797 'ignored' in show, 'clean' in show, 'unknown' in show,
3797 'ignored' in show, 'clean' in show, 'unknown' in show,
3798 opts.get('subrepos'))
3798 opts.get('subrepos'))
3799 changestates = zip(states, 'MAR!?IC', stat)
3799 changestates = zip(states, 'MAR!?IC', stat)
3800
3800
3801 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3801 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3802 ctxn = repo[nullid]
3802 ctxn = repo[nullid]
3803 ctx1 = repo[node1]
3803 ctx1 = repo[node1]
3804 ctx2 = repo[node2]
3804 ctx2 = repo[node2]
3805 added = stat[1]
3805 added = stat[1]
3806 if node2 is None:
3806 if node2 is None:
3807 added = stat[0] + stat[1] # merged?
3807 added = stat[0] + stat[1] # merged?
3808
3808
3809 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3809 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3810 if k in added:
3810 if k in added:
3811 copy[k] = v
3811 copy[k] = v
3812 elif v in added:
3812 elif v in added:
3813 copy[v] = k
3813 copy[v] = k
3814
3814
3815 for state, char, files in changestates:
3815 for state, char, files in changestates:
3816 if state in show:
3816 if state in show:
3817 format = "%s %%s%s" % (char, end)
3817 format = "%s %%s%s" % (char, end)
3818 if opts.get('no_status'):
3818 if opts.get('no_status'):
3819 format = "%%s%s" % end
3819 format = "%%s%s" % end
3820
3820
3821 for f in files:
3821 for f in files:
3822 ui.write(format % repo.pathto(f, cwd),
3822 ui.write(format % repo.pathto(f, cwd),
3823 label='status.' + state)
3823 label='status.' + state)
3824 if f in copy:
3824 if f in copy:
3825 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3825 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3826 label='status.copied')
3826 label='status.copied')
3827
3827
3828 def summary(ui, repo, **opts):
3828 def summary(ui, repo, **opts):
3829 """summarize working directory state
3829 """summarize working directory state
3830
3830
3831 This generates a brief summary of the working directory state,
3831 This generates a brief summary of the working directory state,
3832 including parents, branch, commit status, and available updates.
3832 including parents, branch, commit status, and available updates.
3833
3833
3834 With the --remote option, this will check the default paths for
3834 With the --remote option, this will check the default paths for
3835 incoming and outgoing changes. This can be time-consuming.
3835 incoming and outgoing changes. This can be time-consuming.
3836
3836
3837 Returns 0 on success.
3837 Returns 0 on success.
3838 """
3838 """
3839
3839
3840 ctx = repo[None]
3840 ctx = repo[None]
3841 parents = ctx.parents()
3841 parents = ctx.parents()
3842 pnode = parents[0].node()
3842 pnode = parents[0].node()
3843
3843
3844 for p in parents:
3844 for p in parents:
3845 # label with log.changeset (instead of log.parent) since this
3845 # label with log.changeset (instead of log.parent) since this
3846 # shows a working directory parent *changeset*:
3846 # shows a working directory parent *changeset*:
3847 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3847 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3848 label='log.changeset')
3848 label='log.changeset')
3849 ui.write(' '.join(p.tags()), label='log.tag')
3849 ui.write(' '.join(p.tags()), label='log.tag')
3850 if p.bookmarks():
3850 if p.bookmarks():
3851 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3851 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3852 if p.rev() == -1:
3852 if p.rev() == -1:
3853 if not len(repo):
3853 if not len(repo):
3854 ui.write(_(' (empty repository)'))
3854 ui.write(_(' (empty repository)'))
3855 else:
3855 else:
3856 ui.write(_(' (no revision checked out)'))
3856 ui.write(_(' (no revision checked out)'))
3857 ui.write('\n')
3857 ui.write('\n')
3858 if p.description():
3858 if p.description():
3859 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3859 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3860 label='log.summary')
3860 label='log.summary')
3861
3861
3862 branch = ctx.branch()
3862 branch = ctx.branch()
3863 bheads = repo.branchheads(branch)
3863 bheads = repo.branchheads(branch)
3864 m = _('branch: %s\n') % branch
3864 m = _('branch: %s\n') % branch
3865 if branch != 'default':
3865 if branch != 'default':
3866 ui.write(m, label='log.branch')
3866 ui.write(m, label='log.branch')
3867 else:
3867 else:
3868 ui.status(m, label='log.branch')
3868 ui.status(m, label='log.branch')
3869
3869
3870 st = list(repo.status(unknown=True))[:6]
3870 st = list(repo.status(unknown=True))[:6]
3871
3871
3872 c = repo.dirstate.copies()
3872 c = repo.dirstate.copies()
3873 copied, renamed = [], []
3873 copied, renamed = [], []
3874 for d, s in c.iteritems():
3874 for d, s in c.iteritems():
3875 if s in st[2]:
3875 if s in st[2]:
3876 st[2].remove(s)
3876 st[2].remove(s)
3877 renamed.append(d)
3877 renamed.append(d)
3878 else:
3878 else:
3879 copied.append(d)
3879 copied.append(d)
3880 if d in st[1]:
3880 if d in st[1]:
3881 st[1].remove(d)
3881 st[1].remove(d)
3882 st.insert(3, renamed)
3882 st.insert(3, renamed)
3883 st.insert(4, copied)
3883 st.insert(4, copied)
3884
3884
3885 ms = mergemod.mergestate(repo)
3885 ms = mergemod.mergestate(repo)
3886 st.append([f for f in ms if ms[f] == 'u'])
3886 st.append([f for f in ms if ms[f] == 'u'])
3887
3887
3888 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3888 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3889 st.append(subs)
3889 st.append(subs)
3890
3890
3891 labels = [ui.label(_('%d modified'), 'status.modified'),
3891 labels = [ui.label(_('%d modified'), 'status.modified'),
3892 ui.label(_('%d added'), 'status.added'),
3892 ui.label(_('%d added'), 'status.added'),
3893 ui.label(_('%d removed'), 'status.removed'),
3893 ui.label(_('%d removed'), 'status.removed'),
3894 ui.label(_('%d renamed'), 'status.copied'),
3894 ui.label(_('%d renamed'), 'status.copied'),
3895 ui.label(_('%d copied'), 'status.copied'),
3895 ui.label(_('%d copied'), 'status.copied'),
3896 ui.label(_('%d deleted'), 'status.deleted'),
3896 ui.label(_('%d deleted'), 'status.deleted'),
3897 ui.label(_('%d unknown'), 'status.unknown'),
3897 ui.label(_('%d unknown'), 'status.unknown'),
3898 ui.label(_('%d ignored'), 'status.ignored'),
3898 ui.label(_('%d ignored'), 'status.ignored'),
3899 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3899 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3900 ui.label(_('%d subrepos'), 'status.modified')]
3900 ui.label(_('%d subrepos'), 'status.modified')]
3901 t = []
3901 t = []
3902 for s, l in zip(st, labels):
3902 for s, l in zip(st, labels):
3903 if s:
3903 if s:
3904 t.append(l % len(s))
3904 t.append(l % len(s))
3905
3905
3906 t = ', '.join(t)
3906 t = ', '.join(t)
3907 cleanworkdir = False
3907 cleanworkdir = False
3908
3908
3909 if len(parents) > 1:
3909 if len(parents) > 1:
3910 t += _(' (merge)')
3910 t += _(' (merge)')
3911 elif branch != parents[0].branch():
3911 elif branch != parents[0].branch():
3912 t += _(' (new branch)')
3912 t += _(' (new branch)')
3913 elif (parents[0].extra().get('close') and
3913 elif (parents[0].extra().get('close') and
3914 pnode in repo.branchheads(branch, closed=True)):
3914 pnode in repo.branchheads(branch, closed=True)):
3915 t += _(' (head closed)')
3915 t += _(' (head closed)')
3916 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3916 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3917 t += _(' (clean)')
3917 t += _(' (clean)')
3918 cleanworkdir = True
3918 cleanworkdir = True
3919 elif pnode not in bheads:
3919 elif pnode not in bheads:
3920 t += _(' (new branch head)')
3920 t += _(' (new branch head)')
3921
3921
3922 if cleanworkdir:
3922 if cleanworkdir:
3923 ui.status(_('commit: %s\n') % t.strip())
3923 ui.status(_('commit: %s\n') % t.strip())
3924 else:
3924 else:
3925 ui.write(_('commit: %s\n') % t.strip())
3925 ui.write(_('commit: %s\n') % t.strip())
3926
3926
3927 # all ancestors of branch heads - all ancestors of parent = new csets
3927 # all ancestors of branch heads - all ancestors of parent = new csets
3928 new = [0] * len(repo)
3928 new = [0] * len(repo)
3929 cl = repo.changelog
3929 cl = repo.changelog
3930 for a in [cl.rev(n) for n in bheads]:
3930 for a in [cl.rev(n) for n in bheads]:
3931 new[a] = 1
3931 new[a] = 1
3932 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3932 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3933 new[a] = 1
3933 new[a] = 1
3934 for a in [p.rev() for p in parents]:
3934 for a in [p.rev() for p in parents]:
3935 if a >= 0:
3935 if a >= 0:
3936 new[a] = 0
3936 new[a] = 0
3937 for a in cl.ancestors(*[p.rev() for p in parents]):
3937 for a in cl.ancestors(*[p.rev() for p in parents]):
3938 new[a] = 0
3938 new[a] = 0
3939 new = sum(new)
3939 new = sum(new)
3940
3940
3941 if new == 0:
3941 if new == 0:
3942 ui.status(_('update: (current)\n'))
3942 ui.status(_('update: (current)\n'))
3943 elif pnode not in bheads:
3943 elif pnode not in bheads:
3944 ui.write(_('update: %d new changesets (update)\n') % new)
3944 ui.write(_('update: %d new changesets (update)\n') % new)
3945 else:
3945 else:
3946 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3946 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3947 (new, len(bheads)))
3947 (new, len(bheads)))
3948
3948
3949 if opts.get('remote'):
3949 if opts.get('remote'):
3950 t = []
3950 t = []
3951 source, branches = hg.parseurl(ui.expandpath('default'))
3951 source, branches = hg.parseurl(ui.expandpath('default'))
3952 other = hg.repository(hg.remoteui(repo, {}), source)
3952 other = hg.repository(hg.remoteui(repo, {}), source)
3953 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3953 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3954 ui.debug('comparing with %s\n' % url.hidepassword(source))
3954 ui.debug('comparing with %s\n' % url.hidepassword(source))
3955 repo.ui.pushbuffer()
3955 repo.ui.pushbuffer()
3956 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3956 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3957 repo.ui.popbuffer()
3957 repo.ui.popbuffer()
3958 if incoming:
3958 if incoming:
3959 t.append(_('1 or more incoming'))
3959 t.append(_('1 or more incoming'))
3960
3960
3961 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3961 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3962 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3962 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3963 other = hg.repository(hg.remoteui(repo, {}), dest)
3963 other = hg.repository(hg.remoteui(repo, {}), dest)
3964 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3964 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3965 repo.ui.pushbuffer()
3965 repo.ui.pushbuffer()
3966 o = discovery.findoutgoing(repo, other)
3966 o = discovery.findoutgoing(repo, other)
3967 repo.ui.popbuffer()
3967 repo.ui.popbuffer()
3968 o = repo.changelog.nodesbetween(o, None)[0]
3968 o = repo.changelog.nodesbetween(o, None)[0]
3969 if o:
3969 if o:
3970 t.append(_('%d outgoing') % len(o))
3970 t.append(_('%d outgoing') % len(o))
3971 if 'bookmarks' in other.listkeys('namespaces'):
3971 if 'bookmarks' in other.listkeys('namespaces'):
3972 lmarks = repo.listkeys('bookmarks')
3972 lmarks = repo.listkeys('bookmarks')
3973 rmarks = other.listkeys('bookmarks')
3973 rmarks = other.listkeys('bookmarks')
3974 diff = set(rmarks) - set(lmarks)
3974 diff = set(rmarks) - set(lmarks)
3975 if len(diff) > 0:
3975 if len(diff) > 0:
3976 t.append(_('%d incoming bookmarks') % len(diff))
3976 t.append(_('%d incoming bookmarks') % len(diff))
3977 diff = set(lmarks) - set(rmarks)
3977 diff = set(lmarks) - set(rmarks)
3978 if len(diff) > 0:
3978 if len(diff) > 0:
3979 t.append(_('%d outgoing bookmarks') % len(diff))
3979 t.append(_('%d outgoing bookmarks') % len(diff))
3980
3980
3981 if t:
3981 if t:
3982 ui.write(_('remote: %s\n') % (', '.join(t)))
3982 ui.write(_('remote: %s\n') % (', '.join(t)))
3983 else:
3983 else:
3984 ui.status(_('remote: (synced)\n'))
3984 ui.status(_('remote: (synced)\n'))
3985
3985
3986 def tag(ui, repo, name1, *names, **opts):
3986 def tag(ui, repo, name1, *names, **opts):
3987 """add one or more tags for the current or given revision
3987 """add one or more tags for the current or given revision
3988
3988
3989 Name a particular revision using <name>.
3989 Name a particular revision using <name>.
3990
3990
3991 Tags are used to name particular revisions of the repository and are
3991 Tags are used to name particular revisions of the repository and are
3992 very useful to compare different revisions, to go back to significant
3992 very useful to compare different revisions, to go back to significant
3993 earlier versions or to mark branch points as releases, etc. Changing
3993 earlier versions or to mark branch points as releases, etc. Changing
3994 an existing tag is normally disallowed; use -f/--force to override.
3994 an existing tag is normally disallowed; use -f/--force to override.
3995
3995
3996 If no revision is given, the parent of the working directory is
3996 If no revision is given, the parent of the working directory is
3997 used, or tip if no revision is checked out.
3997 used, or tip if no revision is checked out.
3998
3998
3999 To facilitate version control, distribution, and merging of tags,
3999 To facilitate version control, distribution, and merging of tags,
4000 they are stored as a file named ".hgtags" which is managed similarly
4000 they are stored as a file named ".hgtags" which is managed similarly
4001 to other project files and can be hand-edited if necessary. This
4001 to other project files and can be hand-edited if necessary. This
4002 also means that tagging creates a new commit. The file
4002 also means that tagging creates a new commit. The file
4003 ".hg/localtags" is used for local tags (not shared among
4003 ".hg/localtags" is used for local tags (not shared among
4004 repositories).
4004 repositories).
4005
4005
4006 Tag commits are usually made at the head of a branch. If the parent
4006 Tag commits are usually made at the head of a branch. If the parent
4007 of the working directory is not a branch head, :hg:`tag` aborts; use
4007 of the working directory is not a branch head, :hg:`tag` aborts; use
4008 -f/--force to force the tag commit to be based on a non-head
4008 -f/--force to force the tag commit to be based on a non-head
4009 changeset.
4009 changeset.
4010
4010
4011 See :hg:`help dates` for a list of formats valid for -d/--date.
4011 See :hg:`help dates` for a list of formats valid for -d/--date.
4012
4012
4013 Since tag names have priority over branch names during revision
4013 Since tag names have priority over branch names during revision
4014 lookup, using an existing branch name as a tag name is discouraged.
4014 lookup, using an existing branch name as a tag name is discouraged.
4015
4015
4016 Returns 0 on success.
4016 Returns 0 on success.
4017 """
4017 """
4018
4018
4019 rev_ = "."
4019 rev_ = "."
4020 names = [t.strip() for t in (name1,) + names]
4020 names = [t.strip() for t in (name1,) + names]
4021 if len(names) != len(set(names)):
4021 if len(names) != len(set(names)):
4022 raise util.Abort(_('tag names must be unique'))
4022 raise util.Abort(_('tag names must be unique'))
4023 for n in names:
4023 for n in names:
4024 if n in ['tip', '.', 'null']:
4024 if n in ['tip', '.', 'null']:
4025 raise util.Abort(_('the name \'%s\' is reserved') % n)
4025 raise util.Abort(_('the name \'%s\' is reserved') % n)
4026 if not n:
4026 if not n:
4027 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4027 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4028 if opts.get('rev') and opts.get('remove'):
4028 if opts.get('rev') and opts.get('remove'):
4029 raise util.Abort(_("--rev and --remove are incompatible"))
4029 raise util.Abort(_("--rev and --remove are incompatible"))
4030 if opts.get('rev'):
4030 if opts.get('rev'):
4031 rev_ = opts['rev']
4031 rev_ = opts['rev']
4032 message = opts.get('message')
4032 message = opts.get('message')
4033 if opts.get('remove'):
4033 if opts.get('remove'):
4034 expectedtype = opts.get('local') and 'local' or 'global'
4034 expectedtype = opts.get('local') and 'local' or 'global'
4035 for n in names:
4035 for n in names:
4036 if not repo.tagtype(n):
4036 if not repo.tagtype(n):
4037 raise util.Abort(_('tag \'%s\' does not exist') % n)
4037 raise util.Abort(_('tag \'%s\' does not exist') % n)
4038 if repo.tagtype(n) != expectedtype:
4038 if repo.tagtype(n) != expectedtype:
4039 if expectedtype == 'global':
4039 if expectedtype == 'global':
4040 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
4040 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
4041 else:
4041 else:
4042 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
4042 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
4043 rev_ = nullid
4043 rev_ = nullid
4044 if not message:
4044 if not message:
4045 # we don't translate commit messages
4045 # we don't translate commit messages
4046 message = 'Removed tag %s' % ', '.join(names)
4046 message = 'Removed tag %s' % ', '.join(names)
4047 elif not opts.get('force'):
4047 elif not opts.get('force'):
4048 for n in names:
4048 for n in names:
4049 if n in repo.tags():
4049 if n in repo.tags():
4050 raise util.Abort(_('tag \'%s\' already exists '
4050 raise util.Abort(_('tag \'%s\' already exists '
4051 '(use -f to force)') % n)
4051 '(use -f to force)') % n)
4052 if not opts.get('local'):
4052 if not opts.get('local'):
4053 p1, p2 = repo.dirstate.parents()
4053 p1, p2 = repo.dirstate.parents()
4054 if p2 != nullid:
4054 if p2 != nullid:
4055 raise util.Abort(_('uncommitted merge'))
4055 raise util.Abort(_('uncommitted merge'))
4056 bheads = repo.branchheads()
4056 bheads = repo.branchheads()
4057 if not opts.get('force') and bheads and p1 not in bheads:
4057 if not opts.get('force') and bheads and p1 not in bheads:
4058 raise util.Abort(_('not at a branch head (use -f to force)'))
4058 raise util.Abort(_('not at a branch head (use -f to force)'))
4059 r = cmdutil.revsingle(repo, rev_).node()
4059 r = cmdutil.revsingle(repo, rev_).node()
4060
4060
4061 if not message:
4061 if not message:
4062 # we don't translate commit messages
4062 # we don't translate commit messages
4063 message = ('Added tag %s for changeset %s' %
4063 message = ('Added tag %s for changeset %s' %
4064 (', '.join(names), short(r)))
4064 (', '.join(names), short(r)))
4065
4065
4066 date = opts.get('date')
4066 date = opts.get('date')
4067 if date:
4067 if date:
4068 date = util.parsedate(date)
4068 date = util.parsedate(date)
4069
4069
4070 if opts.get('edit'):
4070 if opts.get('edit'):
4071 message = ui.edit(message, ui.username())
4071 message = ui.edit(message, ui.username())
4072
4072
4073 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4073 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4074
4074
4075 def tags(ui, repo):
4075 def tags(ui, repo):
4076 """list repository tags
4076 """list repository tags
4077
4077
4078 This lists both regular and local tags. When the -v/--verbose
4078 This lists both regular and local tags. When the -v/--verbose
4079 switch is used, a third column "local" is printed for local tags.
4079 switch is used, a third column "local" is printed for local tags.
4080
4080
4081 Returns 0 on success.
4081 Returns 0 on success.
4082 """
4082 """
4083
4083
4084 hexfunc = ui.debugflag and hex or short
4084 hexfunc = ui.debugflag and hex or short
4085 tagtype = ""
4085 tagtype = ""
4086
4086
4087 for t, n in reversed(repo.tagslist()):
4087 for t, n in reversed(repo.tagslist()):
4088 if ui.quiet:
4088 if ui.quiet:
4089 ui.write("%s\n" % t)
4089 ui.write("%s\n" % t)
4090 continue
4090 continue
4091
4091
4092 try:
4092 try:
4093 hn = hexfunc(n)
4093 hn = hexfunc(n)
4094 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4094 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4095 except error.LookupError:
4095 except error.LookupError:
4096 r = " ?:%s" % hn
4096 r = " ?:%s" % hn
4097 else:
4097 else:
4098 spaces = " " * (30 - encoding.colwidth(t))
4098 spaces = " " * (30 - encoding.colwidth(t))
4099 if ui.verbose:
4099 if ui.verbose:
4100 if repo.tagtype(t) == 'local':
4100 if repo.tagtype(t) == 'local':
4101 tagtype = " local"
4101 tagtype = " local"
4102 else:
4102 else:
4103 tagtype = ""
4103 tagtype = ""
4104 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4104 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4105
4105
4106 def tip(ui, repo, **opts):
4106 def tip(ui, repo, **opts):
4107 """show the tip revision
4107 """show the tip revision
4108
4108
4109 The tip revision (usually just called the tip) is the changeset
4109 The tip revision (usually just called the tip) is the changeset
4110 most recently added to the repository (and therefore the most
4110 most recently added to the repository (and therefore the most
4111 recently changed head).
4111 recently changed head).
4112
4112
4113 If you have just made a commit, that commit will be the tip. If
4113 If you have just made a commit, that commit will be the tip. If
4114 you have just pulled changes from another repository, the tip of
4114 you have just pulled changes from another repository, the tip of
4115 that repository becomes the current tip. The "tip" tag is special
4115 that repository becomes the current tip. The "tip" tag is special
4116 and cannot be renamed or assigned to a different changeset.
4116 and cannot be renamed or assigned to a different changeset.
4117
4117
4118 Returns 0 on success.
4118 Returns 0 on success.
4119 """
4119 """
4120 displayer = cmdutil.show_changeset(ui, repo, opts)
4120 displayer = cmdutil.show_changeset(ui, repo, opts)
4121 displayer.show(repo[len(repo) - 1])
4121 displayer.show(repo[len(repo) - 1])
4122 displayer.close()
4122 displayer.close()
4123
4123
4124 def unbundle(ui, repo, fname1, *fnames, **opts):
4124 def unbundle(ui, repo, fname1, *fnames, **opts):
4125 """apply one or more changegroup files
4125 """apply one or more changegroup files
4126
4126
4127 Apply one or more compressed changegroup files generated by the
4127 Apply one or more compressed changegroup files generated by the
4128 bundle command.
4128 bundle command.
4129
4129
4130 Returns 0 on success, 1 if an update has unresolved files.
4130 Returns 0 on success, 1 if an update has unresolved files.
4131 """
4131 """
4132 fnames = (fname1,) + fnames
4132 fnames = (fname1,) + fnames
4133
4133
4134 lock = repo.lock()
4134 lock = repo.lock()
4135 wc = repo['.']
4135 wc = repo['.']
4136 try:
4136 try:
4137 for fname in fnames:
4137 for fname in fnames:
4138 f = url.open(ui, fname)
4138 f = url.open(ui, fname)
4139 gen = changegroup.readbundle(f, fname)
4139 gen = changegroup.readbundle(f, fname)
4140 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4140 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4141 lock=lock)
4141 lock=lock)
4142 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4142 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4143 finally:
4143 finally:
4144 lock.release()
4144 lock.release()
4145 return postincoming(ui, repo, modheads, opts.get('update'), None)
4145 return postincoming(ui, repo, modheads, opts.get('update'), None)
4146
4146
4147 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4147 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4148 """update working directory (or switch revisions)
4148 """update working directory (or switch revisions)
4149
4149
4150 Update the repository's working directory to the specified
4150 Update the repository's working directory to the specified
4151 changeset. If no changeset is specified, update to the tip of the
4151 changeset. If no changeset is specified, update to the tip of the
4152 current named branch.
4152 current named branch.
4153
4153
4154 If the changeset is not a descendant of the working directory's
4154 If the changeset is not a descendant of the working directory's
4155 parent, the update is aborted. With the -c/--check option, the
4155 parent, the update is aborted. With the -c/--check option, the
4156 working directory is checked for uncommitted changes; if none are
4156 working directory is checked for uncommitted changes; if none are
4157 found, the working directory is updated to the specified
4157 found, the working directory is updated to the specified
4158 changeset.
4158 changeset.
4159
4159
4160 The following rules apply when the working directory contains
4160 The following rules apply when the working directory contains
4161 uncommitted changes:
4161 uncommitted changes:
4162
4162
4163 1. If neither -c/--check nor -C/--clean is specified, and if
4163 1. If neither -c/--check nor -C/--clean is specified, and if
4164 the requested changeset is an ancestor or descendant of
4164 the requested changeset is an ancestor or descendant of
4165 the working directory's parent, the uncommitted changes
4165 the working directory's parent, the uncommitted changes
4166 are merged into the requested changeset and the merged
4166 are merged into the requested changeset and the merged
4167 result is left uncommitted. If the requested changeset is
4167 result is left uncommitted. If the requested changeset is
4168 not an ancestor or descendant (that is, it is on another
4168 not an ancestor or descendant (that is, it is on another
4169 branch), the update is aborted and the uncommitted changes
4169 branch), the update is aborted and the uncommitted changes
4170 are preserved.
4170 are preserved.
4171
4171
4172 2. With the -c/--check option, the update is aborted and the
4172 2. With the -c/--check option, the update is aborted and the
4173 uncommitted changes are preserved.
4173 uncommitted changes are preserved.
4174
4174
4175 3. With the -C/--clean option, uncommitted changes are discarded and
4175 3. With the -C/--clean option, uncommitted changes are discarded and
4176 the working directory is updated to the requested changeset.
4176 the working directory is updated to the requested changeset.
4177
4177
4178 Use null as the changeset to remove the working directory (like
4178 Use null as the changeset to remove the working directory (like
4179 :hg:`clone -U`).
4179 :hg:`clone -U`).
4180
4180
4181 If you want to update just one file to an older changeset, use
4181 If you want to update just one file to an older changeset, use
4182 :hg:`revert`.
4182 :hg:`revert`.
4183
4183
4184 See :hg:`help dates` for a list of formats valid for -d/--date.
4184 See :hg:`help dates` for a list of formats valid for -d/--date.
4185
4185
4186 Returns 0 on success, 1 if there are unresolved files.
4186 Returns 0 on success, 1 if there are unresolved files.
4187 """
4187 """
4188 if rev and node:
4188 if rev and node:
4189 raise util.Abort(_("please specify just one revision"))
4189 raise util.Abort(_("please specify just one revision"))
4190
4190
4191 if rev is None or rev == '':
4191 if rev is None or rev == '':
4192 rev = node
4192 rev = node
4193
4193
4194 # if we defined a bookmark, we have to remember the original bookmark name
4194 # if we defined a bookmark, we have to remember the original bookmark name
4195 brev = rev
4195 brev = rev
4196 rev = cmdutil.revsingle(repo, rev, rev).rev()
4196 rev = cmdutil.revsingle(repo, rev, rev).rev()
4197
4197
4198 if check and clean:
4198 if check and clean:
4199 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4199 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4200
4200
4201 if check:
4201 if check:
4202 # we could use dirty() but we can ignore merge and branch trivia
4202 # we could use dirty() but we can ignore merge and branch trivia
4203 c = repo[None]
4203 c = repo[None]
4204 if c.modified() or c.added() or c.removed():
4204 if c.modified() or c.added() or c.removed():
4205 raise util.Abort(_("uncommitted local changes"))
4205 raise util.Abort(_("uncommitted local changes"))
4206
4206
4207 if date:
4207 if date:
4208 if rev:
4208 if rev:
4209 raise util.Abort(_("you can't specify a revision and a date"))
4209 raise util.Abort(_("you can't specify a revision and a date"))
4210 rev = cmdutil.finddate(ui, repo, date)
4210 rev = cmdutil.finddate(ui, repo, date)
4211
4211
4212 if clean or check:
4212 if clean or check:
4213 ret = hg.clean(repo, rev)
4213 ret = hg.clean(repo, rev)
4214 else:
4214 else:
4215 ret = hg.update(repo, rev)
4215 ret = hg.update(repo, rev)
4216
4216
4217 if brev in repo._bookmarks:
4217 if brev in repo._bookmarks:
4218 bookmarks.setcurrent(repo, brev)
4218 bookmarks.setcurrent(repo, brev)
4219
4219
4220 return ret
4220 return ret
4221
4221
4222 def verify(ui, repo):
4222 def verify(ui, repo):
4223 """verify the integrity of the repository
4223 """verify the integrity of the repository
4224
4224
4225 Verify the integrity of the current repository.
4225 Verify the integrity of the current repository.
4226
4226
4227 This will perform an extensive check of the repository's
4227 This will perform an extensive check of the repository's
4228 integrity, validating the hashes and checksums of each entry in
4228 integrity, validating the hashes and checksums of each entry in
4229 the changelog, manifest, and tracked files, as well as the
4229 the changelog, manifest, and tracked files, as well as the
4230 integrity of their crosslinks and indices.
4230 integrity of their crosslinks and indices.
4231
4231
4232 Returns 0 on success, 1 if errors are encountered.
4232 Returns 0 on success, 1 if errors are encountered.
4233 """
4233 """
4234 return hg.verify(repo)
4234 return hg.verify(repo)
4235
4235
4236 def version_(ui):
4236 def version_(ui):
4237 """output version and copyright information"""
4237 """output version and copyright information"""
4238 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4238 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4239 % util.version())
4239 % util.version())
4240 ui.status(_(
4240 ui.status(_(
4241 "(see http://mercurial.selenic.com for more information)\n"
4241 "(see http://mercurial.selenic.com for more information)\n"
4242 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4242 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4243 "This is free software; see the source for copying conditions. "
4243 "This is free software; see the source for copying conditions. "
4244 "There is NO\nwarranty; "
4244 "There is NO\nwarranty; "
4245 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4245 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4246 ))
4246 ))
4247
4247
4248 # Command options and aliases are listed here, alphabetically
4248 # Command options and aliases are listed here, alphabetically
4249
4249
4250 globalopts = [
4250 globalopts = [
4251 ('R', 'repository', '',
4251 ('R', 'repository', '',
4252 _('repository root directory or name of overlay bundle file'),
4252 _('repository root directory or name of overlay bundle file'),
4253 _('REPO')),
4253 _('REPO')),
4254 ('', 'cwd', '',
4254 ('', 'cwd', '',
4255 _('change working directory'), _('DIR')),
4255 _('change working directory'), _('DIR')),
4256 ('y', 'noninteractive', None,
4256 ('y', 'noninteractive', None,
4257 _('do not prompt, assume \'yes\' for any required answers')),
4257 _('do not prompt, assume \'yes\' for any required answers')),
4258 ('q', 'quiet', None, _('suppress output')),
4258 ('q', 'quiet', None, _('suppress output')),
4259 ('v', 'verbose', None, _('enable additional output')),
4259 ('v', 'verbose', None, _('enable additional output')),
4260 ('', 'config', [],
4260 ('', 'config', [],
4261 _('set/override config option (use \'section.name=value\')'),
4261 _('set/override config option (use \'section.name=value\')'),
4262 _('CONFIG')),
4262 _('CONFIG')),
4263 ('', 'debug', None, _('enable debugging output')),
4263 ('', 'debug', None, _('enable debugging output')),
4264 ('', 'debugger', None, _('start debugger')),
4264 ('', 'debugger', None, _('start debugger')),
4265 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4265 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4266 _('ENCODE')),
4266 _('ENCODE')),
4267 ('', 'encodingmode', encoding.encodingmode,
4267 ('', 'encodingmode', encoding.encodingmode,
4268 _('set the charset encoding mode'), _('MODE')),
4268 _('set the charset encoding mode'), _('MODE')),
4269 ('', 'traceback', None, _('always print a traceback on exception')),
4269 ('', 'traceback', None, _('always print a traceback on exception')),
4270 ('', 'time', None, _('time how long the command takes')),
4270 ('', 'time', None, _('time how long the command takes')),
4271 ('', 'profile', None, _('print command execution profile')),
4271 ('', 'profile', None, _('print command execution profile')),
4272 ('', 'version', None, _('output version information and exit')),
4272 ('', 'version', None, _('output version information and exit')),
4273 ('h', 'help', None, _('display help and exit')),
4273 ('h', 'help', None, _('display help and exit')),
4274 ]
4274 ]
4275
4275
4276 dryrunopts = [('n', 'dry-run', None,
4276 dryrunopts = [('n', 'dry-run', None,
4277 _('do not perform actions, just print output'))]
4277 _('do not perform actions, just print output'))]
4278
4278
4279 remoteopts = [
4279 remoteopts = [
4280 ('e', 'ssh', '',
4280 ('e', 'ssh', '',
4281 _('specify ssh command to use'), _('CMD')),
4281 _('specify ssh command to use'), _('CMD')),
4282 ('', 'remotecmd', '',
4282 ('', 'remotecmd', '',
4283 _('specify hg command to run on the remote side'), _('CMD')),
4283 _('specify hg command to run on the remote side'), _('CMD')),
4284 ('', 'insecure', None,
4284 ('', 'insecure', None,
4285 _('do not verify server certificate (ignoring web.cacerts config)')),
4285 _('do not verify server certificate (ignoring web.cacerts config)')),
4286 ]
4286 ]
4287
4287
4288 walkopts = [
4288 walkopts = [
4289 ('I', 'include', [],
4289 ('I', 'include', [],
4290 _('include names matching the given patterns'), _('PATTERN')),
4290 _('include names matching the given patterns'), _('PATTERN')),
4291 ('X', 'exclude', [],
4291 ('X', 'exclude', [],
4292 _('exclude names matching the given patterns'), _('PATTERN')),
4292 _('exclude names matching the given patterns'), _('PATTERN')),
4293 ]
4293 ]
4294
4294
4295 commitopts = [
4295 commitopts = [
4296 ('m', 'message', '',
4296 ('m', 'message', '',
4297 _('use text as commit message'), _('TEXT')),
4297 _('use text as commit message'), _('TEXT')),
4298 ('l', 'logfile', '',
4298 ('l', 'logfile', '',
4299 _('read commit message from file'), _('FILE')),
4299 _('read commit message from file'), _('FILE')),
4300 ]
4300 ]
4301
4301
4302 commitopts2 = [
4302 commitopts2 = [
4303 ('d', 'date', '',
4303 ('d', 'date', '',
4304 _('record datecode as commit date'), _('DATE')),
4304 _('record datecode as commit date'), _('DATE')),
4305 ('u', 'user', '',
4305 ('u', 'user', '',
4306 _('record the specified user as committer'), _('USER')),
4306 _('record the specified user as committer'), _('USER')),
4307 ]
4307 ]
4308
4308
4309 templateopts = [
4309 templateopts = [
4310 ('', 'style', '',
4310 ('', 'style', '',
4311 _('display using template map file'), _('STYLE')),
4311 _('display using template map file'), _('STYLE')),
4312 ('', 'template', '',
4312 ('', 'template', '',
4313 _('display with template'), _('TEMPLATE')),
4313 _('display with template'), _('TEMPLATE')),
4314 ]
4314 ]
4315
4315
4316 logopts = [
4316 logopts = [
4317 ('p', 'patch', None, _('show patch')),
4317 ('p', 'patch', None, _('show patch')),
4318 ('g', 'git', None, _('use git extended diff format')),
4318 ('g', 'git', None, _('use git extended diff format')),
4319 ('l', 'limit', '',
4319 ('l', 'limit', '',
4320 _('limit number of changes displayed'), _('NUM')),
4320 _('limit number of changes displayed'), _('NUM')),
4321 ('M', 'no-merges', None, _('do not show merges')),
4321 ('M', 'no-merges', None, _('do not show merges')),
4322 ('', 'stat', None, _('output diffstat-style summary of changes')),
4322 ('', 'stat', None, _('output diffstat-style summary of changes')),
4323 ] + templateopts
4323 ] + templateopts
4324
4324
4325 diffopts = [
4325 diffopts = [
4326 ('a', 'text', None, _('treat all files as text')),
4326 ('a', 'text', None, _('treat all files as text')),
4327 ('g', 'git', None, _('use git extended diff format')),
4327 ('g', 'git', None, _('use git extended diff format')),
4328 ('', 'nodates', None, _('omit dates from diff headers'))
4328 ('', 'nodates', None, _('omit dates from diff headers'))
4329 ]
4329 ]
4330
4330
4331 diffopts2 = [
4331 diffopts2 = [
4332 ('p', 'show-function', None, _('show which function each change is in')),
4332 ('p', 'show-function', None, _('show which function each change is in')),
4333 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4333 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4334 ('w', 'ignore-all-space', None,
4334 ('w', 'ignore-all-space', None,
4335 _('ignore white space when comparing lines')),
4335 _('ignore white space when comparing lines')),
4336 ('b', 'ignore-space-change', None,
4336 ('b', 'ignore-space-change', None,
4337 _('ignore changes in the amount of white space')),
4337 _('ignore changes in the amount of white space')),
4338 ('B', 'ignore-blank-lines', None,
4338 ('B', 'ignore-blank-lines', None,
4339 _('ignore changes whose lines are all blank')),
4339 _('ignore changes whose lines are all blank')),
4340 ('U', 'unified', '',
4340 ('U', 'unified', '',
4341 _('number of lines of context to show'), _('NUM')),
4341 _('number of lines of context to show'), _('NUM')),
4342 ('', 'stat', None, _('output diffstat-style summary of changes')),
4342 ('', 'stat', None, _('output diffstat-style summary of changes')),
4343 ]
4343 ]
4344
4344
4345 similarityopts = [
4345 similarityopts = [
4346 ('s', 'similarity', '',
4346 ('s', 'similarity', '',
4347 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4347 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4348 ]
4348 ]
4349
4349
4350 subrepoopts = [
4350 subrepoopts = [
4351 ('S', 'subrepos', None,
4351 ('S', 'subrepos', None,
4352 _('recurse into subrepositories'))
4352 _('recurse into subrepositories'))
4353 ]
4353 ]
4354
4354
4355 table = {
4355 table = {
4356 "^add": (add, walkopts + subrepoopts + dryrunopts,
4356 "^add": (add, walkopts + subrepoopts + dryrunopts,
4357 _('[OPTION]... [FILE]...')),
4357 _('[OPTION]... [FILE]...')),
4358 "addremove":
4358 "addremove":
4359 (addremove, similarityopts + walkopts + dryrunopts,
4359 (addremove, similarityopts + walkopts + dryrunopts,
4360 _('[OPTION]... [FILE]...')),
4360 _('[OPTION]... [FILE]...')),
4361 "^annotate|blame":
4361 "^annotate|blame":
4362 (annotate,
4362 (annotate,
4363 [('r', 'rev', '',
4363 [('r', 'rev', '',
4364 _('annotate the specified revision'), _('REV')),
4364 _('annotate the specified revision'), _('REV')),
4365 ('', 'follow', None,
4365 ('', 'follow', None,
4366 _('follow copies/renames and list the filename (DEPRECATED)')),
4366 _('follow copies/renames and list the filename (DEPRECATED)')),
4367 ('', 'no-follow', None, _("don't follow copies and renames")),
4367 ('', 'no-follow', None, _("don't follow copies and renames")),
4368 ('a', 'text', None, _('treat all files as text')),
4368 ('a', 'text', None, _('treat all files as text')),
4369 ('u', 'user', None, _('list the author (long with -v)')),
4369 ('u', 'user', None, _('list the author (long with -v)')),
4370 ('f', 'file', None, _('list the filename')),
4370 ('f', 'file', None, _('list the filename')),
4371 ('d', 'date', None, _('list the date (short with -q)')),
4371 ('d', 'date', None, _('list the date (short with -q)')),
4372 ('n', 'number', None, _('list the revision number (default)')),
4372 ('n', 'number', None, _('list the revision number (default)')),
4373 ('c', 'changeset', None, _('list the changeset')),
4373 ('c', 'changeset', None, _('list the changeset')),
4374 ('l', 'line-number', None,
4374 ('l', 'line-number', None,
4375 _('show line number at the first appearance'))
4375 _('show line number at the first appearance'))
4376 ] + walkopts,
4376 ] + walkopts,
4377 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4377 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4378 "archive":
4378 "archive":
4379 (archive,
4379 (archive,
4380 [('', 'no-decode', None, _('do not pass files through decoders')),
4380 [('', 'no-decode', None, _('do not pass files through decoders')),
4381 ('p', 'prefix', '',
4381 ('p', 'prefix', '',
4382 _('directory prefix for files in archive'), _('PREFIX')),
4382 _('directory prefix for files in archive'), _('PREFIX')),
4383 ('r', 'rev', '',
4383 ('r', 'rev', '',
4384 _('revision to distribute'), _('REV')),
4384 _('revision to distribute'), _('REV')),
4385 ('t', 'type', '',
4385 ('t', 'type', '',
4386 _('type of distribution to create'), _('TYPE')),
4386 _('type of distribution to create'), _('TYPE')),
4387 ] + subrepoopts + walkopts,
4387 ] + subrepoopts + walkopts,
4388 _('[OPTION]... DEST')),
4388 _('[OPTION]... DEST')),
4389 "backout":
4389 "backout":
4390 (backout,
4390 (backout,
4391 [('', 'merge', None,
4391 [('', 'merge', None,
4392 _('merge with old dirstate parent after backout')),
4392 _('merge with old dirstate parent after backout')),
4393 ('', 'parent', '',
4393 ('', 'parent', '',
4394 _('parent to choose when backing out merge'), _('REV')),
4394 _('parent to choose when backing out merge'), _('REV')),
4395 ('t', 'tool', '',
4395 ('t', 'tool', '',
4396 _('specify merge tool')),
4396 _('specify merge tool')),
4397 ('r', 'rev', '',
4397 ('r', 'rev', '',
4398 _('revision to backout'), _('REV')),
4398 _('revision to backout'), _('REV')),
4399 ] + walkopts + commitopts + commitopts2,
4399 ] + walkopts + commitopts + commitopts2,
4400 _('[OPTION]... [-r] REV')),
4400 _('[OPTION]... [-r] REV')),
4401 "bisect":
4401 "bisect":
4402 (bisect,
4402 (bisect,
4403 [('r', 'reset', False, _('reset bisect state')),
4403 [('r', 'reset', False, _('reset bisect state')),
4404 ('g', 'good', False, _('mark changeset good')),
4404 ('g', 'good', False, _('mark changeset good')),
4405 ('b', 'bad', False, _('mark changeset bad')),
4405 ('b', 'bad', False, _('mark changeset bad')),
4406 ('s', 'skip', False, _('skip testing changeset')),
4406 ('s', 'skip', False, _('skip testing changeset')),
4407 ('e', 'extend', False, _('extend the bisect range')),
4407 ('e', 'extend', False, _('extend the bisect range')),
4408 ('c', 'command', '',
4408 ('c', 'command', '',
4409 _('use command to check changeset state'), _('CMD')),
4409 _('use command to check changeset state'), _('CMD')),
4410 ('U', 'noupdate', False, _('do not update to target'))],
4410 ('U', 'noupdate', False, _('do not update to target'))],
4411 _("[-gbsr] [-U] [-c CMD] [REV]")),
4411 _("[-gbsr] [-U] [-c CMD] [REV]")),
4412 "bookmarks":
4412 "bookmarks":
4413 (bookmark,
4413 (bookmark,
4414 [('f', 'force', False, _('force')),
4414 [('f', 'force', False, _('force')),
4415 ('r', 'rev', '', _('revision'), _('REV')),
4415 ('r', 'rev', '', _('revision'), _('REV')),
4416 ('d', 'delete', False, _('delete a given bookmark')),
4416 ('d', 'delete', False, _('delete a given bookmark')),
4417 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4417 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4418 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4418 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4419 "branch":
4419 "branch":
4420 (branch,
4420 (branch,
4421 [('f', 'force', None,
4421 [('f', 'force', None,
4422 _('set branch name even if it shadows an existing branch')),
4422 _('set branch name even if it shadows an existing branch')),
4423 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4423 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4424 _('[-fC] [NAME]')),
4424 _('[-fC] [NAME]')),
4425 "branches":
4425 "branches":
4426 (branches,
4426 (branches,
4427 [('a', 'active', False,
4427 [('a', 'active', False,
4428 _('show only branches that have unmerged heads')),
4428 _('show only branches that have unmerged heads')),
4429 ('c', 'closed', False,
4429 ('c', 'closed', False,
4430 _('show normal and closed branches'))],
4430 _('show normal and closed branches'))],
4431 _('[-ac]')),
4431 _('[-ac]')),
4432 "bundle":
4432 "bundle":
4433 (bundle,
4433 (bundle,
4434 [('f', 'force', None,
4434 [('f', 'force', None,
4435 _('run even when the destination is unrelated')),
4435 _('run even when the destination is unrelated')),
4436 ('r', 'rev', [],
4436 ('r', 'rev', [],
4437 _('a changeset intended to be added to the destination'),
4437 _('a changeset intended to be added to the destination'),
4438 _('REV')),
4438 _('REV')),
4439 ('b', 'branch', [],
4439 ('b', 'branch', [],
4440 _('a specific branch you would like to bundle'),
4440 _('a specific branch you would like to bundle'),
4441 _('BRANCH')),
4441 _('BRANCH')),
4442 ('', 'base', [],
4442 ('', 'base', [],
4443 _('a base changeset assumed to be available at the destination'),
4443 _('a base changeset assumed to be available at the destination'),
4444 _('REV')),
4444 _('REV')),
4445 ('a', 'all', None, _('bundle all changesets in the repository')),
4445 ('a', 'all', None, _('bundle all changesets in the repository')),
4446 ('t', 'type', 'bzip2',
4446 ('t', 'type', 'bzip2',
4447 _('bundle compression type to use'), _('TYPE')),
4447 _('bundle compression type to use'), _('TYPE')),
4448 ] + remoteopts,
4448 ] + remoteopts,
4449 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4449 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4450 "cat":
4450 "cat":
4451 (cat,
4451 (cat,
4452 [('o', 'output', '',
4452 [('o', 'output', '',
4453 _('print output to file with formatted name'), _('FORMAT')),
4453 _('print output to file with formatted name'), _('FORMAT')),
4454 ('r', 'rev', '',
4454 ('r', 'rev', '',
4455 _('print the given revision'), _('REV')),
4455 _('print the given revision'), _('REV')),
4456 ('', 'decode', None, _('apply any matching decode filter')),
4456 ('', 'decode', None, _('apply any matching decode filter')),
4457 ] + walkopts,
4457 ] + walkopts,
4458 _('[OPTION]... FILE...')),
4458 _('[OPTION]... FILE...')),
4459 "^clone":
4459 "^clone":
4460 (clone,
4460 (clone,
4461 [('U', 'noupdate', None,
4461 [('U', 'noupdate', None,
4462 _('the clone will include an empty working copy (only a repository)')),
4462 _('the clone will include an empty working copy (only a repository)')),
4463 ('u', 'updaterev', '',
4463 ('u', 'updaterev', '',
4464 _('revision, tag or branch to check out'), _('REV')),
4464 _('revision, tag or branch to check out'), _('REV')),
4465 ('r', 'rev', [],
4465 ('r', 'rev', [],
4466 _('include the specified changeset'), _('REV')),
4466 _('include the specified changeset'), _('REV')),
4467 ('b', 'branch', [],
4467 ('b', 'branch', [],
4468 _('clone only the specified branch'), _('BRANCH')),
4468 _('clone only the specified branch'), _('BRANCH')),
4469 ('', 'pull', None, _('use pull protocol to copy metadata')),
4469 ('', 'pull', None, _('use pull protocol to copy metadata')),
4470 ('', 'uncompressed', None,
4470 ('', 'uncompressed', None,
4471 _('use uncompressed transfer (fast over LAN)')),
4471 _('use uncompressed transfer (fast over LAN)')),
4472 ] + remoteopts,
4472 ] + remoteopts,
4473 _('[OPTION]... SOURCE [DEST]')),
4473 _('[OPTION]... SOURCE [DEST]')),
4474 "^commit|ci":
4474 "^commit|ci":
4475 (commit,
4475 (commit,
4476 [('A', 'addremove', None,
4476 [('A', 'addremove', None,
4477 _('mark new/missing files as added/removed before committing')),
4477 _('mark new/missing files as added/removed before committing')),
4478 ('', 'close-branch', None,
4478 ('', 'close-branch', None,
4479 _('mark a branch as closed, hiding it from the branch list')),
4479 _('mark a branch as closed, hiding it from the branch list')),
4480 ] + walkopts + commitopts + commitopts2,
4480 ] + walkopts + commitopts + commitopts2,
4481 _('[OPTION]... [FILE]...')),
4481 _('[OPTION]... [FILE]...')),
4482 "copy|cp":
4482 "copy|cp":
4483 (copy,
4483 (copy,
4484 [('A', 'after', None, _('record a copy that has already occurred')),
4484 [('A', 'after', None, _('record a copy that has already occurred')),
4485 ('f', 'force', None,
4485 ('f', 'force', None,
4486 _('forcibly copy over an existing managed file')),
4486 _('forcibly copy over an existing managed file')),
4487 ] + walkopts + dryrunopts,
4487 ] + walkopts + dryrunopts,
4488 _('[OPTION]... [SOURCE]... DEST')),
4488 _('[OPTION]... [SOURCE]... DEST')),
4489 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4489 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4490 "debugbuilddag":
4490 "debugbuilddag":
4491 (debugbuilddag,
4491 (debugbuilddag,
4492 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4492 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4493 ('a', 'appended-file', None, _('add single file all revs append to')),
4493 ('a', 'appended-file', None, _('add single file all revs append to')),
4494 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4494 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4495 ('n', 'new-file', None, _('add new file at each rev')),
4495 ('n', 'new-file', None, _('add new file at each rev')),
4496 ],
4496 ],
4497 _('[OPTION]... TEXT')),
4497 _('[OPTION]... TEXT')),
4498 "debugbundle":
4498 "debugbundle":
4499 (debugbundle,
4499 (debugbundle,
4500 [('a', 'all', None, _('show all details')),
4500 [('a', 'all', None, _('show all details')),
4501 ],
4501 ],
4502 _('FILE')),
4502 _('FILE')),
4503 "debugcheckstate": (debugcheckstate, [], ''),
4503 "debugcheckstate": (debugcheckstate, [], ''),
4504 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4504 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4505 "debugcomplete":
4505 "debugcomplete":
4506 (debugcomplete,
4506 (debugcomplete,
4507 [('o', 'options', None, _('show the command options'))],
4507 [('o', 'options', None, _('show the command options'))],
4508 _('[-o] CMD')),
4508 _('[-o] CMD')),
4509 "debugdag":
4509 "debugdag":
4510 (debugdag,
4510 (debugdag,
4511 [('t', 'tags', None, _('use tags as labels')),
4511 [('t', 'tags', None, _('use tags as labels')),
4512 ('b', 'branches', None, _('annotate with branch names')),
4512 ('b', 'branches', None, _('annotate with branch names')),
4513 ('', 'dots', None, _('use dots for runs')),
4513 ('', 'dots', None, _('use dots for runs')),
4514 ('s', 'spaces', None, _('separate elements by spaces')),
4514 ('s', 'spaces', None, _('separate elements by spaces')),
4515 ],
4515 ],
4516 _('[OPTION]... [FILE [REV]...]')),
4516 _('[OPTION]... [FILE [REV]...]')),
4517 "debugdate":
4517 "debugdate":
4518 (debugdate,
4518 (debugdate,
4519 [('e', 'extended', None, _('try extended date formats'))],
4519 [('e', 'extended', None, _('try extended date formats'))],
4520 _('[-e] DATE [RANGE]')),
4520 _('[-e] DATE [RANGE]')),
4521 "debugdata": (debugdata, [], _('FILE REV')),
4521 "debugdata": (debugdata, [], _('FILE REV')),
4522 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4522 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4523 "debuggetbundle":
4523 "debuggetbundle":
4524 (debuggetbundle,
4524 (debuggetbundle,
4525 [('H', 'head', [], _('id of head node'), _('ID')),
4525 [('H', 'head', [], _('id of head node'), _('ID')),
4526 ('C', 'common', [], _('id of common node'), _('ID')),
4526 ('C', 'common', [], _('id of common node'), _('ID')),
4527 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4527 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4528 ],
4528 ],
4529 _('REPO FILE [-H|-C ID]...')),
4529 _('REPO FILE [-H|-C ID]...')),
4530 "debugignore": (debugignore, [], ''),
4530 "debugignore": (debugignore, [], ''),
4531 "debugindex": (debugindex,
4531 "debugindex": (debugindex,
4532 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4532 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4533 _('FILE')),
4533 _('FILE')),
4534 "debugindexdot": (debugindexdot, [], _('FILE')),
4534 "debugindexdot": (debugindexdot, [], _('FILE')),
4535 "debuginstall": (debuginstall, [], ''),
4535 "debuginstall": (debuginstall, [], ''),
4536 "debugknown": (debugknown, [], _('REPO ID...')),
4536 "debugknown": (debugknown, [], _('REPO ID...')),
4537 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4537 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4538 "debugrebuildstate":
4538 "debugrebuildstate":
4539 (debugrebuildstate,
4539 (debugrebuildstate,
4540 [('r', 'rev', '',
4540 [('r', 'rev', '',
4541 _('revision to rebuild to'), _('REV'))],
4541 _('revision to rebuild to'), _('REV'))],
4542 _('[-r REV] [REV]')),
4542 _('[-r REV] [REV]')),
4543 "debugrename":
4543 "debugrename":
4544 (debugrename,
4544 (debugrename,
4545 [('r', 'rev', '',
4545 [('r', 'rev', '',
4546 _('revision to debug'), _('REV'))],
4546 _('revision to debug'), _('REV'))],
4547 _('[-r REV] FILE')),
4547 _('[-r REV] FILE')),
4548 "debugrevspec":
4548 "debugrevspec":
4549 (debugrevspec, [], ('REVSPEC')),
4549 (debugrevspec, [], ('REVSPEC')),
4550 "debugsetparents":
4550 "debugsetparents":
4551 (debugsetparents, [], _('REV1 [REV2]')),
4551 (debugsetparents, [], _('REV1 [REV2]')),
4552 "debugstate":
4552 "debugstate":
4553 (debugstate,
4553 (debugstate,
4554 [('', 'nodates', None, _('do not display the saved mtime'))],
4554 [('', 'nodates', None, _('do not display the saved mtime'))],
4555 _('[OPTION]...')),
4555 _('[OPTION]...')),
4556 "debugsub":
4556 "debugsub":
4557 (debugsub,
4557 (debugsub,
4558 [('r', 'rev', '',
4558 [('r', 'rev', '',
4559 _('revision to check'), _('REV'))],
4559 _('revision to check'), _('REV'))],
4560 _('[-r REV] [REV]')),
4560 _('[-r REV] [REV]')),
4561 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4561 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4562 "debugwireargs":
4562 "debugwireargs":
4563 (debugwireargs,
4563 (debugwireargs,
4564 [('', 'three', '', 'three'),
4564 [('', 'three', '', 'three'),
4565 ('', 'four', '', 'four'),
4565 ('', 'four', '', 'four'),
4566 ] + remoteopts,
4566 ] + remoteopts,
4567 _('REPO [OPTIONS]... [ONE [TWO]]')),
4567 _('REPO [OPTIONS]... [ONE [TWO]]')),
4568 "^diff":
4568 "^diff":
4569 (diff,
4569 (diff,
4570 [('r', 'rev', [],
4570 [('r', 'rev', [],
4571 _('revision'), _('REV')),
4571 _('revision'), _('REV')),
4572 ('c', 'change', '',
4572 ('c', 'change', '',
4573 _('change made by revision'), _('REV'))
4573 _('change made by revision'), _('REV'))
4574 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4574 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4575 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4575 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4576 "^export":
4576 "^export":
4577 (export,
4577 (export,
4578 [('o', 'output', '',
4578 [('o', 'output', '',
4579 _('print output to file with formatted name'), _('FORMAT')),
4579 _('print output to file with formatted name'), _('FORMAT')),
4580 ('', 'switch-parent', None, _('diff against the second parent')),
4580 ('', 'switch-parent', None, _('diff against the second parent')),
4581 ('r', 'rev', [],
4581 ('r', 'rev', [],
4582 _('revisions to export'), _('REV')),
4582 _('revisions to export'), _('REV')),
4583 ] + diffopts,
4583 ] + diffopts,
4584 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4584 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4585 "^forget":
4585 "^forget":
4586 (forget,
4586 (forget,
4587 [] + walkopts,
4587 [] + walkopts,
4588 _('[OPTION]... FILE...')),
4588 _('[OPTION]... FILE...')),
4589 "grep":
4589 "grep":
4590 (grep,
4590 (grep,
4591 [('0', 'print0', None, _('end fields with NUL')),
4591 [('0', 'print0', None, _('end fields with NUL')),
4592 ('', 'all', None, _('print all revisions that match')),
4592 ('', 'all', None, _('print all revisions that match')),
4593 ('f', 'follow', None,
4593 ('f', 'follow', None,
4594 _('follow changeset history,'
4594 _('follow changeset history,'
4595 ' or file history across copies and renames')),
4595 ' or file history across copies and renames')),
4596 ('i', 'ignore-case', None, _('ignore case when matching')),
4596 ('i', 'ignore-case', None, _('ignore case when matching')),
4597 ('l', 'files-with-matches', None,
4597 ('l', 'files-with-matches', None,
4598 _('print only filenames and revisions that match')),
4598 _('print only filenames and revisions that match')),
4599 ('n', 'line-number', None, _('print matching line numbers')),
4599 ('n', 'line-number', None, _('print matching line numbers')),
4600 ('r', 'rev', [],
4600 ('r', 'rev', [],
4601 _('only search files changed within revision range'), _('REV')),
4601 _('only search files changed within revision range'), _('REV')),
4602 ('u', 'user', None, _('list the author (long with -v)')),
4602 ('u', 'user', None, _('list the author (long with -v)')),
4603 ('d', 'date', None, _('list the date (short with -q)')),
4603 ('d', 'date', None, _('list the date (short with -q)')),
4604 ] + walkopts,
4604 ] + walkopts,
4605 _('[OPTION]... PATTERN [FILE]...')),
4605 _('[OPTION]... PATTERN [FILE]...')),
4606 "heads":
4606 "heads":
4607 (heads,
4607 (heads,
4608 [('r', 'rev', '',
4608 [('r', 'rev', '',
4609 _('show only heads which are descendants of STARTREV'),
4609 _('show only heads which are descendants of STARTREV'),
4610 _('STARTREV')),
4610 _('STARTREV')),
4611 ('t', 'topo', False, _('show topological heads only')),
4611 ('t', 'topo', False, _('show topological heads only')),
4612 ('a', 'active', False,
4612 ('a', 'active', False,
4613 _('show active branchheads only (DEPRECATED)')),
4613 _('show active branchheads only (DEPRECATED)')),
4614 ('c', 'closed', False,
4614 ('c', 'closed', False,
4615 _('show normal and closed branch heads')),
4615 _('show normal and closed branch heads')),
4616 ] + templateopts,
4616 ] + templateopts,
4617 _('[-ac] [-r STARTREV] [REV]...')),
4617 _('[-ac] [-r STARTREV] [REV]...')),
4618 "help": (help_, [], _('[TOPIC]')),
4618 "help": (help_, [], _('[TOPIC]')),
4619 "identify|id":
4619 "identify|id":
4620 (identify,
4620 (identify,
4621 [('r', 'rev', '',
4621 [('r', 'rev', '',
4622 _('identify the specified revision'), _('REV')),
4622 _('identify the specified revision'), _('REV')),
4623 ('n', 'num', None, _('show local revision number')),
4623 ('n', 'num', None, _('show local revision number')),
4624 ('i', 'id', None, _('show global revision id')),
4624 ('i', 'id', None, _('show global revision id')),
4625 ('b', 'branch', None, _('show branch')),
4625 ('b', 'branch', None, _('show branch')),
4626 ('t', 'tags', None, _('show tags')),
4626 ('t', 'tags', None, _('show tags')),
4627 ('B', 'bookmarks', None, _('show bookmarks'))],
4627 ('B', 'bookmarks', None, _('show bookmarks'))],
4628 _('[-nibtB] [-r REV] [SOURCE]')),
4628 _('[-nibtB] [-r REV] [SOURCE]')),
4629 "import|patch":
4629 "import|patch":
4630 (import_,
4630 (import_,
4631 [('p', 'strip', 1,
4631 [('p', 'strip', 1,
4632 _('directory strip option for patch. This has the same '
4632 _('directory strip option for patch. This has the same '
4633 'meaning as the corresponding patch option'),
4633 'meaning as the corresponding patch option'),
4634 _('NUM')),
4634 _('NUM')),
4635 ('b', 'base', '',
4635 ('b', 'base', '',
4636 _('base path'), _('PATH')),
4636 _('base path'), _('PATH')),
4637 ('f', 'force', None,
4637 ('f', 'force', None,
4638 _('skip check for outstanding uncommitted changes')),
4638 _('skip check for outstanding uncommitted changes')),
4639 ('', 'no-commit', None,
4639 ('', 'no-commit', None,
4640 _("don't commit, just update the working directory")),
4640 _("don't commit, just update the working directory")),
4641 ('', 'exact', None,
4641 ('', 'exact', None,
4642 _('apply patch to the nodes from which it was generated')),
4642 _('apply patch to the nodes from which it was generated')),
4643 ('', 'import-branch', None,
4643 ('', 'import-branch', None,
4644 _('use any branch information in patch (implied by --exact)'))] +
4644 _('use any branch information in patch (implied by --exact)'))] +
4645 commitopts + commitopts2 + similarityopts,
4645 commitopts + commitopts2 + similarityopts,
4646 _('[OPTION]... PATCH...')),
4646 _('[OPTION]... PATCH...')),
4647 "incoming|in":
4647 "incoming|in":
4648 (incoming,
4648 (incoming,
4649 [('f', 'force', None,
4649 [('f', 'force', None,
4650 _('run even if remote repository is unrelated')),
4650 _('run even if remote repository is unrelated')),
4651 ('n', 'newest-first', None, _('show newest record first')),
4651 ('n', 'newest-first', None, _('show newest record first')),
4652 ('', 'bundle', '',
4652 ('', 'bundle', '',
4653 _('file to store the bundles into'), _('FILE')),
4653 _('file to store the bundles into'), _('FILE')),
4654 ('r', 'rev', [],
4654 ('r', 'rev', [],
4655 _('a remote changeset intended to be added'), _('REV')),
4655 _('a remote changeset intended to be added'), _('REV')),
4656 ('B', 'bookmarks', False, _("compare bookmarks")),
4656 ('B', 'bookmarks', False, _("compare bookmarks")),
4657 ('b', 'branch', [],
4657 ('b', 'branch', [],
4658 _('a specific branch you would like to pull'), _('BRANCH')),
4658 _('a specific branch you would like to pull'), _('BRANCH')),
4659 ] + logopts + remoteopts + subrepoopts,
4659 ] + logopts + remoteopts + subrepoopts,
4660 _('[-p] [-n] [-M] [-f] [-r REV]...'
4660 _('[-p] [-n] [-M] [-f] [-r REV]...'
4661 ' [--bundle FILENAME] [SOURCE]')),
4661 ' [--bundle FILENAME] [SOURCE]')),
4662 "^init":
4662 "^init":
4663 (init,
4663 (init,
4664 remoteopts,
4664 remoteopts,
4665 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4665 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4666 "locate":
4666 "locate":
4667 (locate,
4667 (locate,
4668 [('r', 'rev', '',
4668 [('r', 'rev', '',
4669 _('search the repository as it is in REV'), _('REV')),
4669 _('search the repository as it is in REV'), _('REV')),
4670 ('0', 'print0', None,
4670 ('0', 'print0', None,
4671 _('end filenames with NUL, for use with xargs')),
4671 _('end filenames with NUL, for use with xargs')),
4672 ('f', 'fullpath', None,
4672 ('f', 'fullpath', None,
4673 _('print complete paths from the filesystem root')),
4673 _('print complete paths from the filesystem root')),
4674 ] + walkopts,
4674 ] + walkopts,
4675 _('[OPTION]... [PATTERN]...')),
4675 _('[OPTION]... [PATTERN]...')),
4676 "^log|history":
4676 "^log|history":
4677 (log,
4677 (log,
4678 [('f', 'follow', None,
4678 [('f', 'follow', None,
4679 _('follow changeset history,'
4679 _('follow changeset history,'
4680 ' or file history across copies and renames')),
4680 ' or file history across copies and renames')),
4681 ('', 'follow-first', None,
4681 ('', 'follow-first', None,
4682 _('only follow the first parent of merge changesets')),
4682 _('only follow the first parent of merge changesets')),
4683 ('d', 'date', '',
4683 ('d', 'date', '',
4684 _('show revisions matching date spec'), _('DATE')),
4684 _('show revisions matching date spec'), _('DATE')),
4685 ('C', 'copies', None, _('show copied files')),
4685 ('C', 'copies', None, _('show copied files')),
4686 ('k', 'keyword', [],
4686 ('k', 'keyword', [],
4687 _('do case-insensitive search for a given text'), _('TEXT')),
4687 _('do case-insensitive search for a given text'), _('TEXT')),
4688 ('r', 'rev', [],
4688 ('r', 'rev', [],
4689 _('show the specified revision or range'), _('REV')),
4689 _('show the specified revision or range'), _('REV')),
4690 ('', 'removed', None, _('include revisions where files were removed')),
4690 ('', 'removed', None, _('include revisions where files were removed')),
4691 ('m', 'only-merges', None, _('show only merges')),
4691 ('m', 'only-merges', None, _('show only merges')),
4692 ('u', 'user', [],
4692 ('u', 'user', [],
4693 _('revisions committed by user'), _('USER')),
4693 _('revisions committed by user'), _('USER')),
4694 ('', 'only-branch', [],
4694 ('', 'only-branch', [],
4695 _('show only changesets within the given named branch (DEPRECATED)'),
4695 _('show only changesets within the given named branch (DEPRECATED)'),
4696 _('BRANCH')),
4696 _('BRANCH')),
4697 ('b', 'branch', [],
4697 ('b', 'branch', [],
4698 _('show changesets within the given named branch'), _('BRANCH')),
4698 _('show changesets within the given named branch'), _('BRANCH')),
4699 ('P', 'prune', [],
4699 ('P', 'prune', [],
4700 _('do not display revision or any of its ancestors'), _('REV')),
4700 _('do not display revision or any of its ancestors'), _('REV')),
4701 ] + logopts + walkopts,
4701 ] + logopts + walkopts,
4702 _('[OPTION]... [FILE]')),
4702 _('[OPTION]... [FILE]')),
4703 "manifest":
4703 "manifest":
4704 (manifest,
4704 (manifest,
4705 [('r', 'rev', '',
4705 [('r', 'rev', '',
4706 _('revision to display'), _('REV'))],
4706 _('revision to display'), _('REV'))],
4707 _('[-r REV]')),
4707 _('[-r REV]')),
4708 "^merge":
4708 "^merge":
4709 (merge,
4709 (merge,
4710 [('f', 'force', None, _('force a merge with outstanding changes')),
4710 [('f', 'force', None, _('force a merge with outstanding changes')),
4711 ('t', 'tool', '', _('specify merge tool')),
4711 ('t', 'tool', '', _('specify merge tool')),
4712 ('r', 'rev', '',
4712 ('r', 'rev', '',
4713 _('revision to merge'), _('REV')),
4713 _('revision to merge'), _('REV')),
4714 ('P', 'preview', None,
4714 ('P', 'preview', None,
4715 _('review revisions to merge (no merge is performed)'))],
4715 _('review revisions to merge (no merge is performed)'))],
4716 _('[-P] [-f] [[-r] REV]')),
4716 _('[-P] [-f] [[-r] REV]')),
4717 "outgoing|out":
4717 "outgoing|out":
4718 (outgoing,
4718 (outgoing,
4719 [('f', 'force', None,
4719 [('f', 'force', None,
4720 _('run even when the destination is unrelated')),
4720 _('run even when the destination is unrelated')),
4721 ('r', 'rev', [],
4721 ('r', 'rev', [],
4722 _('a changeset intended to be included in the destination'),
4722 _('a changeset intended to be included in the destination'),
4723 _('REV')),
4723 _('REV')),
4724 ('n', 'newest-first', None, _('show newest record first')),
4724 ('n', 'newest-first', None, _('show newest record first')),
4725 ('B', 'bookmarks', False, _("compare bookmarks")),
4725 ('B', 'bookmarks', False, _("compare bookmarks")),
4726 ('b', 'branch', [],
4726 ('b', 'branch', [],
4727 _('a specific branch you would like to push'), _('BRANCH')),
4727 _('a specific branch you would like to push'), _('BRANCH')),
4728 ] + logopts + remoteopts + subrepoopts,
4728 ] + logopts + remoteopts + subrepoopts,
4729 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4729 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4730 "parents":
4730 "parents":
4731 (parents,
4731 (parents,
4732 [('r', 'rev', '',
4732 [('r', 'rev', '',
4733 _('show parents of the specified revision'), _('REV')),
4733 _('show parents of the specified revision'), _('REV')),
4734 ] + templateopts,
4734 ] + templateopts,
4735 _('[-r REV] [FILE]')),
4735 _('[-r REV] [FILE]')),
4736 "paths": (paths, [], _('[NAME]')),
4736 "paths": (paths, [], _('[NAME]')),
4737 "^pull":
4737 "^pull":
4738 (pull,
4738 (pull,
4739 [('u', 'update', None,
4739 [('u', 'update', None,
4740 _('update to new branch head if changesets were pulled')),
4740 _('update to new branch head if changesets were pulled')),
4741 ('f', 'force', None,
4741 ('f', 'force', None,
4742 _('run even when remote repository is unrelated')),
4742 _('run even when remote repository is unrelated')),
4743 ('r', 'rev', [],
4743 ('r', 'rev', [],
4744 _('a remote changeset intended to be added'), _('REV')),
4744 _('a remote changeset intended to be added'), _('REV')),
4745 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4745 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4746 ('b', 'branch', [],
4746 ('b', 'branch', [],
4747 _('a specific branch you would like to pull'), _('BRANCH')),
4747 _('a specific branch you would like to pull'), _('BRANCH')),
4748 ] + remoteopts,
4748 ] + remoteopts,
4749 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4749 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4750 "^push":
4750 "^push":
4751 (push,
4751 (push,
4752 [('f', 'force', None, _('force push')),
4752 [('f', 'force', None, _('force push')),
4753 ('r', 'rev', [],
4753 ('r', 'rev', [],
4754 _('a changeset intended to be included in the destination'),
4754 _('a changeset intended to be included in the destination'),
4755 _('REV')),
4755 _('REV')),
4756 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4756 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4757 ('b', 'branch', [],
4757 ('b', 'branch', [],
4758 _('a specific branch you would like to push'), _('BRANCH')),
4758 _('a specific branch you would like to push'), _('BRANCH')),
4759 ('', 'new-branch', False, _('allow pushing a new branch')),
4759 ('', 'new-branch', False, _('allow pushing a new branch')),
4760 ] + remoteopts,
4760 ] + remoteopts,
4761 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4761 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4762 "recover": (recover, []),
4762 "recover": (recover, []),
4763 "^remove|rm":
4763 "^remove|rm":
4764 (remove,
4764 (remove,
4765 [('A', 'after', None, _('record delete for missing files')),
4765 [('A', 'after', None, _('record delete for missing files')),
4766 ('f', 'force', None,
4766 ('f', 'force', None,
4767 _('remove (and delete) file even if added or modified')),
4767 _('remove (and delete) file even if added or modified')),
4768 ] + walkopts,
4768 ] + walkopts,
4769 _('[OPTION]... FILE...')),
4769 _('[OPTION]... FILE...')),
4770 "rename|move|mv":
4770 "rename|move|mv":
4771 (rename,
4771 (rename,
4772 [('A', 'after', None, _('record a rename that has already occurred')),
4772 [('A', 'after', None, _('record a rename that has already occurred')),
4773 ('f', 'force', None,
4773 ('f', 'force', None,
4774 _('forcibly copy over an existing managed file')),
4774 _('forcibly copy over an existing managed file')),
4775 ] + walkopts + dryrunopts,
4775 ] + walkopts + dryrunopts,
4776 _('[OPTION]... SOURCE... DEST')),
4776 _('[OPTION]... SOURCE... DEST')),
4777 "resolve":
4777 "resolve":
4778 (resolve,
4778 (resolve,
4779 [('a', 'all', None, _('select all unresolved files')),
4779 [('a', 'all', None, _('select all unresolved files')),
4780 ('l', 'list', None, _('list state of files needing merge')),
4780 ('l', 'list', None, _('list state of files needing merge')),
4781 ('m', 'mark', None, _('mark files as resolved')),
4781 ('m', 'mark', None, _('mark files as resolved')),
4782 ('u', 'unmark', None, _('mark files as unresolved')),
4782 ('u', 'unmark', None, _('mark files as unresolved')),
4783 ('t', 'tool', '', _('specify merge tool')),
4783 ('t', 'tool', '', _('specify merge tool')),
4784 ('n', 'no-status', None, _('hide status prefix'))]
4784 ('n', 'no-status', None, _('hide status prefix'))]
4785 + walkopts,
4785 + walkopts,
4786 _('[OPTION]... [FILE]...')),
4786 _('[OPTION]... [FILE]...')),
4787 "revert":
4787 "revert":
4788 (revert,
4788 (revert,
4789 [('a', 'all', None, _('revert all changes when no arguments given')),
4789 [('a', 'all', None, _('revert all changes when no arguments given')),
4790 ('d', 'date', '',
4790 ('d', 'date', '',
4791 _('tipmost revision matching date'), _('DATE')),
4791 _('tipmost revision matching date'), _('DATE')),
4792 ('r', 'rev', '',
4792 ('r', 'rev', '',
4793 _('revert to the specified revision'), _('REV')),
4793 _('revert to the specified revision'), _('REV')),
4794 ('', 'no-backup', None, _('do not save backup copies of files')),
4794 ('', 'no-backup', None, _('do not save backup copies of files')),
4795 ] + walkopts + dryrunopts,
4795 ] + walkopts + dryrunopts,
4796 _('[OPTION]... [-r REV] [NAME]...')),
4796 _('[OPTION]... [-r REV] [NAME]...')),
4797 "rollback": (rollback, dryrunopts),
4797 "rollback": (rollback, dryrunopts),
4798 "root": (root, []),
4798 "root": (root, []),
4799 "^serve":
4799 "^serve":
4800 (serve,
4800 (serve,
4801 [('A', 'accesslog', '',
4801 [('A', 'accesslog', '',
4802 _('name of access log file to write to'), _('FILE')),
4802 _('name of access log file to write to'), _('FILE')),
4803 ('d', 'daemon', None, _('run server in background')),
4803 ('d', 'daemon', None, _('run server in background')),
4804 ('', 'daemon-pipefds', '',
4804 ('', 'daemon-pipefds', '',
4805 _('used internally by daemon mode'), _('NUM')),
4805 _('used internally by daemon mode'), _('NUM')),
4806 ('E', 'errorlog', '',
4806 ('E', 'errorlog', '',
4807 _('name of error log file to write to'), _('FILE')),
4807 _('name of error log file to write to'), _('FILE')),
4808 # use string type, then we can check if something was passed
4808 # use string type, then we can check if something was passed
4809 ('p', 'port', '',
4809 ('p', 'port', '',
4810 _('port to listen on (default: 8000)'), _('PORT')),
4810 _('port to listen on (default: 8000)'), _('PORT')),
4811 ('a', 'address', '',
4811 ('a', 'address', '',
4812 _('address to listen on (default: all interfaces)'), _('ADDR')),
4812 _('address to listen on (default: all interfaces)'), _('ADDR')),
4813 ('', 'prefix', '',
4813 ('', 'prefix', '',
4814 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4814 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4815 ('n', 'name', '',
4815 ('n', 'name', '',
4816 _('name to show in web pages (default: working directory)'),
4816 _('name to show in web pages (default: working directory)'),
4817 _('NAME')),
4817 _('NAME')),
4818 ('', 'web-conf', '',
4818 ('', 'web-conf', '',
4819 _('name of the hgweb config file (see "hg help hgweb")'),
4819 _('name of the hgweb config file (see "hg help hgweb")'),
4820 _('FILE')),
4820 _('FILE')),
4821 ('', 'webdir-conf', '',
4821 ('', 'webdir-conf', '',
4822 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4822 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4823 ('', 'pid-file', '',
4823 ('', 'pid-file', '',
4824 _('name of file to write process ID to'), _('FILE')),
4824 _('name of file to write process ID to'), _('FILE')),
4825 ('', 'stdio', None, _('for remote clients')),
4825 ('', 'stdio', None, _('for remote clients')),
4826 ('t', 'templates', '',
4826 ('t', 'templates', '',
4827 _('web templates to use'), _('TEMPLATE')),
4827 _('web templates to use'), _('TEMPLATE')),
4828 ('', 'style', '',
4828 ('', 'style', '',
4829 _('template style to use'), _('STYLE')),
4829 _('template style to use'), _('STYLE')),
4830 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4830 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4831 ('', 'certificate', '',
4831 ('', 'certificate', '',
4832 _('SSL certificate file'), _('FILE'))],
4832 _('SSL certificate file'), _('FILE'))],
4833 _('[OPTION]...')),
4833 _('[OPTION]...')),
4834 "showconfig|debugconfig":
4834 "showconfig|debugconfig":
4835 (showconfig,
4835 (showconfig,
4836 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4836 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4837 _('[-u] [NAME]...')),
4837 _('[-u] [NAME]...')),
4838 "^summary|sum":
4838 "^summary|sum":
4839 (summary,
4839 (summary,
4840 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4840 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4841 "^status|st":
4841 "^status|st":
4842 (status,
4842 (status,
4843 [('A', 'all', None, _('show status of all files')),
4843 [('A', 'all', None, _('show status of all files')),
4844 ('m', 'modified', None, _('show only modified files')),
4844 ('m', 'modified', None, _('show only modified files')),
4845 ('a', 'added', None, _('show only added files')),
4845 ('a', 'added', None, _('show only added files')),
4846 ('r', 'removed', None, _('show only removed files')),
4846 ('r', 'removed', None, _('show only removed files')),
4847 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4847 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4848 ('c', 'clean', None, _('show only files without changes')),
4848 ('c', 'clean', None, _('show only files without changes')),
4849 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4849 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4850 ('i', 'ignored', None, _('show only ignored files')),
4850 ('i', 'ignored', None, _('show only ignored files')),
4851 ('n', 'no-status', None, _('hide status prefix')),
4851 ('n', 'no-status', None, _('hide status prefix')),
4852 ('C', 'copies', None, _('show source of copied files')),
4852 ('C', 'copies', None, _('show source of copied files')),
4853 ('0', 'print0', None,
4853 ('0', 'print0', None,
4854 _('end filenames with NUL, for use with xargs')),
4854 _('end filenames with NUL, for use with xargs')),
4855 ('', 'rev', [],
4855 ('', 'rev', [],
4856 _('show difference from revision'), _('REV')),
4856 _('show difference from revision'), _('REV')),
4857 ('', 'change', '',
4857 ('', 'change', '',
4858 _('list the changed files of a revision'), _('REV')),
4858 _('list the changed files of a revision'), _('REV')),
4859 ] + walkopts + subrepoopts,
4859 ] + walkopts + subrepoopts,
4860 _('[OPTION]... [FILE]...')),
4860 _('[OPTION]... [FILE]...')),
4861 "tag":
4861 "tag":
4862 (tag,
4862 (tag,
4863 [('f', 'force', None, _('force tag')),
4863 [('f', 'force', None, _('force tag')),
4864 ('l', 'local', None, _('make the tag local')),
4864 ('l', 'local', None, _('make the tag local')),
4865 ('r', 'rev', '',
4865 ('r', 'rev', '',
4866 _('revision to tag'), _('REV')),
4866 _('revision to tag'), _('REV')),
4867 ('', 'remove', None, _('remove a tag')),
4867 ('', 'remove', None, _('remove a tag')),
4868 # -l/--local is already there, commitopts cannot be used
4868 # -l/--local is already there, commitopts cannot be used
4869 ('e', 'edit', None, _('edit commit message')),
4869 ('e', 'edit', None, _('edit commit message')),
4870 ('m', 'message', '',
4870 ('m', 'message', '',
4871 _('use <text> as commit message'), _('TEXT')),
4871 _('use <text> as commit message'), _('TEXT')),
4872 ] + commitopts2,
4872 ] + commitopts2,
4873 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4873 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4874 "tags": (tags, [], ''),
4874 "tags": (tags, [], ''),
4875 "tip":
4875 "tip":
4876 (tip,
4876 (tip,
4877 [('p', 'patch', None, _('show patch')),
4877 [('p', 'patch', None, _('show patch')),
4878 ('g', 'git', None, _('use git extended diff format')),
4878 ('g', 'git', None, _('use git extended diff format')),
4879 ] + templateopts,
4879 ] + templateopts,
4880 _('[-p] [-g]')),
4880 _('[-p] [-g]')),
4881 "unbundle":
4881 "unbundle":
4882 (unbundle,
4882 (unbundle,
4883 [('u', 'update', None,
4883 [('u', 'update', None,
4884 _('update to new branch head if changesets were unbundled'))],
4884 _('update to new branch head if changesets were unbundled'))],
4885 _('[-u] FILE...')),
4885 _('[-u] FILE...')),
4886 "^update|up|checkout|co":
4886 "^update|up|checkout|co":
4887 (update,
4887 (update,
4888 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4888 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4889 ('c', 'check', None,
4889 ('c', 'check', None,
4890 _('update across branches if no uncommitted changes')),
4890 _('update across branches if no uncommitted changes')),
4891 ('d', 'date', '',
4891 ('d', 'date', '',
4892 _('tipmost revision matching date'), _('DATE')),
4892 _('tipmost revision matching date'), _('DATE')),
4893 ('r', 'rev', '',
4893 ('r', 'rev', '',
4894 _('revision'), _('REV'))],
4894 _('revision'), _('REV'))],
4895 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4895 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4896 "verify": (verify, []),
4896 "verify": (verify, []),
4897 "version": (version_, []),
4897 "version": (version_, []),
4898 }
4898 }
4899
4899
4900 norepo = ("clone init version help debugcommands debugcomplete"
4900 norepo = ("clone init version help debugcommands debugcomplete"
4901 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4901 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4902 " debugknown debuggetbundle debugbundle")
4902 " debugknown debuggetbundle debugbundle")
4903 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4903 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4904 " debugdata debugindex debugindexdot")
4904 " debugdata debugindex debugindexdot")
@@ -1,158 +1,158 b''
1 # repair.py - functions for repository repair for mercurial
1 # repair.py - functions for repository repair for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 # Copyright 2007 Matt Mackall
4 # Copyright 2007 Matt Mackall
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import changegroup, bookmarks
9 import changegroup, bookmarks
10 from node import nullrev, short
10 from node import nullrev, short
11 from i18n import _
11 from i18n import _
12 import os
12 import os
13
13
14 def _bundle(repo, bases, heads, node, suffix, compress=True):
14 def _bundle(repo, bases, heads, node, suffix, compress=True):
15 """create a bundle with the specified revisions as a backup"""
15 """create a bundle with the specified revisions as a backup"""
16 cg = repo.changegroupsubset(bases, heads, 'strip')
16 cg = repo.changegroupsubset(bases, heads, 'strip')
17 backupdir = repo.join("strip-backup")
17 backupdir = repo.join("strip-backup")
18 if not os.path.isdir(backupdir):
18 if not os.path.isdir(backupdir):
19 os.mkdir(backupdir)
19 os.mkdir(backupdir)
20 name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
20 name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
21 if compress:
21 if compress:
22 bundletype = "HG10BZ"
22 bundletype = "HG10BZ"
23 else:
23 else:
24 bundletype = "HG10UN"
24 bundletype = "HG10UN"
25 return changegroup.writebundle(cg, name, bundletype)
25 return changegroup.writebundle(cg, name, bundletype)
26
26
27 def _collectfiles(repo, striprev):
27 def _collectfiles(repo, striprev):
28 """find out the filelogs affected by the strip"""
28 """find out the filelogs affected by the strip"""
29 files = set()
29 files = set()
30
30
31 for x in xrange(striprev, len(repo)):
31 for x in xrange(striprev, len(repo)):
32 files.update(repo[x].files())
32 files.update(repo[x].files())
33
33
34 return sorted(files)
34 return sorted(files)
35
35
36 def _collectbrokencsets(repo, files, striprev):
36 def _collectbrokencsets(repo, files, striprev):
37 """return the changesets which will be broken by the truncation"""
37 """return the changesets which will be broken by the truncation"""
38 s = set()
38 s = set()
39 def collectone(revlog):
39 def collectone(revlog):
40 links = (revlog.linkrev(i) for i in revlog)
40 links = (revlog.linkrev(i) for i in revlog)
41 # find the truncation point of the revlog
41 # find the truncation point of the revlog
42 for lrev in links:
42 for lrev in links:
43 if lrev >= striprev:
43 if lrev >= striprev:
44 break
44 break
45 # see if any revision after this point has a linkrev
45 # see if any revision after this point has a linkrev
46 # less than striprev (those will be broken by strip)
46 # less than striprev (those will be broken by strip)
47 for lrev in links:
47 for lrev in links:
48 if lrev < striprev:
48 if lrev < striprev:
49 s.add(lrev)
49 s.add(lrev)
50
50
51 collectone(repo.manifest)
51 collectone(repo.manifest)
52 for fname in files:
52 for fname in files:
53 collectone(repo.file(fname))
53 collectone(repo.file(fname))
54
54
55 return s
55 return s
56
56
57 def strip(ui, repo, node, backup="all"):
57 def strip(ui, repo, node, backup="all"):
58 cl = repo.changelog
58 cl = repo.changelog
59 # TODO delete the undo files, and handle undo of merge sets
59 # TODO delete the undo files, and handle undo of merge sets
60 striprev = cl.rev(node)
60 striprev = cl.rev(node)
61
61
62 keeppartialbundle = backup == 'strip'
62 keeppartialbundle = backup == 'strip'
63
63
64 # Some revisions with rev > striprev may not be descendants of striprev.
64 # Some revisions with rev > striprev may not be descendants of striprev.
65 # We have to find these revisions and put them in a bundle, so that
65 # We have to find these revisions and put them in a bundle, so that
66 # we can restore them after the truncations.
66 # we can restore them after the truncations.
67 # To create the bundle we use repo.changegroupsubset which requires
67 # To create the bundle we use repo.changegroupsubset which requires
68 # the list of heads and bases of the set of interesting revisions.
68 # the list of heads and bases of the set of interesting revisions.
69 # (head = revision in the set that has no descendant in the set;
69 # (head = revision in the set that has no descendant in the set;
70 # base = revision in the set that has no ancestor in the set)
70 # base = revision in the set that has no ancestor in the set)
71 tostrip = set(cl.descendants(striprev))
71 tostrip = set(cl.descendants(striprev))
72 tostrip.add(striprev)
72 tostrip.add(striprev)
73
73
74 files = _collectfiles(repo, striprev)
74 files = _collectfiles(repo, striprev)
75 saverevs = _collectbrokencsets(repo, files, striprev)
75 saverevs = _collectbrokencsets(repo, files, striprev)
76
76
77 # compute heads
77 # compute heads
78 saveheads = set(saverevs)
78 saveheads = set(saverevs)
79 for r in xrange(striprev + 1, len(cl)):
79 for r in xrange(striprev + 1, len(cl)):
80 if r not in tostrip:
80 if r not in tostrip:
81 saverevs.add(r)
81 saverevs.add(r)
82 saveheads.difference_update(cl.parentrevs(r))
82 saveheads.difference_update(cl.parentrevs(r))
83 saveheads.add(r)
83 saveheads.add(r)
84 saveheads = [cl.node(r) for r in saveheads]
84 saveheads = [cl.node(r) for r in saveheads]
85
85
86 # compute base nodes
86 # compute base nodes
87 if saverevs:
87 if saverevs:
88 descendants = set(cl.descendants(*saverevs))
88 descendants = set(cl.descendants(*saverevs))
89 saverevs.difference_update(descendants)
89 saverevs.difference_update(descendants)
90 savebases = [cl.node(r) for r in saverevs]
90 savebases = [cl.node(r) for r in saverevs]
91
91
92 bm = repo._bookmarks
92 bm = repo._bookmarks
93 updatebm = []
93 updatebm = []
94 for m in bm:
94 for m in bm:
95 rev = repo[bm[m]].rev()
95 rev = repo[bm[m]].rev()
96 if rev in tostrip:
96 if rev in tostrip:
97 updatebm.append(m)
97 updatebm.append(m)
98
98
99 # create a changegroup for all the branches we need to keep
99 # create a changegroup for all the branches we need to keep
100 backupfile = None
100 backupfile = None
101 if backup == "all":
101 if backup == "all":
102 backupfile = _bundle(repo, [node], cl.heads(), node, 'backup')
102 backupfile = _bundle(repo, [node], cl.heads(), node, 'backup')
103 repo.ui.status(_("saved backup bundle to %s\n") % backupfile)
103 repo.ui.status(_("saved backup bundle to %s\n") % backupfile)
104 if saveheads or savebases:
104 if saveheads or savebases:
105 # do not compress partial bundle if we remove it from disk later
105 # do not compress partial bundle if we remove it from disk later
106 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
106 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
107 compress=keeppartialbundle)
107 compress=keeppartialbundle)
108
108
109 mfst = repo.manifest
109 mfst = repo.manifest
110
110
111 tr = repo.transaction("strip")
111 tr = repo.transaction("strip")
112 offset = len(tr.entries)
112 offset = len(tr.entries)
113
113
114 try:
114 try:
115 tr.startgroup()
115 tr.startgroup()
116 cl.strip(striprev, tr)
116 cl.strip(striprev, tr)
117 mfst.strip(striprev, tr)
117 mfst.strip(striprev, tr)
118 for fn in files:
118 for fn in files:
119 repo.file(fn).strip(striprev, tr)
119 repo.file(fn).strip(striprev, tr)
120 tr.endgroup()
120 tr.endgroup()
121
121
122 try:
122 try:
123 for i in xrange(offset, len(tr.entries)):
123 for i in xrange(offset, len(tr.entries)):
124 file, troffset, ignore = tr.entries[i]
124 file, troffset, ignore = tr.entries[i]
125 repo.sopener(file, 'a').truncate(troffset)
125 repo.sopener(file, 'a').truncate(troffset)
126 tr.close()
126 tr.close()
127 except:
127 except:
128 tr.abort()
128 tr.abort()
129 raise
129 raise
130
130
131 if saveheads or savebases:
131 if saveheads or savebases:
132 ui.note(_("adding branch\n"))
132 ui.note(_("adding branch\n"))
133 f = open(chgrpfile, "rb")
133 f = open(chgrpfile, "rb")
134 gen = changegroup.readbundle(f, chgrpfile)
134 gen = changegroup.readbundle(f, chgrpfile)
135 if not repo.ui.verbose:
135 if not repo.ui.verbose:
136 # silence internal shuffling chatter
136 # silence internal shuffling chatter
137 repo.ui.pushbuffer()
137 repo.ui.pushbuffer()
138 repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
138 repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
139 if not repo.ui.verbose:
139 if not repo.ui.verbose:
140 repo.ui.popbuffer()
140 repo.ui.popbuffer()
141 f.close()
141 f.close()
142 if not keeppartialbundle:
142 if not keeppartialbundle:
143 os.unlink(chgrpfile)
143 os.unlink(chgrpfile)
144
144
145 for m in updatebm:
145 for m in updatebm:
146 bm[m] = repo['.'].node()
146 bm[m] = repo['.'].node()
147 bookmarks.write(repo)
147 bookmarks.write(repo)
148
148
149 except:
149 except:
150 if backupfile:
150 if backupfile:
151 ui.warn(_("strip failed, full bundle stored in '%s'\n")
151 ui.warn(_("strip failed, full bundle stored in '%s'\n")
152 % backupfile)
152 % backupfile)
153 elif saveheads:
153 elif saveheads:
154 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
154 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
155 % chgrpfile)
155 % chgrpfile)
156 raise
156 raise
157
157
158 repo.destroyed()
158 repo.destroyed()
General Comments 0
You need to be logged in to leave comments. Login now