##// END OF EJS Templates
debug: add debugwireargs to test argument passing over the wire...
Peter Arrenbrecht -
r13720:9c4e04fe default
parent child Browse files
Show More
@@ -0,0 +1,42 b''
1
2 Test wire protocol argument passing
3
4 Setup repo:
5
6 $ hg init repo
7
8 Local:
9
10 $ hg debugwireargs repo eins zwei
11 eins zwei None None
12
13 HTTP:
14
15 $ hg serve -R repo -p $HGPORT -d --pid-file=hg1.pid -E error.log -A access.log
16 $ cat hg1.pid >> $DAEMON_PIDS
17
18 $ hg debugwireargs http://localhost:$HGPORT/ eins zwei
19 eins zwei None None
20 $ cat access.log
21 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
22 * - - [*] "GET /?cmd=debugwireargs&one=eins&two=zwei HTTP/1.1" 200 - (glob)
23 * - - [*] "GET /?cmd=debugwireargs&one=eins&two=zwei HTTP/1.1" 200 - (glob)
24
25 SSH (try to exercise the ssh functionality with a dummy script):
26
27 $ cat <<EOF > dummyssh
28 > import sys
29 > import os
30 > os.chdir(os.path.dirname(sys.argv[0]))
31 > if sys.argv[1] != "user@dummy":
32 > sys.exit(-1)
33 > if not os.path.exists("dummyssh"):
34 > sys.exit(-1)
35 > os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
36 > r = os.system(sys.argv[2])
37 > sys.exit(bool(r))
38 > EOF
39
40 $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo eins zwei
41 eins zwei None None
42
@@ -1,4794 +1,4815 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, nullid, nullrev, short
8 from node import hex, 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 debugpushkey(ui, repopath, namespace, *keyinfo):
1221 def debugpushkey(ui, repopath, namespace, *keyinfo):
1222 '''access the pushkey key/value protocol
1222 '''access the pushkey key/value protocol
1223
1223
1224 With two args, list the keys in the given namespace.
1224 With two args, list the keys in the given namespace.
1225
1225
1226 With five args, set a key to new if it currently is set to old.
1226 With five args, set a key to new if it currently is set to old.
1227 Reports success or failure.
1227 Reports success or failure.
1228 '''
1228 '''
1229
1229
1230 target = hg.repository(ui, repopath)
1230 target = hg.repository(ui, repopath)
1231 if keyinfo:
1231 if keyinfo:
1232 key, old, new = keyinfo
1232 key, old, new = keyinfo
1233 r = target.pushkey(namespace, key, old, new)
1233 r = target.pushkey(namespace, key, old, new)
1234 ui.status(str(r) + '\n')
1234 ui.status(str(r) + '\n')
1235 return not r
1235 return not r
1236 else:
1236 else:
1237 for k, v in target.listkeys(namespace).iteritems():
1237 for k, v in target.listkeys(namespace).iteritems():
1238 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1238 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1239 v.encode('string-escape')))
1239 v.encode('string-escape')))
1240
1240
1241 def debugrevspec(ui, repo, expr):
1241 def debugrevspec(ui, repo, expr):
1242 '''parse and apply a revision specification'''
1242 '''parse and apply a revision specification'''
1243 if ui.verbose:
1243 if ui.verbose:
1244 tree = revset.parse(expr)[0]
1244 tree = revset.parse(expr)[0]
1245 ui.note(tree, "\n")
1245 ui.note(tree, "\n")
1246 func = revset.match(expr)
1246 func = revset.match(expr)
1247 for c in func(repo, range(len(repo))):
1247 for c in func(repo, range(len(repo))):
1248 ui.write("%s\n" % c)
1248 ui.write("%s\n" % c)
1249
1249
1250 def debugsetparents(ui, repo, rev1, rev2=None):
1250 def debugsetparents(ui, repo, rev1, rev2=None):
1251 """manually set the parents of the current working directory
1251 """manually set the parents of the current working directory
1252
1252
1253 This is useful for writing repository conversion tools, but should
1253 This is useful for writing repository conversion tools, but should
1254 be used with care.
1254 be used with care.
1255
1255
1256 Returns 0 on success.
1256 Returns 0 on success.
1257 """
1257 """
1258
1258
1259 r1 = cmdutil.revsingle(repo, rev1).node()
1259 r1 = cmdutil.revsingle(repo, rev1).node()
1260 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1260 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1261
1261
1262 wlock = repo.wlock()
1262 wlock = repo.wlock()
1263 try:
1263 try:
1264 repo.dirstate.setparents(r1, r2)
1264 repo.dirstate.setparents(r1, r2)
1265 finally:
1265 finally:
1266 wlock.release()
1266 wlock.release()
1267
1267
1268 def debugstate(ui, repo, nodates=None):
1268 def debugstate(ui, repo, nodates=None):
1269 """show the contents of the current dirstate"""
1269 """show the contents of the current dirstate"""
1270 timestr = ""
1270 timestr = ""
1271 showdate = not nodates
1271 showdate = not nodates
1272 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1272 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1273 if showdate:
1273 if showdate:
1274 if ent[3] == -1:
1274 if ent[3] == -1:
1275 # Pad or slice to locale representation
1275 # Pad or slice to locale representation
1276 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1276 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1277 time.localtime(0)))
1277 time.localtime(0)))
1278 timestr = 'unset'
1278 timestr = 'unset'
1279 timestr = (timestr[:locale_len] +
1279 timestr = (timestr[:locale_len] +
1280 ' ' * (locale_len - len(timestr)))
1280 ' ' * (locale_len - len(timestr)))
1281 else:
1281 else:
1282 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1282 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1283 time.localtime(ent[3]))
1283 time.localtime(ent[3]))
1284 if ent[1] & 020000:
1284 if ent[1] & 020000:
1285 mode = 'lnk'
1285 mode = 'lnk'
1286 else:
1286 else:
1287 mode = '%3o' % (ent[1] & 0777)
1287 mode = '%3o' % (ent[1] & 0777)
1288 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1288 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1289 for f in repo.dirstate.copies():
1289 for f in repo.dirstate.copies():
1290 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1290 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1291
1291
1292 def debugsub(ui, repo, rev=None):
1292 def debugsub(ui, repo, rev=None):
1293 ctx = cmdutil.revsingle(repo, rev, None)
1293 ctx = cmdutil.revsingle(repo, rev, None)
1294 for k, v in sorted(ctx.substate.items()):
1294 for k, v in sorted(ctx.substate.items()):
1295 ui.write('path %s\n' % k)
1295 ui.write('path %s\n' % k)
1296 ui.write(' source %s\n' % v[0])
1296 ui.write(' source %s\n' % v[0])
1297 ui.write(' revision %s\n' % v[1])
1297 ui.write(' revision %s\n' % v[1])
1298
1298
1299 def debugdag(ui, repo, file_=None, *revs, **opts):
1299 def debugdag(ui, repo, file_=None, *revs, **opts):
1300 """format the changelog or an index DAG as a concise textual description
1300 """format the changelog or an index DAG as a concise textual description
1301
1301
1302 If you pass a revlog index, the revlog's DAG is emitted. If you list
1302 If you pass a revlog index, the revlog's DAG is emitted. If you list
1303 revision numbers, they get labelled in the output as rN.
1303 revision numbers, they get labelled in the output as rN.
1304
1304
1305 Otherwise, the changelog DAG of the current repo is emitted.
1305 Otherwise, the changelog DAG of the current repo is emitted.
1306 """
1306 """
1307 spaces = opts.get('spaces')
1307 spaces = opts.get('spaces')
1308 dots = opts.get('dots')
1308 dots = opts.get('dots')
1309 if file_:
1309 if file_:
1310 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1310 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1311 revs = set((int(r) for r in revs))
1311 revs = set((int(r) for r in revs))
1312 def events():
1312 def events():
1313 for r in rlog:
1313 for r in rlog:
1314 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1314 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1315 if r in revs:
1315 if r in revs:
1316 yield 'l', (r, "r%i" % r)
1316 yield 'l', (r, "r%i" % r)
1317 elif repo:
1317 elif repo:
1318 cl = repo.changelog
1318 cl = repo.changelog
1319 tags = opts.get('tags')
1319 tags = opts.get('tags')
1320 branches = opts.get('branches')
1320 branches = opts.get('branches')
1321 if tags:
1321 if tags:
1322 labels = {}
1322 labels = {}
1323 for l, n in repo.tags().items():
1323 for l, n in repo.tags().items():
1324 labels.setdefault(cl.rev(n), []).append(l)
1324 labels.setdefault(cl.rev(n), []).append(l)
1325 def events():
1325 def events():
1326 b = "default"
1326 b = "default"
1327 for r in cl:
1327 for r in cl:
1328 if branches:
1328 if branches:
1329 newb = cl.read(cl.node(r))[5]['branch']
1329 newb = cl.read(cl.node(r))[5]['branch']
1330 if newb != b:
1330 if newb != b:
1331 yield 'a', newb
1331 yield 'a', newb
1332 b = newb
1332 b = newb
1333 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1333 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1334 if tags:
1334 if tags:
1335 ls = labels.get(r)
1335 ls = labels.get(r)
1336 if ls:
1336 if ls:
1337 for l in ls:
1337 for l in ls:
1338 yield 'l', (r, l)
1338 yield 'l', (r, l)
1339 else:
1339 else:
1340 raise util.Abort(_('need repo for changelog dag'))
1340 raise util.Abort(_('need repo for changelog dag'))
1341
1341
1342 for line in dagparser.dagtextlines(events(),
1342 for line in dagparser.dagtextlines(events(),
1343 addspaces=spaces,
1343 addspaces=spaces,
1344 wraplabels=True,
1344 wraplabels=True,
1345 wrapannotations=True,
1345 wrapannotations=True,
1346 wrapnonlinear=dots,
1346 wrapnonlinear=dots,
1347 usedots=dots,
1347 usedots=dots,
1348 maxlinewidth=70):
1348 maxlinewidth=70):
1349 ui.write(line)
1349 ui.write(line)
1350 ui.write("\n")
1350 ui.write("\n")
1351
1351
1352 def debugdata(ui, repo, file_, rev):
1352 def debugdata(ui, repo, file_, rev):
1353 """dump the contents of a data file revision"""
1353 """dump the contents of a data file revision"""
1354 r = None
1354 r = None
1355 if repo:
1355 if repo:
1356 filelog = repo.file(file_)
1356 filelog = repo.file(file_)
1357 if len(filelog):
1357 if len(filelog):
1358 r = filelog
1358 r = filelog
1359 if not r:
1359 if not r:
1360 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1360 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1361 try:
1361 try:
1362 ui.write(r.revision(r.lookup(rev)))
1362 ui.write(r.revision(r.lookup(rev)))
1363 except KeyError:
1363 except KeyError:
1364 raise util.Abort(_('invalid revision identifier %s') % rev)
1364 raise util.Abort(_('invalid revision identifier %s') % rev)
1365
1365
1366 def debugdate(ui, date, range=None, **opts):
1366 def debugdate(ui, date, range=None, **opts):
1367 """parse and display a date"""
1367 """parse and display a date"""
1368 if opts["extended"]:
1368 if opts["extended"]:
1369 d = util.parsedate(date, util.extendeddateformats)
1369 d = util.parsedate(date, util.extendeddateformats)
1370 else:
1370 else:
1371 d = util.parsedate(date)
1371 d = util.parsedate(date)
1372 ui.write("internal: %s %s\n" % d)
1372 ui.write("internal: %s %s\n" % d)
1373 ui.write("standard: %s\n" % util.datestr(d))
1373 ui.write("standard: %s\n" % util.datestr(d))
1374 if range:
1374 if range:
1375 m = util.matchdate(range)
1375 m = util.matchdate(range)
1376 ui.write("match: %s\n" % m(d[0]))
1376 ui.write("match: %s\n" % m(d[0]))
1377
1377
1378 def debugignore(ui, repo, *values, **opts):
1378 def debugignore(ui, repo, *values, **opts):
1379 """display the combined ignore pattern"""
1379 """display the combined ignore pattern"""
1380 ignore = repo.dirstate._ignore
1380 ignore = repo.dirstate._ignore
1381 if hasattr(ignore, 'includepat'):
1381 if hasattr(ignore, 'includepat'):
1382 ui.write("%s\n" % ignore.includepat)
1382 ui.write("%s\n" % ignore.includepat)
1383 else:
1383 else:
1384 raise util.Abort(_("no ignore patterns found"))
1384 raise util.Abort(_("no ignore patterns found"))
1385
1385
1386 def debugindex(ui, repo, file_, **opts):
1386 def debugindex(ui, repo, file_, **opts):
1387 """dump the contents of an index file"""
1387 """dump the contents of an index file"""
1388 r = None
1388 r = None
1389 if repo:
1389 if repo:
1390 filelog = repo.file(file_)
1390 filelog = repo.file(file_)
1391 if len(filelog):
1391 if len(filelog):
1392 r = filelog
1392 r = filelog
1393
1393
1394 format = opts.get('format', 0)
1394 format = opts.get('format', 0)
1395 if format not in (0, 1):
1395 if format not in (0, 1):
1396 raise util.Abort(_("unknown format %d") % format)
1396 raise util.Abort(_("unknown format %d") % format)
1397
1397
1398 if not r:
1398 if not r:
1399 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1399 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1400
1400
1401 if format == 0:
1401 if format == 0:
1402 ui.write(" rev offset length base linkrev"
1402 ui.write(" rev offset length base linkrev"
1403 " nodeid p1 p2\n")
1403 " nodeid p1 p2\n")
1404 elif format == 1:
1404 elif format == 1:
1405 ui.write(" rev flag offset length"
1405 ui.write(" rev flag offset length"
1406 " size base link p1 p2 nodeid\n")
1406 " size base link p1 p2 nodeid\n")
1407
1407
1408 for i in r:
1408 for i in r:
1409 node = r.node(i)
1409 node = r.node(i)
1410 if format == 0:
1410 if format == 0:
1411 try:
1411 try:
1412 pp = r.parents(node)
1412 pp = r.parents(node)
1413 except:
1413 except:
1414 pp = [nullid, nullid]
1414 pp = [nullid, nullid]
1415 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1415 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1416 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1416 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1417 short(node), short(pp[0]), short(pp[1])))
1417 short(node), short(pp[0]), short(pp[1])))
1418 elif format == 1:
1418 elif format == 1:
1419 pr = r.parentrevs(i)
1419 pr = r.parentrevs(i)
1420 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1420 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1421 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1421 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1422 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1422 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1423
1423
1424 def debugindexdot(ui, repo, file_):
1424 def debugindexdot(ui, repo, file_):
1425 """dump an index DAG as a graphviz dot file"""
1425 """dump an index DAG as a graphviz dot file"""
1426 r = None
1426 r = None
1427 if repo:
1427 if repo:
1428 filelog = repo.file(file_)
1428 filelog = repo.file(file_)
1429 if len(filelog):
1429 if len(filelog):
1430 r = filelog
1430 r = filelog
1431 if not r:
1431 if not r:
1432 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1432 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1433 ui.write("digraph G {\n")
1433 ui.write("digraph G {\n")
1434 for i in r:
1434 for i in r:
1435 node = r.node(i)
1435 node = r.node(i)
1436 pp = r.parents(node)
1436 pp = r.parents(node)
1437 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1437 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1438 if pp[1] != nullid:
1438 if pp[1] != nullid:
1439 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1439 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1440 ui.write("}\n")
1440 ui.write("}\n")
1441
1441
1442 def debuginstall(ui):
1442 def debuginstall(ui):
1443 '''test Mercurial installation
1443 '''test Mercurial installation
1444
1444
1445 Returns 0 on success.
1445 Returns 0 on success.
1446 '''
1446 '''
1447
1447
1448 def writetemp(contents):
1448 def writetemp(contents):
1449 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1449 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1450 f = os.fdopen(fd, "wb")
1450 f = os.fdopen(fd, "wb")
1451 f.write(contents)
1451 f.write(contents)
1452 f.close()
1452 f.close()
1453 return name
1453 return name
1454
1454
1455 problems = 0
1455 problems = 0
1456
1456
1457 # encoding
1457 # encoding
1458 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1458 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1459 try:
1459 try:
1460 encoding.fromlocal("test")
1460 encoding.fromlocal("test")
1461 except util.Abort, inst:
1461 except util.Abort, inst:
1462 ui.write(" %s\n" % inst)
1462 ui.write(" %s\n" % inst)
1463 ui.write(_(" (check that your locale is properly set)\n"))
1463 ui.write(_(" (check that your locale is properly set)\n"))
1464 problems += 1
1464 problems += 1
1465
1465
1466 # compiled modules
1466 # compiled modules
1467 ui.status(_("Checking installed modules (%s)...\n")
1467 ui.status(_("Checking installed modules (%s)...\n")
1468 % os.path.dirname(__file__))
1468 % os.path.dirname(__file__))
1469 try:
1469 try:
1470 import bdiff, mpatch, base85, osutil
1470 import bdiff, mpatch, base85, osutil
1471 except Exception, inst:
1471 except Exception, inst:
1472 ui.write(" %s\n" % inst)
1472 ui.write(" %s\n" % inst)
1473 ui.write(_(" One or more extensions could not be found"))
1473 ui.write(_(" One or more extensions could not be found"))
1474 ui.write(_(" (check that you compiled the extensions)\n"))
1474 ui.write(_(" (check that you compiled the extensions)\n"))
1475 problems += 1
1475 problems += 1
1476
1476
1477 # templates
1477 # templates
1478 ui.status(_("Checking templates...\n"))
1478 ui.status(_("Checking templates...\n"))
1479 try:
1479 try:
1480 import templater
1480 import templater
1481 templater.templater(templater.templatepath("map-cmdline.default"))
1481 templater.templater(templater.templatepath("map-cmdline.default"))
1482 except Exception, inst:
1482 except Exception, inst:
1483 ui.write(" %s\n" % inst)
1483 ui.write(" %s\n" % inst)
1484 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1484 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1485 problems += 1
1485 problems += 1
1486
1486
1487 # patch
1487 # patch
1488 ui.status(_("Checking patch...\n"))
1488 ui.status(_("Checking patch...\n"))
1489 patchproblems = 0
1489 patchproblems = 0
1490 a = "1\n2\n3\n4\n"
1490 a = "1\n2\n3\n4\n"
1491 b = "1\n2\n3\ninsert\n4\n"
1491 b = "1\n2\n3\ninsert\n4\n"
1492 fa = writetemp(a)
1492 fa = writetemp(a)
1493 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1493 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1494 os.path.basename(fa))
1494 os.path.basename(fa))
1495 fd = writetemp(d)
1495 fd = writetemp(d)
1496
1496
1497 files = {}
1497 files = {}
1498 try:
1498 try:
1499 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1499 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1500 except util.Abort, e:
1500 except util.Abort, e:
1501 ui.write(_(" patch call failed:\n"))
1501 ui.write(_(" patch call failed:\n"))
1502 ui.write(" " + str(e) + "\n")
1502 ui.write(" " + str(e) + "\n")
1503 patchproblems += 1
1503 patchproblems += 1
1504 else:
1504 else:
1505 if list(files) != [os.path.basename(fa)]:
1505 if list(files) != [os.path.basename(fa)]:
1506 ui.write(_(" unexpected patch output!\n"))
1506 ui.write(_(" unexpected patch output!\n"))
1507 patchproblems += 1
1507 patchproblems += 1
1508 a = open(fa).read()
1508 a = open(fa).read()
1509 if a != b:
1509 if a != b:
1510 ui.write(_(" patch test failed!\n"))
1510 ui.write(_(" patch test failed!\n"))
1511 patchproblems += 1
1511 patchproblems += 1
1512
1512
1513 if patchproblems:
1513 if patchproblems:
1514 if ui.config('ui', 'patch'):
1514 if ui.config('ui', 'patch'):
1515 ui.write(_(" (Current patch tool may be incompatible with patch,"
1515 ui.write(_(" (Current patch tool may be incompatible with patch,"
1516 " or misconfigured. Please check your configuration"
1516 " or misconfigured. Please check your configuration"
1517 " file)\n"))
1517 " file)\n"))
1518 else:
1518 else:
1519 ui.write(_(" Internal patcher failure, please report this error"
1519 ui.write(_(" Internal patcher failure, please report this error"
1520 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1520 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1521 problems += patchproblems
1521 problems += patchproblems
1522
1522
1523 os.unlink(fa)
1523 os.unlink(fa)
1524 os.unlink(fd)
1524 os.unlink(fd)
1525
1525
1526 # editor
1526 # editor
1527 ui.status(_("Checking commit editor...\n"))
1527 ui.status(_("Checking commit editor...\n"))
1528 editor = ui.geteditor()
1528 editor = ui.geteditor()
1529 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1529 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1530 if not cmdpath:
1530 if not cmdpath:
1531 if editor == 'vi':
1531 if editor == 'vi':
1532 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1532 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1533 ui.write(_(" (specify a commit editor in your configuration"
1533 ui.write(_(" (specify a commit editor in your configuration"
1534 " file)\n"))
1534 " file)\n"))
1535 else:
1535 else:
1536 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1536 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1537 ui.write(_(" (specify a commit editor in your configuration"
1537 ui.write(_(" (specify a commit editor in your configuration"
1538 " file)\n"))
1538 " file)\n"))
1539 problems += 1
1539 problems += 1
1540
1540
1541 # check username
1541 # check username
1542 ui.status(_("Checking username...\n"))
1542 ui.status(_("Checking username...\n"))
1543 try:
1543 try:
1544 ui.username()
1544 ui.username()
1545 except util.Abort, e:
1545 except util.Abort, e:
1546 ui.write(" %s\n" % e)
1546 ui.write(" %s\n" % e)
1547 ui.write(_(" (specify a username in your configuration file)\n"))
1547 ui.write(_(" (specify a username in your configuration file)\n"))
1548 problems += 1
1548 problems += 1
1549
1549
1550 if not problems:
1550 if not problems:
1551 ui.status(_("No problems detected\n"))
1551 ui.status(_("No problems detected\n"))
1552 else:
1552 else:
1553 ui.write(_("%s problems detected,"
1553 ui.write(_("%s problems detected,"
1554 " please check your install!\n") % problems)
1554 " please check your install!\n") % problems)
1555
1555
1556 return problems
1556 return problems
1557
1557
1558 def debugrename(ui, repo, file1, *pats, **opts):
1558 def debugrename(ui, repo, file1, *pats, **opts):
1559 """dump rename information"""
1559 """dump rename information"""
1560
1560
1561 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1561 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1562 m = cmdutil.match(repo, (file1,) + pats, opts)
1562 m = cmdutil.match(repo, (file1,) + pats, opts)
1563 for abs in ctx.walk(m):
1563 for abs in ctx.walk(m):
1564 fctx = ctx[abs]
1564 fctx = ctx[abs]
1565 o = fctx.filelog().renamed(fctx.filenode())
1565 o = fctx.filelog().renamed(fctx.filenode())
1566 rel = m.rel(abs)
1566 rel = m.rel(abs)
1567 if o:
1567 if o:
1568 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1568 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1569 else:
1569 else:
1570 ui.write(_("%s not renamed\n") % rel)
1570 ui.write(_("%s not renamed\n") % rel)
1571
1571
1572 def debugwalk(ui, repo, *pats, **opts):
1572 def debugwalk(ui, repo, *pats, **opts):
1573 """show how files match on given patterns"""
1573 """show how files match on given patterns"""
1574 m = cmdutil.match(repo, pats, opts)
1574 m = cmdutil.match(repo, pats, opts)
1575 items = list(repo.walk(m))
1575 items = list(repo.walk(m))
1576 if not items:
1576 if not items:
1577 return
1577 return
1578 fmt = 'f %%-%ds %%-%ds %%s' % (
1578 fmt = 'f %%-%ds %%-%ds %%s' % (
1579 max([len(abs) for abs in items]),
1579 max([len(abs) for abs in items]),
1580 max([len(m.rel(abs)) for abs in items]))
1580 max([len(m.rel(abs)) for abs in items]))
1581 for abs in items:
1581 for abs in items:
1582 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1582 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1583 ui.write("%s\n" % line.rstrip())
1583 ui.write("%s\n" % line.rstrip())
1584
1584
1585 def debugwireargs(ui, repopath, *vals, **opts):
1586 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1587 for opt in remoteopts:
1588 del opts[opt[1]]
1589 args = {}
1590 for k, v in opts.iteritems():
1591 if v:
1592 args[k] = v
1593 # run twice to check that we don't mess up the stream for the next command
1594 res1 = repo.debugwireargs(*vals, **args)
1595 res2 = repo.debugwireargs(*vals, **args)
1596 ui.write("%s\n" % res1)
1597 if res1 != res2:
1598 ui.warn("%s\n" % res2)
1599
1585 def diff(ui, repo, *pats, **opts):
1600 def diff(ui, repo, *pats, **opts):
1586 """diff repository (or selected files)
1601 """diff repository (or selected files)
1587
1602
1588 Show differences between revisions for the specified files.
1603 Show differences between revisions for the specified files.
1589
1604
1590 Differences between files are shown using the unified diff format.
1605 Differences between files are shown using the unified diff format.
1591
1606
1592 .. note::
1607 .. note::
1593 diff may generate unexpected results for merges, as it will
1608 diff may generate unexpected results for merges, as it will
1594 default to comparing against the working directory's first
1609 default to comparing against the working directory's first
1595 parent changeset if no revisions are specified.
1610 parent changeset if no revisions are specified.
1596
1611
1597 When two revision arguments are given, then changes are shown
1612 When two revision arguments are given, then changes are shown
1598 between those revisions. If only one revision is specified then
1613 between those revisions. If only one revision is specified then
1599 that revision is compared to the working directory, and, when no
1614 that revision is compared to the working directory, and, when no
1600 revisions are specified, the working directory files are compared
1615 revisions are specified, the working directory files are compared
1601 to its parent.
1616 to its parent.
1602
1617
1603 Alternatively you can specify -c/--change with a revision to see
1618 Alternatively you can specify -c/--change with a revision to see
1604 the changes in that changeset relative to its first parent.
1619 the changes in that changeset relative to its first parent.
1605
1620
1606 Without the -a/--text option, diff will avoid generating diffs of
1621 Without the -a/--text option, diff will avoid generating diffs of
1607 files it detects as binary. With -a, diff will generate a diff
1622 files it detects as binary. With -a, diff will generate a diff
1608 anyway, probably with undesirable results.
1623 anyway, probably with undesirable results.
1609
1624
1610 Use the -g/--git option to generate diffs in the git extended diff
1625 Use the -g/--git option to generate diffs in the git extended diff
1611 format. For more information, read :hg:`help diffs`.
1626 format. For more information, read :hg:`help diffs`.
1612
1627
1613 Returns 0 on success.
1628 Returns 0 on success.
1614 """
1629 """
1615
1630
1616 revs = opts.get('rev')
1631 revs = opts.get('rev')
1617 change = opts.get('change')
1632 change = opts.get('change')
1618 stat = opts.get('stat')
1633 stat = opts.get('stat')
1619 reverse = opts.get('reverse')
1634 reverse = opts.get('reverse')
1620
1635
1621 if revs and change:
1636 if revs and change:
1622 msg = _('cannot specify --rev and --change at the same time')
1637 msg = _('cannot specify --rev and --change at the same time')
1623 raise util.Abort(msg)
1638 raise util.Abort(msg)
1624 elif change:
1639 elif change:
1625 node2 = cmdutil.revsingle(repo, change, None).node()
1640 node2 = cmdutil.revsingle(repo, change, None).node()
1626 node1 = repo[node2].parents()[0].node()
1641 node1 = repo[node2].parents()[0].node()
1627 else:
1642 else:
1628 node1, node2 = cmdutil.revpair(repo, revs)
1643 node1, node2 = cmdutil.revpair(repo, revs)
1629
1644
1630 if reverse:
1645 if reverse:
1631 node1, node2 = node2, node1
1646 node1, node2 = node2, node1
1632
1647
1633 diffopts = patch.diffopts(ui, opts)
1648 diffopts = patch.diffopts(ui, opts)
1634 m = cmdutil.match(repo, pats, opts)
1649 m = cmdutil.match(repo, pats, opts)
1635 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1650 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1636 listsubrepos=opts.get('subrepos'))
1651 listsubrepos=opts.get('subrepos'))
1637
1652
1638 def export(ui, repo, *changesets, **opts):
1653 def export(ui, repo, *changesets, **opts):
1639 """dump the header and diffs for one or more changesets
1654 """dump the header and diffs for one or more changesets
1640
1655
1641 Print the changeset header and diffs for one or more revisions.
1656 Print the changeset header and diffs for one or more revisions.
1642
1657
1643 The information shown in the changeset header is: author, date,
1658 The information shown in the changeset header is: author, date,
1644 branch name (if non-default), changeset hash, parent(s) and commit
1659 branch name (if non-default), changeset hash, parent(s) and commit
1645 comment.
1660 comment.
1646
1661
1647 .. note::
1662 .. note::
1648 export may generate unexpected diff output for merge
1663 export may generate unexpected diff output for merge
1649 changesets, as it will compare the merge changeset against its
1664 changesets, as it will compare the merge changeset against its
1650 first parent only.
1665 first parent only.
1651
1666
1652 Output may be to a file, in which case the name of the file is
1667 Output may be to a file, in which case the name of the file is
1653 given using a format string. The formatting rules are as follows:
1668 given using a format string. The formatting rules are as follows:
1654
1669
1655 :``%%``: literal "%" character
1670 :``%%``: literal "%" character
1656 :``%H``: changeset hash (40 hexadecimal digits)
1671 :``%H``: changeset hash (40 hexadecimal digits)
1657 :``%N``: number of patches being generated
1672 :``%N``: number of patches being generated
1658 :``%R``: changeset revision number
1673 :``%R``: changeset revision number
1659 :``%b``: basename of the exporting repository
1674 :``%b``: basename of the exporting repository
1660 :``%h``: short-form changeset hash (12 hexadecimal digits)
1675 :``%h``: short-form changeset hash (12 hexadecimal digits)
1661 :``%n``: zero-padded sequence number, starting at 1
1676 :``%n``: zero-padded sequence number, starting at 1
1662 :``%r``: zero-padded changeset revision number
1677 :``%r``: zero-padded changeset revision number
1663
1678
1664 Without the -a/--text option, export will avoid generating diffs
1679 Without the -a/--text option, export will avoid generating diffs
1665 of files it detects as binary. With -a, export will generate a
1680 of files it detects as binary. With -a, export will generate a
1666 diff anyway, probably with undesirable results.
1681 diff anyway, probably with undesirable results.
1667
1682
1668 Use the -g/--git option to generate diffs in the git extended diff
1683 Use the -g/--git option to generate diffs in the git extended diff
1669 format. See :hg:`help diffs` for more information.
1684 format. See :hg:`help diffs` for more information.
1670
1685
1671 With the --switch-parent option, the diff will be against the
1686 With the --switch-parent option, the diff will be against the
1672 second parent. It can be useful to review a merge.
1687 second parent. It can be useful to review a merge.
1673
1688
1674 Returns 0 on success.
1689 Returns 0 on success.
1675 """
1690 """
1676 changesets += tuple(opts.get('rev', []))
1691 changesets += tuple(opts.get('rev', []))
1677 if not changesets:
1692 if not changesets:
1678 raise util.Abort(_("export requires at least one changeset"))
1693 raise util.Abort(_("export requires at least one changeset"))
1679 revs = cmdutil.revrange(repo, changesets)
1694 revs = cmdutil.revrange(repo, changesets)
1680 if len(revs) > 1:
1695 if len(revs) > 1:
1681 ui.note(_('exporting patches:\n'))
1696 ui.note(_('exporting patches:\n'))
1682 else:
1697 else:
1683 ui.note(_('exporting patch:\n'))
1698 ui.note(_('exporting patch:\n'))
1684 cmdutil.export(repo, revs, template=opts.get('output'),
1699 cmdutil.export(repo, revs, template=opts.get('output'),
1685 switch_parent=opts.get('switch_parent'),
1700 switch_parent=opts.get('switch_parent'),
1686 opts=patch.diffopts(ui, opts))
1701 opts=patch.diffopts(ui, opts))
1687
1702
1688 def forget(ui, repo, *pats, **opts):
1703 def forget(ui, repo, *pats, **opts):
1689 """forget the specified files on the next commit
1704 """forget the specified files on the next commit
1690
1705
1691 Mark the specified files so they will no longer be tracked
1706 Mark the specified files so they will no longer be tracked
1692 after the next commit.
1707 after the next commit.
1693
1708
1694 This only removes files from the current branch, not from the
1709 This only removes files from the current branch, not from the
1695 entire project history, and it does not delete them from the
1710 entire project history, and it does not delete them from the
1696 working directory.
1711 working directory.
1697
1712
1698 To undo a forget before the next commit, see :hg:`add`.
1713 To undo a forget before the next commit, see :hg:`add`.
1699
1714
1700 Returns 0 on success.
1715 Returns 0 on success.
1701 """
1716 """
1702
1717
1703 if not pats:
1718 if not pats:
1704 raise util.Abort(_('no files specified'))
1719 raise util.Abort(_('no files specified'))
1705
1720
1706 m = cmdutil.match(repo, pats, opts)
1721 m = cmdutil.match(repo, pats, opts)
1707 s = repo.status(match=m, clean=True)
1722 s = repo.status(match=m, clean=True)
1708 forget = sorted(s[0] + s[1] + s[3] + s[6])
1723 forget = sorted(s[0] + s[1] + s[3] + s[6])
1709 errs = 0
1724 errs = 0
1710
1725
1711 for f in m.files():
1726 for f in m.files():
1712 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1727 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1713 ui.warn(_('not removing %s: file is already untracked\n')
1728 ui.warn(_('not removing %s: file is already untracked\n')
1714 % m.rel(f))
1729 % m.rel(f))
1715 errs = 1
1730 errs = 1
1716
1731
1717 for f in forget:
1732 for f in forget:
1718 if ui.verbose or not m.exact(f):
1733 if ui.verbose or not m.exact(f):
1719 ui.status(_('removing %s\n') % m.rel(f))
1734 ui.status(_('removing %s\n') % m.rel(f))
1720
1735
1721 repo[None].remove(forget, unlink=False)
1736 repo[None].remove(forget, unlink=False)
1722 return errs
1737 return errs
1723
1738
1724 def grep(ui, repo, pattern, *pats, **opts):
1739 def grep(ui, repo, pattern, *pats, **opts):
1725 """search for a pattern in specified files and revisions
1740 """search for a pattern in specified files and revisions
1726
1741
1727 Search revisions of files for a regular expression.
1742 Search revisions of files for a regular expression.
1728
1743
1729 This command behaves differently than Unix grep. It only accepts
1744 This command behaves differently than Unix grep. It only accepts
1730 Python/Perl regexps. It searches repository history, not the
1745 Python/Perl regexps. It searches repository history, not the
1731 working directory. It always prints the revision number in which a
1746 working directory. It always prints the revision number in which a
1732 match appears.
1747 match appears.
1733
1748
1734 By default, grep only prints output for the first revision of a
1749 By default, grep only prints output for the first revision of a
1735 file in which it finds a match. To get it to print every revision
1750 file in which it finds a match. To get it to print every revision
1736 that contains a change in match status ("-" for a match that
1751 that contains a change in match status ("-" for a match that
1737 becomes a non-match, or "+" for a non-match that becomes a match),
1752 becomes a non-match, or "+" for a non-match that becomes a match),
1738 use the --all flag.
1753 use the --all flag.
1739
1754
1740 Returns 0 if a match is found, 1 otherwise.
1755 Returns 0 if a match is found, 1 otherwise.
1741 """
1756 """
1742 reflags = 0
1757 reflags = 0
1743 if opts.get('ignore_case'):
1758 if opts.get('ignore_case'):
1744 reflags |= re.I
1759 reflags |= re.I
1745 try:
1760 try:
1746 regexp = re.compile(pattern, reflags)
1761 regexp = re.compile(pattern, reflags)
1747 except re.error, inst:
1762 except re.error, inst:
1748 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1763 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1749 return 1
1764 return 1
1750 sep, eol = ':', '\n'
1765 sep, eol = ':', '\n'
1751 if opts.get('print0'):
1766 if opts.get('print0'):
1752 sep = eol = '\0'
1767 sep = eol = '\0'
1753
1768
1754 getfile = util.lrucachefunc(repo.file)
1769 getfile = util.lrucachefunc(repo.file)
1755
1770
1756 def matchlines(body):
1771 def matchlines(body):
1757 begin = 0
1772 begin = 0
1758 linenum = 0
1773 linenum = 0
1759 while True:
1774 while True:
1760 match = regexp.search(body, begin)
1775 match = regexp.search(body, begin)
1761 if not match:
1776 if not match:
1762 break
1777 break
1763 mstart, mend = match.span()
1778 mstart, mend = match.span()
1764 linenum += body.count('\n', begin, mstart) + 1
1779 linenum += body.count('\n', begin, mstart) + 1
1765 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1780 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1766 begin = body.find('\n', mend) + 1 or len(body)
1781 begin = body.find('\n', mend) + 1 or len(body)
1767 lend = begin - 1
1782 lend = begin - 1
1768 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1783 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1769
1784
1770 class linestate(object):
1785 class linestate(object):
1771 def __init__(self, line, linenum, colstart, colend):
1786 def __init__(self, line, linenum, colstart, colend):
1772 self.line = line
1787 self.line = line
1773 self.linenum = linenum
1788 self.linenum = linenum
1774 self.colstart = colstart
1789 self.colstart = colstart
1775 self.colend = colend
1790 self.colend = colend
1776
1791
1777 def __hash__(self):
1792 def __hash__(self):
1778 return hash((self.linenum, self.line))
1793 return hash((self.linenum, self.line))
1779
1794
1780 def __eq__(self, other):
1795 def __eq__(self, other):
1781 return self.line == other.line
1796 return self.line == other.line
1782
1797
1783 matches = {}
1798 matches = {}
1784 copies = {}
1799 copies = {}
1785 def grepbody(fn, rev, body):
1800 def grepbody(fn, rev, body):
1786 matches[rev].setdefault(fn, [])
1801 matches[rev].setdefault(fn, [])
1787 m = matches[rev][fn]
1802 m = matches[rev][fn]
1788 for lnum, cstart, cend, line in matchlines(body):
1803 for lnum, cstart, cend, line in matchlines(body):
1789 s = linestate(line, lnum, cstart, cend)
1804 s = linestate(line, lnum, cstart, cend)
1790 m.append(s)
1805 m.append(s)
1791
1806
1792 def difflinestates(a, b):
1807 def difflinestates(a, b):
1793 sm = difflib.SequenceMatcher(None, a, b)
1808 sm = difflib.SequenceMatcher(None, a, b)
1794 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1809 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1795 if tag == 'insert':
1810 if tag == 'insert':
1796 for i in xrange(blo, bhi):
1811 for i in xrange(blo, bhi):
1797 yield ('+', b[i])
1812 yield ('+', b[i])
1798 elif tag == 'delete':
1813 elif tag == 'delete':
1799 for i in xrange(alo, ahi):
1814 for i in xrange(alo, ahi):
1800 yield ('-', a[i])
1815 yield ('-', a[i])
1801 elif tag == 'replace':
1816 elif tag == 'replace':
1802 for i in xrange(alo, ahi):
1817 for i in xrange(alo, ahi):
1803 yield ('-', a[i])
1818 yield ('-', a[i])
1804 for i in xrange(blo, bhi):
1819 for i in xrange(blo, bhi):
1805 yield ('+', b[i])
1820 yield ('+', b[i])
1806
1821
1807 def display(fn, ctx, pstates, states):
1822 def display(fn, ctx, pstates, states):
1808 rev = ctx.rev()
1823 rev = ctx.rev()
1809 datefunc = ui.quiet and util.shortdate or util.datestr
1824 datefunc = ui.quiet and util.shortdate or util.datestr
1810 found = False
1825 found = False
1811 filerevmatches = {}
1826 filerevmatches = {}
1812 if opts.get('all'):
1827 if opts.get('all'):
1813 iter = difflinestates(pstates, states)
1828 iter = difflinestates(pstates, states)
1814 else:
1829 else:
1815 iter = [('', l) for l in states]
1830 iter = [('', l) for l in states]
1816 for change, l in iter:
1831 for change, l in iter:
1817 cols = [fn, str(rev)]
1832 cols = [fn, str(rev)]
1818 before, match, after = None, None, None
1833 before, match, after = None, None, None
1819 if opts.get('line_number'):
1834 if opts.get('line_number'):
1820 cols.append(str(l.linenum))
1835 cols.append(str(l.linenum))
1821 if opts.get('all'):
1836 if opts.get('all'):
1822 cols.append(change)
1837 cols.append(change)
1823 if opts.get('user'):
1838 if opts.get('user'):
1824 cols.append(ui.shortuser(ctx.user()))
1839 cols.append(ui.shortuser(ctx.user()))
1825 if opts.get('date'):
1840 if opts.get('date'):
1826 cols.append(datefunc(ctx.date()))
1841 cols.append(datefunc(ctx.date()))
1827 if opts.get('files_with_matches'):
1842 if opts.get('files_with_matches'):
1828 c = (fn, rev)
1843 c = (fn, rev)
1829 if c in filerevmatches:
1844 if c in filerevmatches:
1830 continue
1845 continue
1831 filerevmatches[c] = 1
1846 filerevmatches[c] = 1
1832 else:
1847 else:
1833 before = l.line[:l.colstart]
1848 before = l.line[:l.colstart]
1834 match = l.line[l.colstart:l.colend]
1849 match = l.line[l.colstart:l.colend]
1835 after = l.line[l.colend:]
1850 after = l.line[l.colend:]
1836 ui.write(sep.join(cols))
1851 ui.write(sep.join(cols))
1837 if before is not None:
1852 if before is not None:
1838 ui.write(sep + before)
1853 ui.write(sep + before)
1839 ui.write(match, label='grep.match')
1854 ui.write(match, label='grep.match')
1840 ui.write(after)
1855 ui.write(after)
1841 ui.write(eol)
1856 ui.write(eol)
1842 found = True
1857 found = True
1843 return found
1858 return found
1844
1859
1845 skip = {}
1860 skip = {}
1846 revfiles = {}
1861 revfiles = {}
1847 matchfn = cmdutil.match(repo, pats, opts)
1862 matchfn = cmdutil.match(repo, pats, opts)
1848 found = False
1863 found = False
1849 follow = opts.get('follow')
1864 follow = opts.get('follow')
1850
1865
1851 def prep(ctx, fns):
1866 def prep(ctx, fns):
1852 rev = ctx.rev()
1867 rev = ctx.rev()
1853 pctx = ctx.parents()[0]
1868 pctx = ctx.parents()[0]
1854 parent = pctx.rev()
1869 parent = pctx.rev()
1855 matches.setdefault(rev, {})
1870 matches.setdefault(rev, {})
1856 matches.setdefault(parent, {})
1871 matches.setdefault(parent, {})
1857 files = revfiles.setdefault(rev, [])
1872 files = revfiles.setdefault(rev, [])
1858 for fn in fns:
1873 for fn in fns:
1859 flog = getfile(fn)
1874 flog = getfile(fn)
1860 try:
1875 try:
1861 fnode = ctx.filenode(fn)
1876 fnode = ctx.filenode(fn)
1862 except error.LookupError:
1877 except error.LookupError:
1863 continue
1878 continue
1864
1879
1865 copied = flog.renamed(fnode)
1880 copied = flog.renamed(fnode)
1866 copy = follow and copied and copied[0]
1881 copy = follow and copied and copied[0]
1867 if copy:
1882 if copy:
1868 copies.setdefault(rev, {})[fn] = copy
1883 copies.setdefault(rev, {})[fn] = copy
1869 if fn in skip:
1884 if fn in skip:
1870 if copy:
1885 if copy:
1871 skip[copy] = True
1886 skip[copy] = True
1872 continue
1887 continue
1873 files.append(fn)
1888 files.append(fn)
1874
1889
1875 if fn not in matches[rev]:
1890 if fn not in matches[rev]:
1876 grepbody(fn, rev, flog.read(fnode))
1891 grepbody(fn, rev, flog.read(fnode))
1877
1892
1878 pfn = copy or fn
1893 pfn = copy or fn
1879 if pfn not in matches[parent]:
1894 if pfn not in matches[parent]:
1880 try:
1895 try:
1881 fnode = pctx.filenode(pfn)
1896 fnode = pctx.filenode(pfn)
1882 grepbody(pfn, parent, flog.read(fnode))
1897 grepbody(pfn, parent, flog.read(fnode))
1883 except error.LookupError:
1898 except error.LookupError:
1884 pass
1899 pass
1885
1900
1886 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1901 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1887 rev = ctx.rev()
1902 rev = ctx.rev()
1888 parent = ctx.parents()[0].rev()
1903 parent = ctx.parents()[0].rev()
1889 for fn in sorted(revfiles.get(rev, [])):
1904 for fn in sorted(revfiles.get(rev, [])):
1890 states = matches[rev][fn]
1905 states = matches[rev][fn]
1891 copy = copies.get(rev, {}).get(fn)
1906 copy = copies.get(rev, {}).get(fn)
1892 if fn in skip:
1907 if fn in skip:
1893 if copy:
1908 if copy:
1894 skip[copy] = True
1909 skip[copy] = True
1895 continue
1910 continue
1896 pstates = matches.get(parent, {}).get(copy or fn, [])
1911 pstates = matches.get(parent, {}).get(copy or fn, [])
1897 if pstates or states:
1912 if pstates or states:
1898 r = display(fn, ctx, pstates, states)
1913 r = display(fn, ctx, pstates, states)
1899 found = found or r
1914 found = found or r
1900 if r and not opts.get('all'):
1915 if r and not opts.get('all'):
1901 skip[fn] = True
1916 skip[fn] = True
1902 if copy:
1917 if copy:
1903 skip[copy] = True
1918 skip[copy] = True
1904 del matches[rev]
1919 del matches[rev]
1905 del revfiles[rev]
1920 del revfiles[rev]
1906
1921
1907 return not found
1922 return not found
1908
1923
1909 def heads(ui, repo, *branchrevs, **opts):
1924 def heads(ui, repo, *branchrevs, **opts):
1910 """show current repository heads or show branch heads
1925 """show current repository heads or show branch heads
1911
1926
1912 With no arguments, show all repository branch heads.
1927 With no arguments, show all repository branch heads.
1913
1928
1914 Repository "heads" are changesets with no child changesets. They are
1929 Repository "heads" are changesets with no child changesets. They are
1915 where development generally takes place and are the usual targets
1930 where development generally takes place and are the usual targets
1916 for update and merge operations. Branch heads are changesets that have
1931 for update and merge operations. Branch heads are changesets that have
1917 no child changeset on the same branch.
1932 no child changeset on the same branch.
1918
1933
1919 If one or more REVs are given, only branch heads on the branches
1934 If one or more REVs are given, only branch heads on the branches
1920 associated with the specified changesets are shown.
1935 associated with the specified changesets are shown.
1921
1936
1922 If -c/--closed is specified, also show branch heads marked closed
1937 If -c/--closed is specified, also show branch heads marked closed
1923 (see :hg:`commit --close-branch`).
1938 (see :hg:`commit --close-branch`).
1924
1939
1925 If STARTREV is specified, only those heads that are descendants of
1940 If STARTREV is specified, only those heads that are descendants of
1926 STARTREV will be displayed.
1941 STARTREV will be displayed.
1927
1942
1928 If -t/--topo is specified, named branch mechanics will be ignored and only
1943 If -t/--topo is specified, named branch mechanics will be ignored and only
1929 changesets without children will be shown.
1944 changesets without children will be shown.
1930
1945
1931 Returns 0 if matching heads are found, 1 if not.
1946 Returns 0 if matching heads are found, 1 if not.
1932 """
1947 """
1933
1948
1934 start = None
1949 start = None
1935 if 'rev' in opts:
1950 if 'rev' in opts:
1936 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1951 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1937
1952
1938 if opts.get('topo'):
1953 if opts.get('topo'):
1939 heads = [repo[h] for h in repo.heads(start)]
1954 heads = [repo[h] for h in repo.heads(start)]
1940 else:
1955 else:
1941 heads = []
1956 heads = []
1942 for b, ls in repo.branchmap().iteritems():
1957 for b, ls in repo.branchmap().iteritems():
1943 if start is None:
1958 if start is None:
1944 heads += [repo[h] for h in ls]
1959 heads += [repo[h] for h in ls]
1945 continue
1960 continue
1946 startrev = repo.changelog.rev(start)
1961 startrev = repo.changelog.rev(start)
1947 descendants = set(repo.changelog.descendants(startrev))
1962 descendants = set(repo.changelog.descendants(startrev))
1948 descendants.add(startrev)
1963 descendants.add(startrev)
1949 rev = repo.changelog.rev
1964 rev = repo.changelog.rev
1950 heads += [repo[h] for h in ls if rev(h) in descendants]
1965 heads += [repo[h] for h in ls if rev(h) in descendants]
1951
1966
1952 if branchrevs:
1967 if branchrevs:
1953 branches = set(repo[br].branch() for br in branchrevs)
1968 branches = set(repo[br].branch() for br in branchrevs)
1954 heads = [h for h in heads if h.branch() in branches]
1969 heads = [h for h in heads if h.branch() in branches]
1955
1970
1956 if not opts.get('closed'):
1971 if not opts.get('closed'):
1957 heads = [h for h in heads if not h.extra().get('close')]
1972 heads = [h for h in heads if not h.extra().get('close')]
1958
1973
1959 if opts.get('active') and branchrevs:
1974 if opts.get('active') and branchrevs:
1960 dagheads = repo.heads(start)
1975 dagheads = repo.heads(start)
1961 heads = [h for h in heads if h.node() in dagheads]
1976 heads = [h for h in heads if h.node() in dagheads]
1962
1977
1963 if branchrevs:
1978 if branchrevs:
1964 haveheads = set(h.branch() for h in heads)
1979 haveheads = set(h.branch() for h in heads)
1965 if branches - haveheads:
1980 if branches - haveheads:
1966 headless = ', '.join(b for b in branches - haveheads)
1981 headless = ', '.join(b for b in branches - haveheads)
1967 msg = _('no open branch heads found on branches %s')
1982 msg = _('no open branch heads found on branches %s')
1968 if opts.get('rev'):
1983 if opts.get('rev'):
1969 msg += _(' (started at %s)' % opts['rev'])
1984 msg += _(' (started at %s)' % opts['rev'])
1970 ui.warn((msg + '\n') % headless)
1985 ui.warn((msg + '\n') % headless)
1971
1986
1972 if not heads:
1987 if not heads:
1973 return 1
1988 return 1
1974
1989
1975 heads = sorted(heads, key=lambda x: -x.rev())
1990 heads = sorted(heads, key=lambda x: -x.rev())
1976 displayer = cmdutil.show_changeset(ui, repo, opts)
1991 displayer = cmdutil.show_changeset(ui, repo, opts)
1977 for ctx in heads:
1992 for ctx in heads:
1978 displayer.show(ctx)
1993 displayer.show(ctx)
1979 displayer.close()
1994 displayer.close()
1980
1995
1981 def help_(ui, name=None, with_version=False, unknowncmd=False):
1996 def help_(ui, name=None, with_version=False, unknowncmd=False):
1982 """show help for a given topic or a help overview
1997 """show help for a given topic or a help overview
1983
1998
1984 With no arguments, print a list of commands with short help messages.
1999 With no arguments, print a list of commands with short help messages.
1985
2000
1986 Given a topic, extension, or command name, print help for that
2001 Given a topic, extension, or command name, print help for that
1987 topic.
2002 topic.
1988
2003
1989 Returns 0 if successful.
2004 Returns 0 if successful.
1990 """
2005 """
1991 option_lists = []
2006 option_lists = []
1992 textwidth = min(ui.termwidth(), 80) - 2
2007 textwidth = min(ui.termwidth(), 80) - 2
1993
2008
1994 def addglobalopts(aliases):
2009 def addglobalopts(aliases):
1995 if ui.verbose:
2010 if ui.verbose:
1996 option_lists.append((_("global options:"), globalopts))
2011 option_lists.append((_("global options:"), globalopts))
1997 if name == 'shortlist':
2012 if name == 'shortlist':
1998 option_lists.append((_('use "hg help" for the full list '
2013 option_lists.append((_('use "hg help" for the full list '
1999 'of commands'), ()))
2014 'of commands'), ()))
2000 else:
2015 else:
2001 if name == 'shortlist':
2016 if name == 'shortlist':
2002 msg = _('use "hg help" for the full list of commands '
2017 msg = _('use "hg help" for the full list of commands '
2003 'or "hg -v" for details')
2018 'or "hg -v" for details')
2004 elif aliases:
2019 elif aliases:
2005 msg = _('use "hg -v help%s" to show builtin aliases and '
2020 msg = _('use "hg -v help%s" to show builtin aliases and '
2006 'global options') % (name and " " + name or "")
2021 'global options') % (name and " " + name or "")
2007 else:
2022 else:
2008 msg = _('use "hg -v help %s" to show global options') % name
2023 msg = _('use "hg -v help %s" to show global options') % name
2009 option_lists.append((msg, ()))
2024 option_lists.append((msg, ()))
2010
2025
2011 def helpcmd(name):
2026 def helpcmd(name):
2012 if with_version:
2027 if with_version:
2013 version_(ui)
2028 version_(ui)
2014 ui.write('\n')
2029 ui.write('\n')
2015
2030
2016 try:
2031 try:
2017 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2032 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2018 except error.AmbiguousCommand, inst:
2033 except error.AmbiguousCommand, inst:
2019 # py3k fix: except vars can't be used outside the scope of the
2034 # py3k fix: except vars can't be used outside the scope of the
2020 # except block, nor can be used inside a lambda. python issue4617
2035 # except block, nor can be used inside a lambda. python issue4617
2021 prefix = inst.args[0]
2036 prefix = inst.args[0]
2022 select = lambda c: c.lstrip('^').startswith(prefix)
2037 select = lambda c: c.lstrip('^').startswith(prefix)
2023 helplist(_('list of commands:\n\n'), select)
2038 helplist(_('list of commands:\n\n'), select)
2024 return
2039 return
2025
2040
2026 # check if it's an invalid alias and display its error if it is
2041 # check if it's an invalid alias and display its error if it is
2027 if getattr(entry[0], 'badalias', False):
2042 if getattr(entry[0], 'badalias', False):
2028 if not unknowncmd:
2043 if not unknowncmd:
2029 entry[0](ui)
2044 entry[0](ui)
2030 return
2045 return
2031
2046
2032 # synopsis
2047 # synopsis
2033 if len(entry) > 2:
2048 if len(entry) > 2:
2034 if entry[2].startswith('hg'):
2049 if entry[2].startswith('hg'):
2035 ui.write("%s\n" % entry[2])
2050 ui.write("%s\n" % entry[2])
2036 else:
2051 else:
2037 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2052 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2038 else:
2053 else:
2039 ui.write('hg %s\n' % aliases[0])
2054 ui.write('hg %s\n' % aliases[0])
2040
2055
2041 # aliases
2056 # aliases
2042 if not ui.quiet and len(aliases) > 1:
2057 if not ui.quiet and len(aliases) > 1:
2043 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2058 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2044
2059
2045 # description
2060 # description
2046 doc = gettext(entry[0].__doc__)
2061 doc = gettext(entry[0].__doc__)
2047 if not doc:
2062 if not doc:
2048 doc = _("(no help text available)")
2063 doc = _("(no help text available)")
2049 if hasattr(entry[0], 'definition'): # aliased command
2064 if hasattr(entry[0], 'definition'): # aliased command
2050 if entry[0].definition.startswith('!'): # shell alias
2065 if entry[0].definition.startswith('!'): # shell alias
2051 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2066 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2052 else:
2067 else:
2053 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2068 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2054 if ui.quiet:
2069 if ui.quiet:
2055 doc = doc.splitlines()[0]
2070 doc = doc.splitlines()[0]
2056 keep = ui.verbose and ['verbose'] or []
2071 keep = ui.verbose and ['verbose'] or []
2057 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2072 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2058 ui.write("\n%s\n" % formatted)
2073 ui.write("\n%s\n" % formatted)
2059 if pruned:
2074 if pruned:
2060 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2075 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2061
2076
2062 if not ui.quiet:
2077 if not ui.quiet:
2063 # options
2078 # options
2064 if entry[1]:
2079 if entry[1]:
2065 option_lists.append((_("options:\n"), entry[1]))
2080 option_lists.append((_("options:\n"), entry[1]))
2066
2081
2067 addglobalopts(False)
2082 addglobalopts(False)
2068
2083
2069 def helplist(header, select=None):
2084 def helplist(header, select=None):
2070 h = {}
2085 h = {}
2071 cmds = {}
2086 cmds = {}
2072 for c, e in table.iteritems():
2087 for c, e in table.iteritems():
2073 f = c.split("|", 1)[0]
2088 f = c.split("|", 1)[0]
2074 if select and not select(f):
2089 if select and not select(f):
2075 continue
2090 continue
2076 if (not select and name != 'shortlist' and
2091 if (not select and name != 'shortlist' and
2077 e[0].__module__ != __name__):
2092 e[0].__module__ != __name__):
2078 continue
2093 continue
2079 if name == "shortlist" and not f.startswith("^"):
2094 if name == "shortlist" and not f.startswith("^"):
2080 continue
2095 continue
2081 f = f.lstrip("^")
2096 f = f.lstrip("^")
2082 if not ui.debugflag and f.startswith("debug"):
2097 if not ui.debugflag and f.startswith("debug"):
2083 continue
2098 continue
2084 doc = e[0].__doc__
2099 doc = e[0].__doc__
2085 if doc and 'DEPRECATED' in doc and not ui.verbose:
2100 if doc and 'DEPRECATED' in doc and not ui.verbose:
2086 continue
2101 continue
2087 doc = gettext(doc)
2102 doc = gettext(doc)
2088 if not doc:
2103 if not doc:
2089 doc = _("(no help text available)")
2104 doc = _("(no help text available)")
2090 h[f] = doc.splitlines()[0].rstrip()
2105 h[f] = doc.splitlines()[0].rstrip()
2091 cmds[f] = c.lstrip("^")
2106 cmds[f] = c.lstrip("^")
2092
2107
2093 if not h:
2108 if not h:
2094 ui.status(_('no commands defined\n'))
2109 ui.status(_('no commands defined\n'))
2095 return
2110 return
2096
2111
2097 ui.status(header)
2112 ui.status(header)
2098 fns = sorted(h)
2113 fns = sorted(h)
2099 m = max(map(len, fns))
2114 m = max(map(len, fns))
2100 for f in fns:
2115 for f in fns:
2101 if ui.verbose:
2116 if ui.verbose:
2102 commands = cmds[f].replace("|",", ")
2117 commands = cmds[f].replace("|",", ")
2103 ui.write(" %s:\n %s\n"%(commands, h[f]))
2118 ui.write(" %s:\n %s\n"%(commands, h[f]))
2104 else:
2119 else:
2105 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2120 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2106 initindent=' %-*s ' % (m, f),
2121 initindent=' %-*s ' % (m, f),
2107 hangindent=' ' * (m + 4))))
2122 hangindent=' ' * (m + 4))))
2108
2123
2109 if not ui.quiet:
2124 if not ui.quiet:
2110 addglobalopts(True)
2125 addglobalopts(True)
2111
2126
2112 def helptopic(name):
2127 def helptopic(name):
2113 for names, header, doc in help.helptable:
2128 for names, header, doc in help.helptable:
2114 if name in names:
2129 if name in names:
2115 break
2130 break
2116 else:
2131 else:
2117 raise error.UnknownCommand(name)
2132 raise error.UnknownCommand(name)
2118
2133
2119 # description
2134 # description
2120 if not doc:
2135 if not doc:
2121 doc = _("(no help text available)")
2136 doc = _("(no help text available)")
2122 if hasattr(doc, '__call__'):
2137 if hasattr(doc, '__call__'):
2123 doc = doc()
2138 doc = doc()
2124
2139
2125 ui.write("%s\n\n" % header)
2140 ui.write("%s\n\n" % header)
2126 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2141 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2127
2142
2128 def helpext(name):
2143 def helpext(name):
2129 try:
2144 try:
2130 mod = extensions.find(name)
2145 mod = extensions.find(name)
2131 doc = gettext(mod.__doc__) or _('no help text available')
2146 doc = gettext(mod.__doc__) or _('no help text available')
2132 except KeyError:
2147 except KeyError:
2133 mod = None
2148 mod = None
2134 doc = extensions.disabledext(name)
2149 doc = extensions.disabledext(name)
2135 if not doc:
2150 if not doc:
2136 raise error.UnknownCommand(name)
2151 raise error.UnknownCommand(name)
2137
2152
2138 if '\n' not in doc:
2153 if '\n' not in doc:
2139 head, tail = doc, ""
2154 head, tail = doc, ""
2140 else:
2155 else:
2141 head, tail = doc.split('\n', 1)
2156 head, tail = doc.split('\n', 1)
2142 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2157 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2143 if tail:
2158 if tail:
2144 ui.write(minirst.format(tail, textwidth))
2159 ui.write(minirst.format(tail, textwidth))
2145 ui.status('\n\n')
2160 ui.status('\n\n')
2146
2161
2147 if mod:
2162 if mod:
2148 try:
2163 try:
2149 ct = mod.cmdtable
2164 ct = mod.cmdtable
2150 except AttributeError:
2165 except AttributeError:
2151 ct = {}
2166 ct = {}
2152 modcmds = set([c.split('|', 1)[0] for c in ct])
2167 modcmds = set([c.split('|', 1)[0] for c in ct])
2153 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2168 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2154 else:
2169 else:
2155 ui.write(_('use "hg help extensions" for information on enabling '
2170 ui.write(_('use "hg help extensions" for information on enabling '
2156 'extensions\n'))
2171 'extensions\n'))
2157
2172
2158 def helpextcmd(name):
2173 def helpextcmd(name):
2159 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2174 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2160 doc = gettext(mod.__doc__).splitlines()[0]
2175 doc = gettext(mod.__doc__).splitlines()[0]
2161
2176
2162 msg = help.listexts(_("'%s' is provided by the following "
2177 msg = help.listexts(_("'%s' is provided by the following "
2163 "extension:") % cmd, {ext: doc}, len(ext),
2178 "extension:") % cmd, {ext: doc}, len(ext),
2164 indent=4)
2179 indent=4)
2165 ui.write(minirst.format(msg, textwidth))
2180 ui.write(minirst.format(msg, textwidth))
2166 ui.write('\n\n')
2181 ui.write('\n\n')
2167 ui.write(_('use "hg help extensions" for information on enabling '
2182 ui.write(_('use "hg help extensions" for information on enabling '
2168 'extensions\n'))
2183 'extensions\n'))
2169
2184
2170 help.addtopichook('revsets', revset.makedoc)
2185 help.addtopichook('revsets', revset.makedoc)
2171 help.addtopichook('templates', templatekw.makedoc)
2186 help.addtopichook('templates', templatekw.makedoc)
2172 help.addtopichook('templates', templatefilters.makedoc)
2187 help.addtopichook('templates', templatefilters.makedoc)
2173
2188
2174 if name and name != 'shortlist':
2189 if name and name != 'shortlist':
2175 i = None
2190 i = None
2176 if unknowncmd:
2191 if unknowncmd:
2177 queries = (helpextcmd,)
2192 queries = (helpextcmd,)
2178 else:
2193 else:
2179 queries = (helptopic, helpcmd, helpext, helpextcmd)
2194 queries = (helptopic, helpcmd, helpext, helpextcmd)
2180 for f in queries:
2195 for f in queries:
2181 try:
2196 try:
2182 f(name)
2197 f(name)
2183 i = None
2198 i = None
2184 break
2199 break
2185 except error.UnknownCommand, inst:
2200 except error.UnknownCommand, inst:
2186 i = inst
2201 i = inst
2187 if i:
2202 if i:
2188 raise i
2203 raise i
2189
2204
2190 else:
2205 else:
2191 # program name
2206 # program name
2192 if ui.verbose or with_version:
2207 if ui.verbose or with_version:
2193 version_(ui)
2208 version_(ui)
2194 else:
2209 else:
2195 ui.status(_("Mercurial Distributed SCM\n"))
2210 ui.status(_("Mercurial Distributed SCM\n"))
2196 ui.status('\n')
2211 ui.status('\n')
2197
2212
2198 # list of commands
2213 # list of commands
2199 if name == "shortlist":
2214 if name == "shortlist":
2200 header = _('basic commands:\n\n')
2215 header = _('basic commands:\n\n')
2201 else:
2216 else:
2202 header = _('list of commands:\n\n')
2217 header = _('list of commands:\n\n')
2203
2218
2204 helplist(header)
2219 helplist(header)
2205 if name != 'shortlist':
2220 if name != 'shortlist':
2206 exts, maxlength = extensions.enabled()
2221 exts, maxlength = extensions.enabled()
2207 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2222 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2208 if text:
2223 if text:
2209 ui.write("\n%s\n" % minirst.format(text, textwidth))
2224 ui.write("\n%s\n" % minirst.format(text, textwidth))
2210
2225
2211 # list all option lists
2226 # list all option lists
2212 opt_output = []
2227 opt_output = []
2213 multioccur = False
2228 multioccur = False
2214 for title, options in option_lists:
2229 for title, options in option_lists:
2215 opt_output.append(("\n%s" % title, None))
2230 opt_output.append(("\n%s" % title, None))
2216 for option in options:
2231 for option in options:
2217 if len(option) == 5:
2232 if len(option) == 5:
2218 shortopt, longopt, default, desc, optlabel = option
2233 shortopt, longopt, default, desc, optlabel = option
2219 else:
2234 else:
2220 shortopt, longopt, default, desc = option
2235 shortopt, longopt, default, desc = option
2221 optlabel = _("VALUE") # default label
2236 optlabel = _("VALUE") # default label
2222
2237
2223 if _("DEPRECATED") in desc and not ui.verbose:
2238 if _("DEPRECATED") in desc and not ui.verbose:
2224 continue
2239 continue
2225 if isinstance(default, list):
2240 if isinstance(default, list):
2226 numqualifier = " %s [+]" % optlabel
2241 numqualifier = " %s [+]" % optlabel
2227 multioccur = True
2242 multioccur = True
2228 elif (default is not None) and not isinstance(default, bool):
2243 elif (default is not None) and not isinstance(default, bool):
2229 numqualifier = " %s" % optlabel
2244 numqualifier = " %s" % optlabel
2230 else:
2245 else:
2231 numqualifier = ""
2246 numqualifier = ""
2232 opt_output.append(("%2s%s" %
2247 opt_output.append(("%2s%s" %
2233 (shortopt and "-%s" % shortopt,
2248 (shortopt and "-%s" % shortopt,
2234 longopt and " --%s%s" %
2249 longopt and " --%s%s" %
2235 (longopt, numqualifier)),
2250 (longopt, numqualifier)),
2236 "%s%s" % (desc,
2251 "%s%s" % (desc,
2237 default
2252 default
2238 and _(" (default: %s)") % default
2253 and _(" (default: %s)") % default
2239 or "")))
2254 or "")))
2240 if multioccur:
2255 if multioccur:
2241 msg = _("\n[+] marked option can be specified multiple times")
2256 msg = _("\n[+] marked option can be specified multiple times")
2242 if ui.verbose and name != 'shortlist':
2257 if ui.verbose and name != 'shortlist':
2243 opt_output.append((msg, None))
2258 opt_output.append((msg, None))
2244 else:
2259 else:
2245 opt_output.insert(-1, (msg, None))
2260 opt_output.insert(-1, (msg, None))
2246
2261
2247 if not name:
2262 if not name:
2248 ui.write(_("\nadditional help topics:\n\n"))
2263 ui.write(_("\nadditional help topics:\n\n"))
2249 topics = []
2264 topics = []
2250 for names, header, doc in help.helptable:
2265 for names, header, doc in help.helptable:
2251 topics.append((sorted(names, key=len, reverse=True)[0], header))
2266 topics.append((sorted(names, key=len, reverse=True)[0], header))
2252 topics_len = max([len(s[0]) for s in topics])
2267 topics_len = max([len(s[0]) for s in topics])
2253 for t, desc in topics:
2268 for t, desc in topics:
2254 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2269 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2255
2270
2256 if opt_output:
2271 if opt_output:
2257 colwidth = encoding.colwidth
2272 colwidth = encoding.colwidth
2258 # normalize: (opt or message, desc or None, width of opt)
2273 # normalize: (opt or message, desc or None, width of opt)
2259 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2274 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2260 for opt, desc in opt_output]
2275 for opt, desc in opt_output]
2261 hanging = max([e[2] for e in entries])
2276 hanging = max([e[2] for e in entries])
2262 for opt, desc, width in entries:
2277 for opt, desc, width in entries:
2263 if desc:
2278 if desc:
2264 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2279 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2265 hangindent = ' ' * (hanging + 3)
2280 hangindent = ' ' * (hanging + 3)
2266 ui.write('%s\n' % (util.wrap(desc, textwidth,
2281 ui.write('%s\n' % (util.wrap(desc, textwidth,
2267 initindent=initindent,
2282 initindent=initindent,
2268 hangindent=hangindent)))
2283 hangindent=hangindent)))
2269 else:
2284 else:
2270 ui.write("%s\n" % opt)
2285 ui.write("%s\n" % opt)
2271
2286
2272 def identify(ui, repo, source=None, rev=None,
2287 def identify(ui, repo, source=None, rev=None,
2273 num=None, id=None, branch=None, tags=None, bookmarks=None):
2288 num=None, id=None, branch=None, tags=None, bookmarks=None):
2274 """identify the working copy or specified revision
2289 """identify the working copy or specified revision
2275
2290
2276 With no revision, print a summary of the current state of the
2291 With no revision, print a summary of the current state of the
2277 repository.
2292 repository.
2278
2293
2279 Specifying a path to a repository root or Mercurial bundle will
2294 Specifying a path to a repository root or Mercurial bundle will
2280 cause lookup to operate on that repository/bundle.
2295 cause lookup to operate on that repository/bundle.
2281
2296
2282 This summary identifies the repository state using one or two
2297 This summary identifies the repository state using one or two
2283 parent hash identifiers, followed by a "+" if there are
2298 parent hash identifiers, followed by a "+" if there are
2284 uncommitted changes in the working directory, a list of tags for
2299 uncommitted changes in the working directory, a list of tags for
2285 this revision and a branch name for non-default branches.
2300 this revision and a branch name for non-default branches.
2286
2301
2287 Returns 0 if successful.
2302 Returns 0 if successful.
2288 """
2303 """
2289
2304
2290 if not repo and not source:
2305 if not repo and not source:
2291 raise util.Abort(_("there is no Mercurial repository here "
2306 raise util.Abort(_("there is no Mercurial repository here "
2292 "(.hg not found)"))
2307 "(.hg not found)"))
2293
2308
2294 hexfunc = ui.debugflag and hex or short
2309 hexfunc = ui.debugflag and hex or short
2295 default = not (num or id or branch or tags or bookmarks)
2310 default = not (num or id or branch or tags or bookmarks)
2296 output = []
2311 output = []
2297
2312
2298 revs = []
2313 revs = []
2299 bms = []
2314 bms = []
2300 if source:
2315 if source:
2301 source, branches = hg.parseurl(ui.expandpath(source))
2316 source, branches = hg.parseurl(ui.expandpath(source))
2302 repo = hg.repository(ui, source)
2317 repo = hg.repository(ui, source)
2303 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2318 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2304
2319
2305 if not repo.local():
2320 if not repo.local():
2306 if not rev and revs:
2321 if not rev and revs:
2307 rev = revs[0]
2322 rev = revs[0]
2308 if not rev:
2323 if not rev:
2309 rev = "tip"
2324 rev = "tip"
2310 if num or branch or tags:
2325 if num or branch or tags:
2311 raise util.Abort(
2326 raise util.Abort(
2312 _("can't query remote revision number, branch, or tags"))
2327 _("can't query remote revision number, branch, or tags"))
2313
2328
2314 remoterev = repo.lookup(rev)
2329 remoterev = repo.lookup(rev)
2315 if default or id:
2330 if default or id:
2316 output = [hexfunc(remoterev)]
2331 output = [hexfunc(remoterev)]
2317
2332
2318 if 'bookmarks' in repo.listkeys('namespaces'):
2333 if 'bookmarks' in repo.listkeys('namespaces'):
2319 hexremoterev = hex(remoterev)
2334 hexremoterev = hex(remoterev)
2320 bms = [bm for bm, bmrev in repo.listkeys('bookmarks').iteritems()
2335 bms = [bm for bm, bmrev in repo.listkeys('bookmarks').iteritems()
2321 if bmrev == hexremoterev]
2336 if bmrev == hexremoterev]
2322
2337
2323 elif not rev:
2338 elif not rev:
2324 ctx = repo[None]
2339 ctx = repo[None]
2325 parents = ctx.parents()
2340 parents = ctx.parents()
2326 changed = False
2341 changed = False
2327 if default or id or num:
2342 if default or id or num:
2328 changed = util.any(repo.status())
2343 changed = util.any(repo.status())
2329 if default or id:
2344 if default or id:
2330 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2345 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2331 (changed) and "+" or "")]
2346 (changed) and "+" or "")]
2332 if num:
2347 if num:
2333 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2348 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2334 (changed) and "+" or ""))
2349 (changed) and "+" or ""))
2335 else:
2350 else:
2336 ctx = cmdutil.revsingle(repo, rev)
2351 ctx = cmdutil.revsingle(repo, rev)
2337 if default or id:
2352 if default or id:
2338 output = [hexfunc(ctx.node())]
2353 output = [hexfunc(ctx.node())]
2339 if num:
2354 if num:
2340 output.append(str(ctx.rev()))
2355 output.append(str(ctx.rev()))
2341
2356
2342 if repo.local():
2357 if repo.local():
2343 bms = ctx.bookmarks()
2358 bms = ctx.bookmarks()
2344
2359
2345 if repo.local() and default and not ui.quiet:
2360 if repo.local() and default and not ui.quiet:
2346 b = ctx.branch()
2361 b = ctx.branch()
2347 if b != 'default':
2362 if b != 'default':
2348 output.append("(%s)" % b)
2363 output.append("(%s)" % b)
2349
2364
2350 # multiple tags for a single parent separated by '/'
2365 # multiple tags for a single parent separated by '/'
2351 t = "/".join(ctx.tags())
2366 t = "/".join(ctx.tags())
2352 if t:
2367 if t:
2353 output.append(t)
2368 output.append(t)
2354
2369
2355 if default and not ui.quiet:
2370 if default and not ui.quiet:
2356 # multiple bookmarks for a single parent separated by '/'
2371 # multiple bookmarks for a single parent separated by '/'
2357 bm = '/'.join(bms)
2372 bm = '/'.join(bms)
2358 if bm:
2373 if bm:
2359 output.append(bm)
2374 output.append(bm)
2360
2375
2361 if branch:
2376 if branch:
2362 output.append(ctx.branch())
2377 output.append(ctx.branch())
2363
2378
2364 if tags:
2379 if tags:
2365 output.extend(ctx.tags())
2380 output.extend(ctx.tags())
2366
2381
2367 if bookmarks:
2382 if bookmarks:
2368 output.extend(bms)
2383 output.extend(bms)
2369
2384
2370 ui.write("%s\n" % ' '.join(output))
2385 ui.write("%s\n" % ' '.join(output))
2371
2386
2372 def import_(ui, repo, patch1, *patches, **opts):
2387 def import_(ui, repo, patch1, *patches, **opts):
2373 """import an ordered set of patches
2388 """import an ordered set of patches
2374
2389
2375 Import a list of patches and commit them individually (unless
2390 Import a list of patches and commit them individually (unless
2376 --no-commit is specified).
2391 --no-commit is specified).
2377
2392
2378 If there are outstanding changes in the working directory, import
2393 If there are outstanding changes in the working directory, import
2379 will abort unless given the -f/--force flag.
2394 will abort unless given the -f/--force flag.
2380
2395
2381 You can import a patch straight from a mail message. Even patches
2396 You can import a patch straight from a mail message. Even patches
2382 as attachments work (to use the body part, it must have type
2397 as attachments work (to use the body part, it must have type
2383 text/plain or text/x-patch). From and Subject headers of email
2398 text/plain or text/x-patch). From and Subject headers of email
2384 message are used as default committer and commit message. All
2399 message are used as default committer and commit message. All
2385 text/plain body parts before first diff are added to commit
2400 text/plain body parts before first diff are added to commit
2386 message.
2401 message.
2387
2402
2388 If the imported patch was generated by :hg:`export`, user and
2403 If the imported patch was generated by :hg:`export`, user and
2389 description from patch override values from message headers and
2404 description from patch override values from message headers and
2390 body. Values given on command line with -m/--message and -u/--user
2405 body. Values given on command line with -m/--message and -u/--user
2391 override these.
2406 override these.
2392
2407
2393 If --exact is specified, import will set the working directory to
2408 If --exact is specified, import will set the working directory to
2394 the parent of each patch before applying it, and will abort if the
2409 the parent of each patch before applying it, and will abort if the
2395 resulting changeset has a different ID than the one recorded in
2410 resulting changeset has a different ID than the one recorded in
2396 the patch. This may happen due to character set problems or other
2411 the patch. This may happen due to character set problems or other
2397 deficiencies in the text patch format.
2412 deficiencies in the text patch format.
2398
2413
2399 With -s/--similarity, hg will attempt to discover renames and
2414 With -s/--similarity, hg will attempt to discover renames and
2400 copies in the patch in the same way as 'addremove'.
2415 copies in the patch in the same way as 'addremove'.
2401
2416
2402 To read a patch from standard input, use "-" as the patch name. If
2417 To read a patch from standard input, use "-" as the patch name. If
2403 a URL is specified, the patch will be downloaded from it.
2418 a URL is specified, the patch will be downloaded from it.
2404 See :hg:`help dates` for a list of formats valid for -d/--date.
2419 See :hg:`help dates` for a list of formats valid for -d/--date.
2405
2420
2406 Returns 0 on success.
2421 Returns 0 on success.
2407 """
2422 """
2408 patches = (patch1,) + patches
2423 patches = (patch1,) + patches
2409
2424
2410 date = opts.get('date')
2425 date = opts.get('date')
2411 if date:
2426 if date:
2412 opts['date'] = util.parsedate(date)
2427 opts['date'] = util.parsedate(date)
2413
2428
2414 try:
2429 try:
2415 sim = float(opts.get('similarity') or 0)
2430 sim = float(opts.get('similarity') or 0)
2416 except ValueError:
2431 except ValueError:
2417 raise util.Abort(_('similarity must be a number'))
2432 raise util.Abort(_('similarity must be a number'))
2418 if sim < 0 or sim > 100:
2433 if sim < 0 or sim > 100:
2419 raise util.Abort(_('similarity must be between 0 and 100'))
2434 raise util.Abort(_('similarity must be between 0 and 100'))
2420
2435
2421 if opts.get('exact') or not opts.get('force'):
2436 if opts.get('exact') or not opts.get('force'):
2422 cmdutil.bail_if_changed(repo)
2437 cmdutil.bail_if_changed(repo)
2423
2438
2424 d = opts["base"]
2439 d = opts["base"]
2425 strip = opts["strip"]
2440 strip = opts["strip"]
2426 wlock = lock = None
2441 wlock = lock = None
2427 msgs = []
2442 msgs = []
2428
2443
2429 def tryone(ui, hunk):
2444 def tryone(ui, hunk):
2430 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2445 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2431 patch.extract(ui, hunk)
2446 patch.extract(ui, hunk)
2432
2447
2433 if not tmpname:
2448 if not tmpname:
2434 return None
2449 return None
2435 commitid = _('to working directory')
2450 commitid = _('to working directory')
2436
2451
2437 try:
2452 try:
2438 cmdline_message = cmdutil.logmessage(opts)
2453 cmdline_message = cmdutil.logmessage(opts)
2439 if cmdline_message:
2454 if cmdline_message:
2440 # pickup the cmdline msg
2455 # pickup the cmdline msg
2441 message = cmdline_message
2456 message = cmdline_message
2442 elif message:
2457 elif message:
2443 # pickup the patch msg
2458 # pickup the patch msg
2444 message = message.strip()
2459 message = message.strip()
2445 else:
2460 else:
2446 # launch the editor
2461 # launch the editor
2447 message = None
2462 message = None
2448 ui.debug('message:\n%s\n' % message)
2463 ui.debug('message:\n%s\n' % message)
2449
2464
2450 wp = repo.parents()
2465 wp = repo.parents()
2451 if opts.get('exact'):
2466 if opts.get('exact'):
2452 if not nodeid or not p1:
2467 if not nodeid or not p1:
2453 raise util.Abort(_('not a Mercurial patch'))
2468 raise util.Abort(_('not a Mercurial patch'))
2454 p1 = repo.lookup(p1)
2469 p1 = repo.lookup(p1)
2455 p2 = repo.lookup(p2 or hex(nullid))
2470 p2 = repo.lookup(p2 or hex(nullid))
2456
2471
2457 if p1 != wp[0].node():
2472 if p1 != wp[0].node():
2458 hg.clean(repo, p1)
2473 hg.clean(repo, p1)
2459 repo.dirstate.setparents(p1, p2)
2474 repo.dirstate.setparents(p1, p2)
2460 elif p2:
2475 elif p2:
2461 try:
2476 try:
2462 p1 = repo.lookup(p1)
2477 p1 = repo.lookup(p1)
2463 p2 = repo.lookup(p2)
2478 p2 = repo.lookup(p2)
2464 if p1 == wp[0].node():
2479 if p1 == wp[0].node():
2465 repo.dirstate.setparents(p1, p2)
2480 repo.dirstate.setparents(p1, p2)
2466 except error.RepoError:
2481 except error.RepoError:
2467 pass
2482 pass
2468 if opts.get('exact') or opts.get('import_branch'):
2483 if opts.get('exact') or opts.get('import_branch'):
2469 repo.dirstate.setbranch(branch or 'default')
2484 repo.dirstate.setbranch(branch or 'default')
2470
2485
2471 files = {}
2486 files = {}
2472 try:
2487 try:
2473 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2488 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2474 files=files, eolmode=None)
2489 files=files, eolmode=None)
2475 finally:
2490 finally:
2476 files = cmdutil.updatedir(ui, repo, files,
2491 files = cmdutil.updatedir(ui, repo, files,
2477 similarity=sim / 100.0)
2492 similarity=sim / 100.0)
2478 if opts.get('no_commit'):
2493 if opts.get('no_commit'):
2479 if message:
2494 if message:
2480 msgs.append(message)
2495 msgs.append(message)
2481 else:
2496 else:
2482 if opts.get('exact'):
2497 if opts.get('exact'):
2483 m = None
2498 m = None
2484 else:
2499 else:
2485 m = cmdutil.matchfiles(repo, files or [])
2500 m = cmdutil.matchfiles(repo, files or [])
2486 n = repo.commit(message, opts.get('user') or user,
2501 n = repo.commit(message, opts.get('user') or user,
2487 opts.get('date') or date, match=m,
2502 opts.get('date') or date, match=m,
2488 editor=cmdutil.commiteditor)
2503 editor=cmdutil.commiteditor)
2489 if opts.get('exact'):
2504 if opts.get('exact'):
2490 if hex(n) != nodeid:
2505 if hex(n) != nodeid:
2491 repo.rollback()
2506 repo.rollback()
2492 raise util.Abort(_('patch is damaged'
2507 raise util.Abort(_('patch is damaged'
2493 ' or loses information'))
2508 ' or loses information'))
2494 # Force a dirstate write so that the next transaction
2509 # Force a dirstate write so that the next transaction
2495 # backups an up-do-date file.
2510 # backups an up-do-date file.
2496 repo.dirstate.write()
2511 repo.dirstate.write()
2497 if n:
2512 if n:
2498 commitid = short(n)
2513 commitid = short(n)
2499
2514
2500 return commitid
2515 return commitid
2501 finally:
2516 finally:
2502 os.unlink(tmpname)
2517 os.unlink(tmpname)
2503
2518
2504 try:
2519 try:
2505 wlock = repo.wlock()
2520 wlock = repo.wlock()
2506 lock = repo.lock()
2521 lock = repo.lock()
2507 lastcommit = None
2522 lastcommit = None
2508 for p in patches:
2523 for p in patches:
2509 pf = os.path.join(d, p)
2524 pf = os.path.join(d, p)
2510
2525
2511 if pf == '-':
2526 if pf == '-':
2512 ui.status(_("applying patch from stdin\n"))
2527 ui.status(_("applying patch from stdin\n"))
2513 pf = sys.stdin
2528 pf = sys.stdin
2514 else:
2529 else:
2515 ui.status(_("applying %s\n") % p)
2530 ui.status(_("applying %s\n") % p)
2516 pf = url.open(ui, pf)
2531 pf = url.open(ui, pf)
2517
2532
2518 haspatch = False
2533 haspatch = False
2519 for hunk in patch.split(pf):
2534 for hunk in patch.split(pf):
2520 commitid = tryone(ui, hunk)
2535 commitid = tryone(ui, hunk)
2521 if commitid:
2536 if commitid:
2522 haspatch = True
2537 haspatch = True
2523 if lastcommit:
2538 if lastcommit:
2524 ui.status(_('applied %s\n') % lastcommit)
2539 ui.status(_('applied %s\n') % lastcommit)
2525 lastcommit = commitid
2540 lastcommit = commitid
2526
2541
2527 if not haspatch:
2542 if not haspatch:
2528 raise util.Abort(_('no diffs found'))
2543 raise util.Abort(_('no diffs found'))
2529
2544
2530 if msgs:
2545 if msgs:
2531 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2546 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2532 finally:
2547 finally:
2533 release(lock, wlock)
2548 release(lock, wlock)
2534
2549
2535 def incoming(ui, repo, source="default", **opts):
2550 def incoming(ui, repo, source="default", **opts):
2536 """show new changesets found in source
2551 """show new changesets found in source
2537
2552
2538 Show new changesets found in the specified path/URL or the default
2553 Show new changesets found in the specified path/URL or the default
2539 pull location. These are the changesets that would have been pulled
2554 pull location. These are the changesets that would have been pulled
2540 if a pull at the time you issued this command.
2555 if a pull at the time you issued this command.
2541
2556
2542 For remote repository, using --bundle avoids downloading the
2557 For remote repository, using --bundle avoids downloading the
2543 changesets twice if the incoming is followed by a pull.
2558 changesets twice if the incoming is followed by a pull.
2544
2559
2545 See pull for valid source format details.
2560 See pull for valid source format details.
2546
2561
2547 Returns 0 if there are incoming changes, 1 otherwise.
2562 Returns 0 if there are incoming changes, 1 otherwise.
2548 """
2563 """
2549 if opts.get('bundle') and opts.get('subrepos'):
2564 if opts.get('bundle') and opts.get('subrepos'):
2550 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2565 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2551
2566
2552 if opts.get('bookmarks'):
2567 if opts.get('bookmarks'):
2553 source, branches = hg.parseurl(ui.expandpath(source),
2568 source, branches = hg.parseurl(ui.expandpath(source),
2554 opts.get('branch'))
2569 opts.get('branch'))
2555 other = hg.repository(hg.remoteui(repo, opts), source)
2570 other = hg.repository(hg.remoteui(repo, opts), source)
2556 if 'bookmarks' not in other.listkeys('namespaces'):
2571 if 'bookmarks' not in other.listkeys('namespaces'):
2557 ui.warn(_("remote doesn't support bookmarks\n"))
2572 ui.warn(_("remote doesn't support bookmarks\n"))
2558 return 0
2573 return 0
2559 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2574 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2560 return bookmarks.diff(ui, repo, other)
2575 return bookmarks.diff(ui, repo, other)
2561
2576
2562 ret = hg.incoming(ui, repo, source, opts)
2577 ret = hg.incoming(ui, repo, source, opts)
2563 return ret
2578 return ret
2564
2579
2565 def init(ui, dest=".", **opts):
2580 def init(ui, dest=".", **opts):
2566 """create a new repository in the given directory
2581 """create a new repository in the given directory
2567
2582
2568 Initialize a new repository in the given directory. If the given
2583 Initialize a new repository in the given directory. If the given
2569 directory does not exist, it will be created.
2584 directory does not exist, it will be created.
2570
2585
2571 If no directory is given, the current directory is used.
2586 If no directory is given, the current directory is used.
2572
2587
2573 It is possible to specify an ``ssh://`` URL as the destination.
2588 It is possible to specify an ``ssh://`` URL as the destination.
2574 See :hg:`help urls` for more information.
2589 See :hg:`help urls` for more information.
2575
2590
2576 Returns 0 on success.
2591 Returns 0 on success.
2577 """
2592 """
2578 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2593 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2579
2594
2580 def locate(ui, repo, *pats, **opts):
2595 def locate(ui, repo, *pats, **opts):
2581 """locate files matching specific patterns
2596 """locate files matching specific patterns
2582
2597
2583 Print files under Mercurial control in the working directory whose
2598 Print files under Mercurial control in the working directory whose
2584 names match the given patterns.
2599 names match the given patterns.
2585
2600
2586 By default, this command searches all directories in the working
2601 By default, this command searches all directories in the working
2587 directory. To search just the current directory and its
2602 directory. To search just the current directory and its
2588 subdirectories, use "--include .".
2603 subdirectories, use "--include .".
2589
2604
2590 If no patterns are given to match, this command prints the names
2605 If no patterns are given to match, this command prints the names
2591 of all files under Mercurial control in the working directory.
2606 of all files under Mercurial control in the working directory.
2592
2607
2593 If you want to feed the output of this command into the "xargs"
2608 If you want to feed the output of this command into the "xargs"
2594 command, use the -0 option to both this command and "xargs". This
2609 command, use the -0 option to both this command and "xargs". This
2595 will avoid the problem of "xargs" treating single filenames that
2610 will avoid the problem of "xargs" treating single filenames that
2596 contain whitespace as multiple filenames.
2611 contain whitespace as multiple filenames.
2597
2612
2598 Returns 0 if a match is found, 1 otherwise.
2613 Returns 0 if a match is found, 1 otherwise.
2599 """
2614 """
2600 end = opts.get('print0') and '\0' or '\n'
2615 end = opts.get('print0') and '\0' or '\n'
2601 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2616 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2602
2617
2603 ret = 1
2618 ret = 1
2604 m = cmdutil.match(repo, pats, opts, default='relglob')
2619 m = cmdutil.match(repo, pats, opts, default='relglob')
2605 m.bad = lambda x, y: False
2620 m.bad = lambda x, y: False
2606 for abs in repo[rev].walk(m):
2621 for abs in repo[rev].walk(m):
2607 if not rev and abs not in repo.dirstate:
2622 if not rev and abs not in repo.dirstate:
2608 continue
2623 continue
2609 if opts.get('fullpath'):
2624 if opts.get('fullpath'):
2610 ui.write(repo.wjoin(abs), end)
2625 ui.write(repo.wjoin(abs), end)
2611 else:
2626 else:
2612 ui.write(((pats and m.rel(abs)) or abs), end)
2627 ui.write(((pats and m.rel(abs)) or abs), end)
2613 ret = 0
2628 ret = 0
2614
2629
2615 return ret
2630 return ret
2616
2631
2617 def log(ui, repo, *pats, **opts):
2632 def log(ui, repo, *pats, **opts):
2618 """show revision history of entire repository or files
2633 """show revision history of entire repository or files
2619
2634
2620 Print the revision history of the specified files or the entire
2635 Print the revision history of the specified files or the entire
2621 project.
2636 project.
2622
2637
2623 File history is shown without following rename or copy history of
2638 File history is shown without following rename or copy history of
2624 files. Use -f/--follow with a filename to follow history across
2639 files. Use -f/--follow with a filename to follow history across
2625 renames and copies. --follow without a filename will only show
2640 renames and copies. --follow without a filename will only show
2626 ancestors or descendants of the starting revision. --follow-first
2641 ancestors or descendants of the starting revision. --follow-first
2627 only follows the first parent of merge revisions.
2642 only follows the first parent of merge revisions.
2628
2643
2629 If no revision range is specified, the default is ``tip:0`` unless
2644 If no revision range is specified, the default is ``tip:0`` unless
2630 --follow is set, in which case the working directory parent is
2645 --follow is set, in which case the working directory parent is
2631 used as the starting revision. You can specify a revision set for
2646 used as the starting revision. You can specify a revision set for
2632 log, see :hg:`help revsets` for more information.
2647 log, see :hg:`help revsets` for more information.
2633
2648
2634 See :hg:`help dates` for a list of formats valid for -d/--date.
2649 See :hg:`help dates` for a list of formats valid for -d/--date.
2635
2650
2636 By default this command prints revision number and changeset id,
2651 By default this command prints revision number and changeset id,
2637 tags, non-trivial parents, user, date and time, and a summary for
2652 tags, non-trivial parents, user, date and time, and a summary for
2638 each commit. When the -v/--verbose switch is used, the list of
2653 each commit. When the -v/--verbose switch is used, the list of
2639 changed files and full commit message are shown.
2654 changed files and full commit message are shown.
2640
2655
2641 .. note::
2656 .. note::
2642 log -p/--patch may generate unexpected diff output for merge
2657 log -p/--patch may generate unexpected diff output for merge
2643 changesets, as it will only compare the merge changeset against
2658 changesets, as it will only compare the merge changeset against
2644 its first parent. Also, only files different from BOTH parents
2659 its first parent. Also, only files different from BOTH parents
2645 will appear in files:.
2660 will appear in files:.
2646
2661
2647 Returns 0 on success.
2662 Returns 0 on success.
2648 """
2663 """
2649
2664
2650 matchfn = cmdutil.match(repo, pats, opts)
2665 matchfn = cmdutil.match(repo, pats, opts)
2651 limit = cmdutil.loglimit(opts)
2666 limit = cmdutil.loglimit(opts)
2652 count = 0
2667 count = 0
2653
2668
2654 endrev = None
2669 endrev = None
2655 if opts.get('copies') and opts.get('rev'):
2670 if opts.get('copies') and opts.get('rev'):
2656 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2671 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2657
2672
2658 df = False
2673 df = False
2659 if opts["date"]:
2674 if opts["date"]:
2660 df = util.matchdate(opts["date"])
2675 df = util.matchdate(opts["date"])
2661
2676
2662 branches = opts.get('branch', []) + opts.get('only_branch', [])
2677 branches = opts.get('branch', []) + opts.get('only_branch', [])
2663 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2678 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2664
2679
2665 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2680 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2666 def prep(ctx, fns):
2681 def prep(ctx, fns):
2667 rev = ctx.rev()
2682 rev = ctx.rev()
2668 parents = [p for p in repo.changelog.parentrevs(rev)
2683 parents = [p for p in repo.changelog.parentrevs(rev)
2669 if p != nullrev]
2684 if p != nullrev]
2670 if opts.get('no_merges') and len(parents) == 2:
2685 if opts.get('no_merges') and len(parents) == 2:
2671 return
2686 return
2672 if opts.get('only_merges') and len(parents) != 2:
2687 if opts.get('only_merges') and len(parents) != 2:
2673 return
2688 return
2674 if opts.get('branch') and ctx.branch() not in opts['branch']:
2689 if opts.get('branch') and ctx.branch() not in opts['branch']:
2675 return
2690 return
2676 if df and not df(ctx.date()[0]):
2691 if df and not df(ctx.date()[0]):
2677 return
2692 return
2678 if opts['user'] and not [k for k in opts['user']
2693 if opts['user'] and not [k for k in opts['user']
2679 if k.lower() in ctx.user().lower()]:
2694 if k.lower() in ctx.user().lower()]:
2680 return
2695 return
2681 if opts.get('keyword'):
2696 if opts.get('keyword'):
2682 for k in [kw.lower() for kw in opts['keyword']]:
2697 for k in [kw.lower() for kw in opts['keyword']]:
2683 if (k in ctx.user().lower() or
2698 if (k in ctx.user().lower() or
2684 k in ctx.description().lower() or
2699 k in ctx.description().lower() or
2685 k in " ".join(ctx.files()).lower()):
2700 k in " ".join(ctx.files()).lower()):
2686 break
2701 break
2687 else:
2702 else:
2688 return
2703 return
2689
2704
2690 copies = None
2705 copies = None
2691 if opts.get('copies') and rev:
2706 if opts.get('copies') and rev:
2692 copies = []
2707 copies = []
2693 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2708 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2694 for fn in ctx.files():
2709 for fn in ctx.files():
2695 rename = getrenamed(fn, rev)
2710 rename = getrenamed(fn, rev)
2696 if rename:
2711 if rename:
2697 copies.append((fn, rename[0]))
2712 copies.append((fn, rename[0]))
2698
2713
2699 revmatchfn = None
2714 revmatchfn = None
2700 if opts.get('patch') or opts.get('stat'):
2715 if opts.get('patch') or opts.get('stat'):
2701 if opts.get('follow') or opts.get('follow_first'):
2716 if opts.get('follow') or opts.get('follow_first'):
2702 # note: this might be wrong when following through merges
2717 # note: this might be wrong when following through merges
2703 revmatchfn = cmdutil.match(repo, fns, default='path')
2718 revmatchfn = cmdutil.match(repo, fns, default='path')
2704 else:
2719 else:
2705 revmatchfn = matchfn
2720 revmatchfn = matchfn
2706
2721
2707 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2722 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2708
2723
2709 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2724 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2710 if count == limit:
2725 if count == limit:
2711 break
2726 break
2712 if displayer.flush(ctx.rev()):
2727 if displayer.flush(ctx.rev()):
2713 count += 1
2728 count += 1
2714 displayer.close()
2729 displayer.close()
2715
2730
2716 def manifest(ui, repo, node=None, rev=None):
2731 def manifest(ui, repo, node=None, rev=None):
2717 """output the current or given revision of the project manifest
2732 """output the current or given revision of the project manifest
2718
2733
2719 Print a list of version controlled files for the given revision.
2734 Print a list of version controlled files for the given revision.
2720 If no revision is given, the first parent of the working directory
2735 If no revision is given, the first parent of the working directory
2721 is used, or the null revision if no revision is checked out.
2736 is used, or the null revision if no revision is checked out.
2722
2737
2723 With -v, print file permissions, symlink and executable bits.
2738 With -v, print file permissions, symlink and executable bits.
2724 With --debug, print file revision hashes.
2739 With --debug, print file revision hashes.
2725
2740
2726 Returns 0 on success.
2741 Returns 0 on success.
2727 """
2742 """
2728
2743
2729 if rev and node:
2744 if rev and node:
2730 raise util.Abort(_("please specify just one revision"))
2745 raise util.Abort(_("please specify just one revision"))
2731
2746
2732 if not node:
2747 if not node:
2733 node = rev
2748 node = rev
2734
2749
2735 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2750 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2736 ctx = cmdutil.revsingle(repo, node)
2751 ctx = cmdutil.revsingle(repo, node)
2737 for f in ctx:
2752 for f in ctx:
2738 if ui.debugflag:
2753 if ui.debugflag:
2739 ui.write("%40s " % hex(ctx.manifest()[f]))
2754 ui.write("%40s " % hex(ctx.manifest()[f]))
2740 if ui.verbose:
2755 if ui.verbose:
2741 ui.write(decor[ctx.flags(f)])
2756 ui.write(decor[ctx.flags(f)])
2742 ui.write("%s\n" % f)
2757 ui.write("%s\n" % f)
2743
2758
2744 def merge(ui, repo, node=None, **opts):
2759 def merge(ui, repo, node=None, **opts):
2745 """merge working directory with another revision
2760 """merge working directory with another revision
2746
2761
2747 The current working directory is updated with all changes made in
2762 The current working directory is updated with all changes made in
2748 the requested revision since the last common predecessor revision.
2763 the requested revision since the last common predecessor revision.
2749
2764
2750 Files that changed between either parent are marked as changed for
2765 Files that changed between either parent are marked as changed for
2751 the next commit and a commit must be performed before any further
2766 the next commit and a commit must be performed before any further
2752 updates to the repository are allowed. The next commit will have
2767 updates to the repository are allowed. The next commit will have
2753 two parents.
2768 two parents.
2754
2769
2755 ``--tool`` can be used to specify the merge tool used for file
2770 ``--tool`` can be used to specify the merge tool used for file
2756 merges. It overrides the HGMERGE environment variable and your
2771 merges. It overrides the HGMERGE environment variable and your
2757 configuration files.
2772 configuration files.
2758
2773
2759 If no revision is specified, the working directory's parent is a
2774 If no revision is specified, the working directory's parent is a
2760 head revision, and the current branch contains exactly one other
2775 head revision, and the current branch contains exactly one other
2761 head, the other head is merged with by default. Otherwise, an
2776 head, the other head is merged with by default. Otherwise, an
2762 explicit revision with which to merge with must be provided.
2777 explicit revision with which to merge with must be provided.
2763
2778
2764 :hg:`resolve` must be used to resolve unresolved files.
2779 :hg:`resolve` must be used to resolve unresolved files.
2765
2780
2766 To undo an uncommitted merge, use :hg:`update --clean .` which
2781 To undo an uncommitted merge, use :hg:`update --clean .` which
2767 will check out a clean copy of the original merge parent, losing
2782 will check out a clean copy of the original merge parent, losing
2768 all changes.
2783 all changes.
2769
2784
2770 Returns 0 on success, 1 if there are unresolved files.
2785 Returns 0 on success, 1 if there are unresolved files.
2771 """
2786 """
2772
2787
2773 if opts.get('rev') and node:
2788 if opts.get('rev') and node:
2774 raise util.Abort(_("please specify just one revision"))
2789 raise util.Abort(_("please specify just one revision"))
2775 if not node:
2790 if not node:
2776 node = opts.get('rev')
2791 node = opts.get('rev')
2777
2792
2778 if not node:
2793 if not node:
2779 branch = repo[None].branch()
2794 branch = repo[None].branch()
2780 bheads = repo.branchheads(branch)
2795 bheads = repo.branchheads(branch)
2781 if len(bheads) > 2:
2796 if len(bheads) > 2:
2782 raise util.Abort(_(
2797 raise util.Abort(_(
2783 'branch \'%s\' has %d heads - '
2798 'branch \'%s\' has %d heads - '
2784 'please merge with an explicit rev\n'
2799 'please merge with an explicit rev\n'
2785 '(run \'hg heads .\' to see heads)')
2800 '(run \'hg heads .\' to see heads)')
2786 % (branch, len(bheads)))
2801 % (branch, len(bheads)))
2787
2802
2788 parent = repo.dirstate.parents()[0]
2803 parent = repo.dirstate.parents()[0]
2789 if len(bheads) == 1:
2804 if len(bheads) == 1:
2790 if len(repo.heads()) > 1:
2805 if len(repo.heads()) > 1:
2791 raise util.Abort(_(
2806 raise util.Abort(_(
2792 'branch \'%s\' has one head - '
2807 'branch \'%s\' has one head - '
2793 'please merge with an explicit rev\n'
2808 'please merge with an explicit rev\n'
2794 '(run \'hg heads\' to see all heads)')
2809 '(run \'hg heads\' to see all heads)')
2795 % branch)
2810 % branch)
2796 msg = _('there is nothing to merge')
2811 msg = _('there is nothing to merge')
2797 if parent != repo.lookup(repo[None].branch()):
2812 if parent != repo.lookup(repo[None].branch()):
2798 msg = _('%s - use "hg update" instead') % msg
2813 msg = _('%s - use "hg update" instead') % msg
2799 raise util.Abort(msg)
2814 raise util.Abort(msg)
2800
2815
2801 if parent not in bheads:
2816 if parent not in bheads:
2802 raise util.Abort(_('working dir not at a head rev - '
2817 raise util.Abort(_('working dir not at a head rev - '
2803 'use "hg update" or merge with an explicit rev'))
2818 'use "hg update" or merge with an explicit rev'))
2804 node = parent == bheads[0] and bheads[-1] or bheads[0]
2819 node = parent == bheads[0] and bheads[-1] or bheads[0]
2805 else:
2820 else:
2806 node = cmdutil.revsingle(repo, node).node()
2821 node = cmdutil.revsingle(repo, node).node()
2807
2822
2808 if opts.get('preview'):
2823 if opts.get('preview'):
2809 # find nodes that are ancestors of p2 but not of p1
2824 # find nodes that are ancestors of p2 but not of p1
2810 p1 = repo.lookup('.')
2825 p1 = repo.lookup('.')
2811 p2 = repo.lookup(node)
2826 p2 = repo.lookup(node)
2812 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2827 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2813
2828
2814 displayer = cmdutil.show_changeset(ui, repo, opts)
2829 displayer = cmdutil.show_changeset(ui, repo, opts)
2815 for node in nodes:
2830 for node in nodes:
2816 displayer.show(repo[node])
2831 displayer.show(repo[node])
2817 displayer.close()
2832 displayer.close()
2818 return 0
2833 return 0
2819
2834
2820 try:
2835 try:
2821 # ui.forcemerge is an internal variable, do not document
2836 # ui.forcemerge is an internal variable, do not document
2822 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2837 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2823 return hg.merge(repo, node, force=opts.get('force'))
2838 return hg.merge(repo, node, force=opts.get('force'))
2824 finally:
2839 finally:
2825 ui.setconfig('ui', 'forcemerge', '')
2840 ui.setconfig('ui', 'forcemerge', '')
2826
2841
2827 def outgoing(ui, repo, dest=None, **opts):
2842 def outgoing(ui, repo, dest=None, **opts):
2828 """show changesets not found in the destination
2843 """show changesets not found in the destination
2829
2844
2830 Show changesets not found in the specified destination repository
2845 Show changesets not found in the specified destination repository
2831 or the default push location. These are the changesets that would
2846 or the default push location. These are the changesets that would
2832 be pushed if a push was requested.
2847 be pushed if a push was requested.
2833
2848
2834 See pull for details of valid destination formats.
2849 See pull for details of valid destination formats.
2835
2850
2836 Returns 0 if there are outgoing changes, 1 otherwise.
2851 Returns 0 if there are outgoing changes, 1 otherwise.
2837 """
2852 """
2838
2853
2839 if opts.get('bookmarks'):
2854 if opts.get('bookmarks'):
2840 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2855 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2841 dest, branches = hg.parseurl(dest, opts.get('branch'))
2856 dest, branches = hg.parseurl(dest, opts.get('branch'))
2842 other = hg.repository(hg.remoteui(repo, opts), dest)
2857 other = hg.repository(hg.remoteui(repo, opts), dest)
2843 if 'bookmarks' not in other.listkeys('namespaces'):
2858 if 'bookmarks' not in other.listkeys('namespaces'):
2844 ui.warn(_("remote doesn't support bookmarks\n"))
2859 ui.warn(_("remote doesn't support bookmarks\n"))
2845 return 0
2860 return 0
2846 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2861 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2847 return bookmarks.diff(ui, other, repo)
2862 return bookmarks.diff(ui, other, repo)
2848
2863
2849 ret = hg.outgoing(ui, repo, dest, opts)
2864 ret = hg.outgoing(ui, repo, dest, opts)
2850 return ret
2865 return ret
2851
2866
2852 def parents(ui, repo, file_=None, **opts):
2867 def parents(ui, repo, file_=None, **opts):
2853 """show the parents of the working directory or revision
2868 """show the parents of the working directory or revision
2854
2869
2855 Print the working directory's parent revisions. If a revision is
2870 Print the working directory's parent revisions. If a revision is
2856 given via -r/--rev, the parent of that revision will be printed.
2871 given via -r/--rev, the parent of that revision will be printed.
2857 If a file argument is given, the revision in which the file was
2872 If a file argument is given, the revision in which the file was
2858 last changed (before the working directory revision or the
2873 last changed (before the working directory revision or the
2859 argument to --rev if given) is printed.
2874 argument to --rev if given) is printed.
2860
2875
2861 Returns 0 on success.
2876 Returns 0 on success.
2862 """
2877 """
2863
2878
2864 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2879 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2865
2880
2866 if file_:
2881 if file_:
2867 m = cmdutil.match(repo, (file_,), opts)
2882 m = cmdutil.match(repo, (file_,), opts)
2868 if m.anypats() or len(m.files()) != 1:
2883 if m.anypats() or len(m.files()) != 1:
2869 raise util.Abort(_('can only specify an explicit filename'))
2884 raise util.Abort(_('can only specify an explicit filename'))
2870 file_ = m.files()[0]
2885 file_ = m.files()[0]
2871 filenodes = []
2886 filenodes = []
2872 for cp in ctx.parents():
2887 for cp in ctx.parents():
2873 if not cp:
2888 if not cp:
2874 continue
2889 continue
2875 try:
2890 try:
2876 filenodes.append(cp.filenode(file_))
2891 filenodes.append(cp.filenode(file_))
2877 except error.LookupError:
2892 except error.LookupError:
2878 pass
2893 pass
2879 if not filenodes:
2894 if not filenodes:
2880 raise util.Abort(_("'%s' not found in manifest!") % file_)
2895 raise util.Abort(_("'%s' not found in manifest!") % file_)
2881 fl = repo.file(file_)
2896 fl = repo.file(file_)
2882 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2897 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2883 else:
2898 else:
2884 p = [cp.node() for cp in ctx.parents()]
2899 p = [cp.node() for cp in ctx.parents()]
2885
2900
2886 displayer = cmdutil.show_changeset(ui, repo, opts)
2901 displayer = cmdutil.show_changeset(ui, repo, opts)
2887 for n in p:
2902 for n in p:
2888 if n != nullid:
2903 if n != nullid:
2889 displayer.show(repo[n])
2904 displayer.show(repo[n])
2890 displayer.close()
2905 displayer.close()
2891
2906
2892 def paths(ui, repo, search=None):
2907 def paths(ui, repo, search=None):
2893 """show aliases for remote repositories
2908 """show aliases for remote repositories
2894
2909
2895 Show definition of symbolic path name NAME. If no name is given,
2910 Show definition of symbolic path name NAME. If no name is given,
2896 show definition of all available names.
2911 show definition of all available names.
2897
2912
2898 Path names are defined in the [paths] section of your
2913 Path names are defined in the [paths] section of your
2899 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2914 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2900 repository, ``.hg/hgrc`` is used, too.
2915 repository, ``.hg/hgrc`` is used, too.
2901
2916
2902 The path names ``default`` and ``default-push`` have a special
2917 The path names ``default`` and ``default-push`` have a special
2903 meaning. When performing a push or pull operation, they are used
2918 meaning. When performing a push or pull operation, they are used
2904 as fallbacks if no location is specified on the command-line.
2919 as fallbacks if no location is specified on the command-line.
2905 When ``default-push`` is set, it will be used for push and
2920 When ``default-push`` is set, it will be used for push and
2906 ``default`` will be used for pull; otherwise ``default`` is used
2921 ``default`` will be used for pull; otherwise ``default`` is used
2907 as the fallback for both. When cloning a repository, the clone
2922 as the fallback for both. When cloning a repository, the clone
2908 source is written as ``default`` in ``.hg/hgrc``. Note that
2923 source is written as ``default`` in ``.hg/hgrc``. Note that
2909 ``default`` and ``default-push`` apply to all inbound (e.g.
2924 ``default`` and ``default-push`` apply to all inbound (e.g.
2910 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2925 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2911 :hg:`bundle`) operations.
2926 :hg:`bundle`) operations.
2912
2927
2913 See :hg:`help urls` for more information.
2928 See :hg:`help urls` for more information.
2914
2929
2915 Returns 0 on success.
2930 Returns 0 on success.
2916 """
2931 """
2917 if search:
2932 if search:
2918 for name, path in ui.configitems("paths"):
2933 for name, path in ui.configitems("paths"):
2919 if name == search:
2934 if name == search:
2920 ui.write("%s\n" % url.hidepassword(path))
2935 ui.write("%s\n" % url.hidepassword(path))
2921 return
2936 return
2922 ui.warn(_("not found!\n"))
2937 ui.warn(_("not found!\n"))
2923 return 1
2938 return 1
2924 else:
2939 else:
2925 for name, path in ui.configitems("paths"):
2940 for name, path in ui.configitems("paths"):
2926 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2941 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2927
2942
2928 def postincoming(ui, repo, modheads, optupdate, checkout):
2943 def postincoming(ui, repo, modheads, optupdate, checkout):
2929 if modheads == 0:
2944 if modheads == 0:
2930 return
2945 return
2931 if optupdate:
2946 if optupdate:
2932 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2947 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2933 return hg.update(repo, checkout)
2948 return hg.update(repo, checkout)
2934 else:
2949 else:
2935 ui.status(_("not updating, since new heads added\n"))
2950 ui.status(_("not updating, since new heads added\n"))
2936 if modheads > 1:
2951 if modheads > 1:
2937 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2952 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2938 else:
2953 else:
2939 ui.status(_("(run 'hg update' to get a working copy)\n"))
2954 ui.status(_("(run 'hg update' to get a working copy)\n"))
2940
2955
2941 def pull(ui, repo, source="default", **opts):
2956 def pull(ui, repo, source="default", **opts):
2942 """pull changes from the specified source
2957 """pull changes from the specified source
2943
2958
2944 Pull changes from a remote repository to a local one.
2959 Pull changes from a remote repository to a local one.
2945
2960
2946 This finds all changes from the repository at the specified path
2961 This finds all changes from the repository at the specified path
2947 or URL and adds them to a local repository (the current one unless
2962 or URL and adds them to a local repository (the current one unless
2948 -R is specified). By default, this does not update the copy of the
2963 -R is specified). By default, this does not update the copy of the
2949 project in the working directory.
2964 project in the working directory.
2950
2965
2951 Use :hg:`incoming` if you want to see what would have been added
2966 Use :hg:`incoming` if you want to see what would have been added
2952 by a pull at the time you issued this command. If you then decide
2967 by a pull at the time you issued this command. If you then decide
2953 to add those changes to the repository, you should use :hg:`pull
2968 to add those changes to the repository, you should use :hg:`pull
2954 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2969 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2955
2970
2956 If SOURCE is omitted, the 'default' path will be used.
2971 If SOURCE is omitted, the 'default' path will be used.
2957 See :hg:`help urls` for more information.
2972 See :hg:`help urls` for more information.
2958
2973
2959 Returns 0 on success, 1 if an update had unresolved files.
2974 Returns 0 on success, 1 if an update had unresolved files.
2960 """
2975 """
2961 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2976 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2962 other = hg.repository(hg.remoteui(repo, opts), source)
2977 other = hg.repository(hg.remoteui(repo, opts), source)
2963 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2978 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2964 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2979 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2965
2980
2966 if opts.get('bookmark'):
2981 if opts.get('bookmark'):
2967 if not revs:
2982 if not revs:
2968 revs = []
2983 revs = []
2969 rb = other.listkeys('bookmarks')
2984 rb = other.listkeys('bookmarks')
2970 for b in opts['bookmark']:
2985 for b in opts['bookmark']:
2971 if b not in rb:
2986 if b not in rb:
2972 raise util.Abort(_('remote bookmark %s not found!') % b)
2987 raise util.Abort(_('remote bookmark %s not found!') % b)
2973 revs.append(rb[b])
2988 revs.append(rb[b])
2974
2989
2975 if revs:
2990 if revs:
2976 try:
2991 try:
2977 revs = [other.lookup(rev) for rev in revs]
2992 revs = [other.lookup(rev) for rev in revs]
2978 except error.CapabilityError:
2993 except error.CapabilityError:
2979 err = _("other repository doesn't support revision lookup, "
2994 err = _("other repository doesn't support revision lookup, "
2980 "so a rev cannot be specified.")
2995 "so a rev cannot be specified.")
2981 raise util.Abort(err)
2996 raise util.Abort(err)
2982
2997
2983 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2998 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2984 bookmarks.updatefromremote(ui, repo, other)
2999 bookmarks.updatefromremote(ui, repo, other)
2985 if checkout:
3000 if checkout:
2986 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3001 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2987 repo._subtoppath = source
3002 repo._subtoppath = source
2988 try:
3003 try:
2989 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3004 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
2990
3005
2991 finally:
3006 finally:
2992 del repo._subtoppath
3007 del repo._subtoppath
2993
3008
2994 # update specified bookmarks
3009 # update specified bookmarks
2995 if opts.get('bookmark'):
3010 if opts.get('bookmark'):
2996 for b in opts['bookmark']:
3011 for b in opts['bookmark']:
2997 # explicit pull overrides local bookmark if any
3012 # explicit pull overrides local bookmark if any
2998 ui.status(_("importing bookmark %s\n") % b)
3013 ui.status(_("importing bookmark %s\n") % b)
2999 repo._bookmarks[b] = repo[rb[b]].node()
3014 repo._bookmarks[b] = repo[rb[b]].node()
3000 bookmarks.write(repo)
3015 bookmarks.write(repo)
3001
3016
3002 return ret
3017 return ret
3003
3018
3004 def push(ui, repo, dest=None, **opts):
3019 def push(ui, repo, dest=None, **opts):
3005 """push changes to the specified destination
3020 """push changes to the specified destination
3006
3021
3007 Push changesets from the local repository to the specified
3022 Push changesets from the local repository to the specified
3008 destination.
3023 destination.
3009
3024
3010 This operation is symmetrical to pull: it is identical to a pull
3025 This operation is symmetrical to pull: it is identical to a pull
3011 in the destination repository from the current one.
3026 in the destination repository from the current one.
3012
3027
3013 By default, push will not allow creation of new heads at the
3028 By default, push will not allow creation of new heads at the
3014 destination, since multiple heads would make it unclear which head
3029 destination, since multiple heads would make it unclear which head
3015 to use. In this situation, it is recommended to pull and merge
3030 to use. In this situation, it is recommended to pull and merge
3016 before pushing.
3031 before pushing.
3017
3032
3018 Use --new-branch if you want to allow push to create a new named
3033 Use --new-branch if you want to allow push to create a new named
3019 branch that is not present at the destination. This allows you to
3034 branch that is not present at the destination. This allows you to
3020 only create a new branch without forcing other changes.
3035 only create a new branch without forcing other changes.
3021
3036
3022 Use -f/--force to override the default behavior and push all
3037 Use -f/--force to override the default behavior and push all
3023 changesets on all branches.
3038 changesets on all branches.
3024
3039
3025 If -r/--rev is used, the specified revision and all its ancestors
3040 If -r/--rev is used, the specified revision and all its ancestors
3026 will be pushed to the remote repository.
3041 will be pushed to the remote repository.
3027
3042
3028 Please see :hg:`help urls` for important details about ``ssh://``
3043 Please see :hg:`help urls` for important details about ``ssh://``
3029 URLs. If DESTINATION is omitted, a default path will be used.
3044 URLs. If DESTINATION is omitted, a default path will be used.
3030
3045
3031 Returns 0 if push was successful, 1 if nothing to push.
3046 Returns 0 if push was successful, 1 if nothing to push.
3032 """
3047 """
3033
3048
3034 if opts.get('bookmark'):
3049 if opts.get('bookmark'):
3035 for b in opts['bookmark']:
3050 for b in opts['bookmark']:
3036 # translate -B options to -r so changesets get pushed
3051 # translate -B options to -r so changesets get pushed
3037 if b in repo._bookmarks:
3052 if b in repo._bookmarks:
3038 opts.setdefault('rev', []).append(b)
3053 opts.setdefault('rev', []).append(b)
3039 else:
3054 else:
3040 # if we try to push a deleted bookmark, translate it to null
3055 # if we try to push a deleted bookmark, translate it to null
3041 # this lets simultaneous -r, -b options continue working
3056 # this lets simultaneous -r, -b options continue working
3042 opts.setdefault('rev', []).append("null")
3057 opts.setdefault('rev', []).append("null")
3043
3058
3044 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3059 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3045 dest, branches = hg.parseurl(dest, opts.get('branch'))
3060 dest, branches = hg.parseurl(dest, opts.get('branch'))
3046 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
3061 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
3047 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3062 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3048 other = hg.repository(hg.remoteui(repo, opts), dest)
3063 other = hg.repository(hg.remoteui(repo, opts), dest)
3049 if revs:
3064 if revs:
3050 revs = [repo.lookup(rev) for rev in revs]
3065 revs = [repo.lookup(rev) for rev in revs]
3051
3066
3052 repo._subtoppath = dest
3067 repo._subtoppath = dest
3053 try:
3068 try:
3054 # push subrepos depth-first for coherent ordering
3069 # push subrepos depth-first for coherent ordering
3055 c = repo['']
3070 c = repo['']
3056 subs = c.substate # only repos that are committed
3071 subs = c.substate # only repos that are committed
3057 for s in sorted(subs):
3072 for s in sorted(subs):
3058 if not c.sub(s).push(opts.get('force')):
3073 if not c.sub(s).push(opts.get('force')):
3059 return False
3074 return False
3060 finally:
3075 finally:
3061 del repo._subtoppath
3076 del repo._subtoppath
3062 result = repo.push(other, opts.get('force'), revs=revs,
3077 result = repo.push(other, opts.get('force'), revs=revs,
3063 newbranch=opts.get('new_branch'))
3078 newbranch=opts.get('new_branch'))
3064
3079
3065 result = (result == 0)
3080 result = (result == 0)
3066
3081
3067 if opts.get('bookmark'):
3082 if opts.get('bookmark'):
3068 rb = other.listkeys('bookmarks')
3083 rb = other.listkeys('bookmarks')
3069 for b in opts['bookmark']:
3084 for b in opts['bookmark']:
3070 # explicit push overrides remote bookmark if any
3085 # explicit push overrides remote bookmark if any
3071 if b in repo._bookmarks:
3086 if b in repo._bookmarks:
3072 ui.status(_("exporting bookmark %s\n") % b)
3087 ui.status(_("exporting bookmark %s\n") % b)
3073 new = repo[b].hex()
3088 new = repo[b].hex()
3074 elif b in rb:
3089 elif b in rb:
3075 ui.status(_("deleting remote bookmark %s\n") % b)
3090 ui.status(_("deleting remote bookmark %s\n") % b)
3076 new = '' # delete
3091 new = '' # delete
3077 else:
3092 else:
3078 ui.warn(_('bookmark %s does not exist on the local '
3093 ui.warn(_('bookmark %s does not exist on the local '
3079 'or remote repository!\n') % b)
3094 'or remote repository!\n') % b)
3080 return 2
3095 return 2
3081 old = rb.get(b, '')
3096 old = rb.get(b, '')
3082 r = other.pushkey('bookmarks', b, old, new)
3097 r = other.pushkey('bookmarks', b, old, new)
3083 if not r:
3098 if not r:
3084 ui.warn(_('updating bookmark %s failed!\n') % b)
3099 ui.warn(_('updating bookmark %s failed!\n') % b)
3085 if not result:
3100 if not result:
3086 result = 2
3101 result = 2
3087
3102
3088 return result
3103 return result
3089
3104
3090 def recover(ui, repo):
3105 def recover(ui, repo):
3091 """roll back an interrupted transaction
3106 """roll back an interrupted transaction
3092
3107
3093 Recover from an interrupted commit or pull.
3108 Recover from an interrupted commit or pull.
3094
3109
3095 This command tries to fix the repository status after an
3110 This command tries to fix the repository status after an
3096 interrupted operation. It should only be necessary when Mercurial
3111 interrupted operation. It should only be necessary when Mercurial
3097 suggests it.
3112 suggests it.
3098
3113
3099 Returns 0 if successful, 1 if nothing to recover or verify fails.
3114 Returns 0 if successful, 1 if nothing to recover or verify fails.
3100 """
3115 """
3101 if repo.recover():
3116 if repo.recover():
3102 return hg.verify(repo)
3117 return hg.verify(repo)
3103 return 1
3118 return 1
3104
3119
3105 def remove(ui, repo, *pats, **opts):
3120 def remove(ui, repo, *pats, **opts):
3106 """remove the specified files on the next commit
3121 """remove the specified files on the next commit
3107
3122
3108 Schedule the indicated files for removal from the repository.
3123 Schedule the indicated files for removal from the repository.
3109
3124
3110 This only removes files from the current branch, not from the
3125 This only removes files from the current branch, not from the
3111 entire project history. -A/--after can be used to remove only
3126 entire project history. -A/--after can be used to remove only
3112 files that have already been deleted, -f/--force can be used to
3127 files that have already been deleted, -f/--force can be used to
3113 force deletion, and -Af can be used to remove files from the next
3128 force deletion, and -Af can be used to remove files from the next
3114 revision without deleting them from the working directory.
3129 revision without deleting them from the working directory.
3115
3130
3116 The following table details the behavior of remove for different
3131 The following table details the behavior of remove for different
3117 file states (columns) and option combinations (rows). The file
3132 file states (columns) and option combinations (rows). The file
3118 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3133 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3119 reported by :hg:`status`). The actions are Warn, Remove (from
3134 reported by :hg:`status`). The actions are Warn, Remove (from
3120 branch) and Delete (from disk)::
3135 branch) and Delete (from disk)::
3121
3136
3122 A C M !
3137 A C M !
3123 none W RD W R
3138 none W RD W R
3124 -f R RD RD R
3139 -f R RD RD R
3125 -A W W W R
3140 -A W W W R
3126 -Af R R R R
3141 -Af R R R R
3127
3142
3128 This command schedules the files to be removed at the next commit.
3143 This command schedules the files to be removed at the next commit.
3129 To undo a remove before that, see :hg:`revert`.
3144 To undo a remove before that, see :hg:`revert`.
3130
3145
3131 Returns 0 on success, 1 if any warnings encountered.
3146 Returns 0 on success, 1 if any warnings encountered.
3132 """
3147 """
3133
3148
3134 ret = 0
3149 ret = 0
3135 after, force = opts.get('after'), opts.get('force')
3150 after, force = opts.get('after'), opts.get('force')
3136 if not pats and not after:
3151 if not pats and not after:
3137 raise util.Abort(_('no files specified'))
3152 raise util.Abort(_('no files specified'))
3138
3153
3139 m = cmdutil.match(repo, pats, opts)
3154 m = cmdutil.match(repo, pats, opts)
3140 s = repo.status(match=m, clean=True)
3155 s = repo.status(match=m, clean=True)
3141 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3156 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3142
3157
3143 for f in m.files():
3158 for f in m.files():
3144 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3159 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3145 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3160 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3146 ret = 1
3161 ret = 1
3147
3162
3148 if force:
3163 if force:
3149 remove, forget = modified + deleted + clean, added
3164 remove, forget = modified + deleted + clean, added
3150 elif after:
3165 elif after:
3151 remove, forget = deleted, []
3166 remove, forget = deleted, []
3152 for f in modified + added + clean:
3167 for f in modified + added + clean:
3153 ui.warn(_('not removing %s: file still exists (use -f'
3168 ui.warn(_('not removing %s: file still exists (use -f'
3154 ' to force removal)\n') % m.rel(f))
3169 ' to force removal)\n') % m.rel(f))
3155 ret = 1
3170 ret = 1
3156 else:
3171 else:
3157 remove, forget = deleted + clean, []
3172 remove, forget = deleted + clean, []
3158 for f in modified:
3173 for f in modified:
3159 ui.warn(_('not removing %s: file is modified (use -f'
3174 ui.warn(_('not removing %s: file is modified (use -f'
3160 ' to force removal)\n') % m.rel(f))
3175 ' to force removal)\n') % m.rel(f))
3161 ret = 1
3176 ret = 1
3162 for f in added:
3177 for f in added:
3163 ui.warn(_('not removing %s: file has been marked for add (use -f'
3178 ui.warn(_('not removing %s: file has been marked for add (use -f'
3164 ' to force removal)\n') % m.rel(f))
3179 ' to force removal)\n') % m.rel(f))
3165 ret = 1
3180 ret = 1
3166
3181
3167 for f in sorted(remove + forget):
3182 for f in sorted(remove + forget):
3168 if ui.verbose or not m.exact(f):
3183 if ui.verbose or not m.exact(f):
3169 ui.status(_('removing %s\n') % m.rel(f))
3184 ui.status(_('removing %s\n') % m.rel(f))
3170
3185
3171 repo[None].forget(forget)
3186 repo[None].forget(forget)
3172 repo[None].remove(remove, unlink=not after)
3187 repo[None].remove(remove, unlink=not after)
3173 return ret
3188 return ret
3174
3189
3175 def rename(ui, repo, *pats, **opts):
3190 def rename(ui, repo, *pats, **opts):
3176 """rename files; equivalent of copy + remove
3191 """rename files; equivalent of copy + remove
3177
3192
3178 Mark dest as copies of sources; mark sources for deletion. If dest
3193 Mark dest as copies of sources; mark sources for deletion. If dest
3179 is a directory, copies are put in that directory. If dest is a
3194 is a directory, copies are put in that directory. If dest is a
3180 file, there can only be one source.
3195 file, there can only be one source.
3181
3196
3182 By default, this command copies the contents of files as they
3197 By default, this command copies the contents of files as they
3183 exist in the working directory. If invoked with -A/--after, the
3198 exist in the working directory. If invoked with -A/--after, the
3184 operation is recorded, but no copying is performed.
3199 operation is recorded, but no copying is performed.
3185
3200
3186 This command takes effect at the next commit. To undo a rename
3201 This command takes effect at the next commit. To undo a rename
3187 before that, see :hg:`revert`.
3202 before that, see :hg:`revert`.
3188
3203
3189 Returns 0 on success, 1 if errors are encountered.
3204 Returns 0 on success, 1 if errors are encountered.
3190 """
3205 """
3191 wlock = repo.wlock(False)
3206 wlock = repo.wlock(False)
3192 try:
3207 try:
3193 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3208 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3194 finally:
3209 finally:
3195 wlock.release()
3210 wlock.release()
3196
3211
3197 def resolve(ui, repo, *pats, **opts):
3212 def resolve(ui, repo, *pats, **opts):
3198 """redo merges or set/view the merge status of files
3213 """redo merges or set/view the merge status of files
3199
3214
3200 Merges with unresolved conflicts are often the result of
3215 Merges with unresolved conflicts are often the result of
3201 non-interactive merging using the ``internal:merge`` configuration
3216 non-interactive merging using the ``internal:merge`` configuration
3202 setting, or a command-line merge tool like ``diff3``. The resolve
3217 setting, or a command-line merge tool like ``diff3``. The resolve
3203 command is used to manage the files involved in a merge, after
3218 command is used to manage the files involved in a merge, after
3204 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3219 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3205 working directory must have two parents).
3220 working directory must have two parents).
3206
3221
3207 The resolve command can be used in the following ways:
3222 The resolve command can be used in the following ways:
3208
3223
3209 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3224 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3210 files, discarding any previous merge attempts. Re-merging is not
3225 files, discarding any previous merge attempts. Re-merging is not
3211 performed for files already marked as resolved. Use ``--all/-a``
3226 performed for files already marked as resolved. Use ``--all/-a``
3212 to selects all unresolved files. ``--tool`` can be used to specify
3227 to selects all unresolved files. ``--tool`` can be used to specify
3213 the merge tool used for the given files. It overrides the HGMERGE
3228 the merge tool used for the given files. It overrides the HGMERGE
3214 environment variable and your configuration files.
3229 environment variable and your configuration files.
3215
3230
3216 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3231 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3217 (e.g. after having manually fixed-up the files). The default is
3232 (e.g. after having manually fixed-up the files). The default is
3218 to mark all unresolved files.
3233 to mark all unresolved files.
3219
3234
3220 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3235 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3221 default is to mark all resolved files.
3236 default is to mark all resolved files.
3222
3237
3223 - :hg:`resolve -l`: list files which had or still have conflicts.
3238 - :hg:`resolve -l`: list files which had or still have conflicts.
3224 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3239 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3225
3240
3226 Note that Mercurial will not let you commit files with unresolved
3241 Note that Mercurial will not let you commit files with unresolved
3227 merge conflicts. You must use :hg:`resolve -m ...` before you can
3242 merge conflicts. You must use :hg:`resolve -m ...` before you can
3228 commit after a conflicting merge.
3243 commit after a conflicting merge.
3229
3244
3230 Returns 0 on success, 1 if any files fail a resolve attempt.
3245 Returns 0 on success, 1 if any files fail a resolve attempt.
3231 """
3246 """
3232
3247
3233 all, mark, unmark, show, nostatus = \
3248 all, mark, unmark, show, nostatus = \
3234 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3249 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3235
3250
3236 if (show and (mark or unmark)) or (mark and unmark):
3251 if (show and (mark or unmark)) or (mark and unmark):
3237 raise util.Abort(_("too many options specified"))
3252 raise util.Abort(_("too many options specified"))
3238 if pats and all:
3253 if pats and all:
3239 raise util.Abort(_("can't specify --all and patterns"))
3254 raise util.Abort(_("can't specify --all and patterns"))
3240 if not (all or pats or show or mark or unmark):
3255 if not (all or pats or show or mark or unmark):
3241 raise util.Abort(_('no files or directories specified; '
3256 raise util.Abort(_('no files or directories specified; '
3242 'use --all to remerge all files'))
3257 'use --all to remerge all files'))
3243
3258
3244 ms = mergemod.mergestate(repo)
3259 ms = mergemod.mergestate(repo)
3245 m = cmdutil.match(repo, pats, opts)
3260 m = cmdutil.match(repo, pats, opts)
3246 ret = 0
3261 ret = 0
3247
3262
3248 for f in ms:
3263 for f in ms:
3249 if m(f):
3264 if m(f):
3250 if show:
3265 if show:
3251 if nostatus:
3266 if nostatus:
3252 ui.write("%s\n" % f)
3267 ui.write("%s\n" % f)
3253 else:
3268 else:
3254 ui.write("%s %s\n" % (ms[f].upper(), f),
3269 ui.write("%s %s\n" % (ms[f].upper(), f),
3255 label='resolve.' +
3270 label='resolve.' +
3256 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3271 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3257 elif mark:
3272 elif mark:
3258 ms.mark(f, "r")
3273 ms.mark(f, "r")
3259 elif unmark:
3274 elif unmark:
3260 ms.mark(f, "u")
3275 ms.mark(f, "u")
3261 else:
3276 else:
3262 wctx = repo[None]
3277 wctx = repo[None]
3263 mctx = wctx.parents()[-1]
3278 mctx = wctx.parents()[-1]
3264
3279
3265 # backup pre-resolve (merge uses .orig for its own purposes)
3280 # backup pre-resolve (merge uses .orig for its own purposes)
3266 a = repo.wjoin(f)
3281 a = repo.wjoin(f)
3267 util.copyfile(a, a + ".resolve")
3282 util.copyfile(a, a + ".resolve")
3268
3283
3269 try:
3284 try:
3270 # resolve file
3285 # resolve file
3271 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3286 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3272 if ms.resolve(f, wctx, mctx):
3287 if ms.resolve(f, wctx, mctx):
3273 ret = 1
3288 ret = 1
3274 finally:
3289 finally:
3275 ui.setconfig('ui', 'forcemerge', '')
3290 ui.setconfig('ui', 'forcemerge', '')
3276
3291
3277 # replace filemerge's .orig file with our resolve file
3292 # replace filemerge's .orig file with our resolve file
3278 util.rename(a + ".resolve", a + ".orig")
3293 util.rename(a + ".resolve", a + ".orig")
3279
3294
3280 ms.commit()
3295 ms.commit()
3281 return ret
3296 return ret
3282
3297
3283 def revert(ui, repo, *pats, **opts):
3298 def revert(ui, repo, *pats, **opts):
3284 """restore individual files or directories to an earlier state
3299 """restore individual files or directories to an earlier state
3285
3300
3286 .. note::
3301 .. note::
3287 This command is most likely not what you are looking for.
3302 This command is most likely not what you are looking for.
3288 Revert will partially overwrite content in the working
3303 Revert will partially overwrite content in the working
3289 directory without changing the working directory parents. Use
3304 directory without changing the working directory parents. Use
3290 :hg:`update -r rev` to check out earlier revisions, or
3305 :hg:`update -r rev` to check out earlier revisions, or
3291 :hg:`update --clean .` to undo a merge which has added another
3306 :hg:`update --clean .` to undo a merge which has added another
3292 parent.
3307 parent.
3293
3308
3294 With no revision specified, revert the named files or directories
3309 With no revision specified, revert the named files or directories
3295 to the contents they had in the parent of the working directory.
3310 to the contents they had in the parent of the working directory.
3296 This restores the contents of the affected files to an unmodified
3311 This restores the contents of the affected files to an unmodified
3297 state and unschedules adds, removes, copies, and renames. If the
3312 state and unschedules adds, removes, copies, and renames. If the
3298 working directory has two parents, you must explicitly specify a
3313 working directory has two parents, you must explicitly specify a
3299 revision.
3314 revision.
3300
3315
3301 Using the -r/--rev option, revert the given files or directories
3316 Using the -r/--rev option, revert the given files or directories
3302 to their contents as of a specific revision. This can be helpful
3317 to their contents as of a specific revision. This can be helpful
3303 to "roll back" some or all of an earlier change. See :hg:`help
3318 to "roll back" some or all of an earlier change. See :hg:`help
3304 dates` for a list of formats valid for -d/--date.
3319 dates` for a list of formats valid for -d/--date.
3305
3320
3306 Revert modifies the working directory. It does not commit any
3321 Revert modifies the working directory. It does not commit any
3307 changes, or change the parent of the working directory. If you
3322 changes, or change the parent of the working directory. If you
3308 revert to a revision other than the parent of the working
3323 revert to a revision other than the parent of the working
3309 directory, the reverted files will thus appear modified
3324 directory, the reverted files will thus appear modified
3310 afterwards.
3325 afterwards.
3311
3326
3312 If a file has been deleted, it is restored. If the executable mode
3327 If a file has been deleted, it is restored. If the executable mode
3313 of a file was changed, it is reset.
3328 of a file was changed, it is reset.
3314
3329
3315 If names are given, all files matching the names are reverted.
3330 If names are given, all files matching the names are reverted.
3316 If no arguments are given, no files are reverted.
3331 If no arguments are given, no files are reverted.
3317
3332
3318 Modified files are saved with a .orig suffix before reverting.
3333 Modified files are saved with a .orig suffix before reverting.
3319 To disable these backups, use --no-backup.
3334 To disable these backups, use --no-backup.
3320
3335
3321 Returns 0 on success.
3336 Returns 0 on success.
3322 """
3337 """
3323
3338
3324 if opts.get("date"):
3339 if opts.get("date"):
3325 if opts.get("rev"):
3340 if opts.get("rev"):
3326 raise util.Abort(_("you can't specify a revision and a date"))
3341 raise util.Abort(_("you can't specify a revision and a date"))
3327 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3342 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3328
3343
3329 parent, p2 = repo.dirstate.parents()
3344 parent, p2 = repo.dirstate.parents()
3330 if not opts.get('rev') and p2 != nullid:
3345 if not opts.get('rev') and p2 != nullid:
3331 raise util.Abort(_('uncommitted merge - '
3346 raise util.Abort(_('uncommitted merge - '
3332 'use "hg update", see "hg help revert"'))
3347 'use "hg update", see "hg help revert"'))
3333
3348
3334 if not pats and not opts.get('all'):
3349 if not pats and not opts.get('all'):
3335 raise util.Abort(_('no files or directories specified; '
3350 raise util.Abort(_('no files or directories specified; '
3336 'use --all to revert the whole repo'))
3351 'use --all to revert the whole repo'))
3337
3352
3338 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3353 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3339 node = ctx.node()
3354 node = ctx.node()
3340 mf = ctx.manifest()
3355 mf = ctx.manifest()
3341 if node == parent:
3356 if node == parent:
3342 pmf = mf
3357 pmf = mf
3343 else:
3358 else:
3344 pmf = None
3359 pmf = None
3345
3360
3346 # need all matching names in dirstate and manifest of target rev,
3361 # need all matching names in dirstate and manifest of target rev,
3347 # so have to walk both. do not print errors if files exist in one
3362 # so have to walk both. do not print errors if files exist in one
3348 # but not other.
3363 # but not other.
3349
3364
3350 names = {}
3365 names = {}
3351
3366
3352 wlock = repo.wlock()
3367 wlock = repo.wlock()
3353 try:
3368 try:
3354 # walk dirstate.
3369 # walk dirstate.
3355
3370
3356 m = cmdutil.match(repo, pats, opts)
3371 m = cmdutil.match(repo, pats, opts)
3357 m.bad = lambda x, y: False
3372 m.bad = lambda x, y: False
3358 for abs in repo.walk(m):
3373 for abs in repo.walk(m):
3359 names[abs] = m.rel(abs), m.exact(abs)
3374 names[abs] = m.rel(abs), m.exact(abs)
3360
3375
3361 # walk target manifest.
3376 # walk target manifest.
3362
3377
3363 def badfn(path, msg):
3378 def badfn(path, msg):
3364 if path in names:
3379 if path in names:
3365 return
3380 return
3366 path_ = path + '/'
3381 path_ = path + '/'
3367 for f in names:
3382 for f in names:
3368 if f.startswith(path_):
3383 if f.startswith(path_):
3369 return
3384 return
3370 ui.warn("%s: %s\n" % (m.rel(path), msg))
3385 ui.warn("%s: %s\n" % (m.rel(path), msg))
3371
3386
3372 m = cmdutil.match(repo, pats, opts)
3387 m = cmdutil.match(repo, pats, opts)
3373 m.bad = badfn
3388 m.bad = badfn
3374 for abs in repo[node].walk(m):
3389 for abs in repo[node].walk(m):
3375 if abs not in names:
3390 if abs not in names:
3376 names[abs] = m.rel(abs), m.exact(abs)
3391 names[abs] = m.rel(abs), m.exact(abs)
3377
3392
3378 m = cmdutil.matchfiles(repo, names)
3393 m = cmdutil.matchfiles(repo, names)
3379 changes = repo.status(match=m)[:4]
3394 changes = repo.status(match=m)[:4]
3380 modified, added, removed, deleted = map(set, changes)
3395 modified, added, removed, deleted = map(set, changes)
3381
3396
3382 # if f is a rename, also revert the source
3397 # if f is a rename, also revert the source
3383 cwd = repo.getcwd()
3398 cwd = repo.getcwd()
3384 for f in added:
3399 for f in added:
3385 src = repo.dirstate.copied(f)
3400 src = repo.dirstate.copied(f)
3386 if src and src not in names and repo.dirstate[src] == 'r':
3401 if src and src not in names and repo.dirstate[src] == 'r':
3387 removed.add(src)
3402 removed.add(src)
3388 names[src] = (repo.pathto(src, cwd), True)
3403 names[src] = (repo.pathto(src, cwd), True)
3389
3404
3390 def removeforget(abs):
3405 def removeforget(abs):
3391 if repo.dirstate[abs] == 'a':
3406 if repo.dirstate[abs] == 'a':
3392 return _('forgetting %s\n')
3407 return _('forgetting %s\n')
3393 return _('removing %s\n')
3408 return _('removing %s\n')
3394
3409
3395 revert = ([], _('reverting %s\n'))
3410 revert = ([], _('reverting %s\n'))
3396 add = ([], _('adding %s\n'))
3411 add = ([], _('adding %s\n'))
3397 remove = ([], removeforget)
3412 remove = ([], removeforget)
3398 undelete = ([], _('undeleting %s\n'))
3413 undelete = ([], _('undeleting %s\n'))
3399
3414
3400 disptable = (
3415 disptable = (
3401 # dispatch table:
3416 # dispatch table:
3402 # file state
3417 # file state
3403 # action if in target manifest
3418 # action if in target manifest
3404 # action if not in target manifest
3419 # action if not in target manifest
3405 # make backup if in target manifest
3420 # make backup if in target manifest
3406 # make backup if not in target manifest
3421 # make backup if not in target manifest
3407 (modified, revert, remove, True, True),
3422 (modified, revert, remove, True, True),
3408 (added, revert, remove, True, False),
3423 (added, revert, remove, True, False),
3409 (removed, undelete, None, False, False),
3424 (removed, undelete, None, False, False),
3410 (deleted, revert, remove, False, False),
3425 (deleted, revert, remove, False, False),
3411 )
3426 )
3412
3427
3413 for abs, (rel, exact) in sorted(names.items()):
3428 for abs, (rel, exact) in sorted(names.items()):
3414 mfentry = mf.get(abs)
3429 mfentry = mf.get(abs)
3415 target = repo.wjoin(abs)
3430 target = repo.wjoin(abs)
3416 def handle(xlist, dobackup):
3431 def handle(xlist, dobackup):
3417 xlist[0].append(abs)
3432 xlist[0].append(abs)
3418 if (dobackup and not opts.get('no_backup') and
3433 if (dobackup and not opts.get('no_backup') and
3419 os.path.lexists(target)):
3434 os.path.lexists(target)):
3420 bakname = "%s.orig" % rel
3435 bakname = "%s.orig" % rel
3421 ui.note(_('saving current version of %s as %s\n') %
3436 ui.note(_('saving current version of %s as %s\n') %
3422 (rel, bakname))
3437 (rel, bakname))
3423 if not opts.get('dry_run'):
3438 if not opts.get('dry_run'):
3424 util.rename(target, bakname)
3439 util.rename(target, bakname)
3425 if ui.verbose or not exact:
3440 if ui.verbose or not exact:
3426 msg = xlist[1]
3441 msg = xlist[1]
3427 if not isinstance(msg, basestring):
3442 if not isinstance(msg, basestring):
3428 msg = msg(abs)
3443 msg = msg(abs)
3429 ui.status(msg % rel)
3444 ui.status(msg % rel)
3430 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3445 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3431 if abs not in table:
3446 if abs not in table:
3432 continue
3447 continue
3433 # file has changed in dirstate
3448 # file has changed in dirstate
3434 if mfentry:
3449 if mfentry:
3435 handle(hitlist, backuphit)
3450 handle(hitlist, backuphit)
3436 elif misslist is not None:
3451 elif misslist is not None:
3437 handle(misslist, backupmiss)
3452 handle(misslist, backupmiss)
3438 break
3453 break
3439 else:
3454 else:
3440 if abs not in repo.dirstate:
3455 if abs not in repo.dirstate:
3441 if mfentry:
3456 if mfentry:
3442 handle(add, True)
3457 handle(add, True)
3443 elif exact:
3458 elif exact:
3444 ui.warn(_('file not managed: %s\n') % rel)
3459 ui.warn(_('file not managed: %s\n') % rel)
3445 continue
3460 continue
3446 # file has not changed in dirstate
3461 # file has not changed in dirstate
3447 if node == parent:
3462 if node == parent:
3448 if exact:
3463 if exact:
3449 ui.warn(_('no changes needed to %s\n') % rel)
3464 ui.warn(_('no changes needed to %s\n') % rel)
3450 continue
3465 continue
3451 if pmf is None:
3466 if pmf is None:
3452 # only need parent manifest in this unlikely case,
3467 # only need parent manifest in this unlikely case,
3453 # so do not read by default
3468 # so do not read by default
3454 pmf = repo[parent].manifest()
3469 pmf = repo[parent].manifest()
3455 if abs in pmf:
3470 if abs in pmf:
3456 if mfentry:
3471 if mfentry:
3457 # if version of file is same in parent and target
3472 # if version of file is same in parent and target
3458 # manifests, do nothing
3473 # manifests, do nothing
3459 if (pmf[abs] != mfentry or
3474 if (pmf[abs] != mfentry or
3460 pmf.flags(abs) != mf.flags(abs)):
3475 pmf.flags(abs) != mf.flags(abs)):
3461 handle(revert, False)
3476 handle(revert, False)
3462 else:
3477 else:
3463 handle(remove, False)
3478 handle(remove, False)
3464
3479
3465 if not opts.get('dry_run'):
3480 if not opts.get('dry_run'):
3466 def checkout(f):
3481 def checkout(f):
3467 fc = ctx[f]
3482 fc = ctx[f]
3468 repo.wwrite(f, fc.data(), fc.flags())
3483 repo.wwrite(f, fc.data(), fc.flags())
3469
3484
3470 audit_path = util.path_auditor(repo.root)
3485 audit_path = util.path_auditor(repo.root)
3471 for f in remove[0]:
3486 for f in remove[0]:
3472 if repo.dirstate[f] == 'a':
3487 if repo.dirstate[f] == 'a':
3473 repo.dirstate.forget(f)
3488 repo.dirstate.forget(f)
3474 continue
3489 continue
3475 audit_path(f)
3490 audit_path(f)
3476 try:
3491 try:
3477 util.unlinkpath(repo.wjoin(f))
3492 util.unlinkpath(repo.wjoin(f))
3478 except OSError:
3493 except OSError:
3479 pass
3494 pass
3480 repo.dirstate.remove(f)
3495 repo.dirstate.remove(f)
3481
3496
3482 normal = None
3497 normal = None
3483 if node == parent:
3498 if node == parent:
3484 # We're reverting to our parent. If possible, we'd like status
3499 # We're reverting to our parent. If possible, we'd like status
3485 # to report the file as clean. We have to use normallookup for
3500 # to report the file as clean. We have to use normallookup for
3486 # merges to avoid losing information about merged/dirty files.
3501 # merges to avoid losing information about merged/dirty files.
3487 if p2 != nullid:
3502 if p2 != nullid:
3488 normal = repo.dirstate.normallookup
3503 normal = repo.dirstate.normallookup
3489 else:
3504 else:
3490 normal = repo.dirstate.normal
3505 normal = repo.dirstate.normal
3491 for f in revert[0]:
3506 for f in revert[0]:
3492 checkout(f)
3507 checkout(f)
3493 if normal:
3508 if normal:
3494 normal(f)
3509 normal(f)
3495
3510
3496 for f in add[0]:
3511 for f in add[0]:
3497 checkout(f)
3512 checkout(f)
3498 repo.dirstate.add(f)
3513 repo.dirstate.add(f)
3499
3514
3500 normal = repo.dirstate.normallookup
3515 normal = repo.dirstate.normallookup
3501 if node == parent and p2 == nullid:
3516 if node == parent and p2 == nullid:
3502 normal = repo.dirstate.normal
3517 normal = repo.dirstate.normal
3503 for f in undelete[0]:
3518 for f in undelete[0]:
3504 checkout(f)
3519 checkout(f)
3505 normal(f)
3520 normal(f)
3506
3521
3507 finally:
3522 finally:
3508 wlock.release()
3523 wlock.release()
3509
3524
3510 def rollback(ui, repo, **opts):
3525 def rollback(ui, repo, **opts):
3511 """roll back the last transaction (dangerous)
3526 """roll back the last transaction (dangerous)
3512
3527
3513 This command should be used with care. There is only one level of
3528 This command should be used with care. There is only one level of
3514 rollback, and there is no way to undo a rollback. It will also
3529 rollback, and there is no way to undo a rollback. It will also
3515 restore the dirstate at the time of the last transaction, losing
3530 restore the dirstate at the time of the last transaction, losing
3516 any dirstate changes since that time. This command does not alter
3531 any dirstate changes since that time. This command does not alter
3517 the working directory.
3532 the working directory.
3518
3533
3519 Transactions are used to encapsulate the effects of all commands
3534 Transactions are used to encapsulate the effects of all commands
3520 that create new changesets or propagate existing changesets into a
3535 that create new changesets or propagate existing changesets into a
3521 repository. For example, the following commands are transactional,
3536 repository. For example, the following commands are transactional,
3522 and their effects can be rolled back:
3537 and their effects can be rolled back:
3523
3538
3524 - commit
3539 - commit
3525 - import
3540 - import
3526 - pull
3541 - pull
3527 - push (with this repository as the destination)
3542 - push (with this repository as the destination)
3528 - unbundle
3543 - unbundle
3529
3544
3530 This command is not intended for use on public repositories. Once
3545 This command is not intended for use on public repositories. Once
3531 changes are visible for pull by other users, rolling a transaction
3546 changes are visible for pull by other users, rolling a transaction
3532 back locally is ineffective (someone else may already have pulled
3547 back locally is ineffective (someone else may already have pulled
3533 the changes). Furthermore, a race is possible with readers of the
3548 the changes). Furthermore, a race is possible with readers of the
3534 repository; for example an in-progress pull from the repository
3549 repository; for example an in-progress pull from the repository
3535 may fail if a rollback is performed.
3550 may fail if a rollback is performed.
3536
3551
3537 Returns 0 on success, 1 if no rollback data is available.
3552 Returns 0 on success, 1 if no rollback data is available.
3538 """
3553 """
3539 return repo.rollback(opts.get('dry_run'))
3554 return repo.rollback(opts.get('dry_run'))
3540
3555
3541 def root(ui, repo):
3556 def root(ui, repo):
3542 """print the root (top) of the current working directory
3557 """print the root (top) of the current working directory
3543
3558
3544 Print the root directory of the current repository.
3559 Print the root directory of the current repository.
3545
3560
3546 Returns 0 on success.
3561 Returns 0 on success.
3547 """
3562 """
3548 ui.write(repo.root + "\n")
3563 ui.write(repo.root + "\n")
3549
3564
3550 def serve(ui, repo, **opts):
3565 def serve(ui, repo, **opts):
3551 """start stand-alone webserver
3566 """start stand-alone webserver
3552
3567
3553 Start a local HTTP repository browser and pull server. You can use
3568 Start a local HTTP repository browser and pull server. You can use
3554 this for ad-hoc sharing and browsing of repositories. It is
3569 this for ad-hoc sharing and browsing of repositories. It is
3555 recommended to use a real web server to serve a repository for
3570 recommended to use a real web server to serve a repository for
3556 longer periods of time.
3571 longer periods of time.
3557
3572
3558 Please note that the server does not implement access control.
3573 Please note that the server does not implement access control.
3559 This means that, by default, anybody can read from the server and
3574 This means that, by default, anybody can read from the server and
3560 nobody can write to it by default. Set the ``web.allow_push``
3575 nobody can write to it by default. Set the ``web.allow_push``
3561 option to ``*`` to allow everybody to push to the server. You
3576 option to ``*`` to allow everybody to push to the server. You
3562 should use a real web server if you need to authenticate users.
3577 should use a real web server if you need to authenticate users.
3563
3578
3564 By default, the server logs accesses to stdout and errors to
3579 By default, the server logs accesses to stdout and errors to
3565 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3580 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3566 files.
3581 files.
3567
3582
3568 To have the server choose a free port number to listen on, specify
3583 To have the server choose a free port number to listen on, specify
3569 a port number of 0; in this case, the server will print the port
3584 a port number of 0; in this case, the server will print the port
3570 number it uses.
3585 number it uses.
3571
3586
3572 Returns 0 on success.
3587 Returns 0 on success.
3573 """
3588 """
3574
3589
3575 if opts["stdio"]:
3590 if opts["stdio"]:
3576 if repo is None:
3591 if repo is None:
3577 raise error.RepoError(_("There is no Mercurial repository here"
3592 raise error.RepoError(_("There is no Mercurial repository here"
3578 " (.hg not found)"))
3593 " (.hg not found)"))
3579 s = sshserver.sshserver(ui, repo)
3594 s = sshserver.sshserver(ui, repo)
3580 s.serve_forever()
3595 s.serve_forever()
3581
3596
3582 # this way we can check if something was given in the command-line
3597 # this way we can check if something was given in the command-line
3583 if opts.get('port'):
3598 if opts.get('port'):
3584 opts['port'] = util.getport(opts.get('port'))
3599 opts['port'] = util.getport(opts.get('port'))
3585
3600
3586 baseui = repo and repo.baseui or ui
3601 baseui = repo and repo.baseui or ui
3587 optlist = ("name templates style address port prefix ipv6"
3602 optlist = ("name templates style address port prefix ipv6"
3588 " accesslog errorlog certificate encoding")
3603 " accesslog errorlog certificate encoding")
3589 for o in optlist.split():
3604 for o in optlist.split():
3590 val = opts.get(o, '')
3605 val = opts.get(o, '')
3591 if val in (None, ''): # should check against default options instead
3606 if val in (None, ''): # should check against default options instead
3592 continue
3607 continue
3593 baseui.setconfig("web", o, val)
3608 baseui.setconfig("web", o, val)
3594 if repo and repo.ui != baseui:
3609 if repo and repo.ui != baseui:
3595 repo.ui.setconfig("web", o, val)
3610 repo.ui.setconfig("web", o, val)
3596
3611
3597 o = opts.get('web_conf') or opts.get('webdir_conf')
3612 o = opts.get('web_conf') or opts.get('webdir_conf')
3598 if not o:
3613 if not o:
3599 if not repo:
3614 if not repo:
3600 raise error.RepoError(_("There is no Mercurial repository"
3615 raise error.RepoError(_("There is no Mercurial repository"
3601 " here (.hg not found)"))
3616 " here (.hg not found)"))
3602 o = repo.root
3617 o = repo.root
3603
3618
3604 app = hgweb.hgweb(o, baseui=ui)
3619 app = hgweb.hgweb(o, baseui=ui)
3605
3620
3606 class service(object):
3621 class service(object):
3607 def init(self):
3622 def init(self):
3608 util.set_signal_handler()
3623 util.set_signal_handler()
3609 self.httpd = hgweb.server.create_server(ui, app)
3624 self.httpd = hgweb.server.create_server(ui, app)
3610
3625
3611 if opts['port'] and not ui.verbose:
3626 if opts['port'] and not ui.verbose:
3612 return
3627 return
3613
3628
3614 if self.httpd.prefix:
3629 if self.httpd.prefix:
3615 prefix = self.httpd.prefix.strip('/') + '/'
3630 prefix = self.httpd.prefix.strip('/') + '/'
3616 else:
3631 else:
3617 prefix = ''
3632 prefix = ''
3618
3633
3619 port = ':%d' % self.httpd.port
3634 port = ':%d' % self.httpd.port
3620 if port == ':80':
3635 if port == ':80':
3621 port = ''
3636 port = ''
3622
3637
3623 bindaddr = self.httpd.addr
3638 bindaddr = self.httpd.addr
3624 if bindaddr == '0.0.0.0':
3639 if bindaddr == '0.0.0.0':
3625 bindaddr = '*'
3640 bindaddr = '*'
3626 elif ':' in bindaddr: # IPv6
3641 elif ':' in bindaddr: # IPv6
3627 bindaddr = '[%s]' % bindaddr
3642 bindaddr = '[%s]' % bindaddr
3628
3643
3629 fqaddr = self.httpd.fqaddr
3644 fqaddr = self.httpd.fqaddr
3630 if ':' in fqaddr:
3645 if ':' in fqaddr:
3631 fqaddr = '[%s]' % fqaddr
3646 fqaddr = '[%s]' % fqaddr
3632 if opts['port']:
3647 if opts['port']:
3633 write = ui.status
3648 write = ui.status
3634 else:
3649 else:
3635 write = ui.write
3650 write = ui.write
3636 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3651 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3637 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3652 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3638
3653
3639 def run(self):
3654 def run(self):
3640 self.httpd.serve_forever()
3655 self.httpd.serve_forever()
3641
3656
3642 service = service()
3657 service = service()
3643
3658
3644 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3659 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3645
3660
3646 def status(ui, repo, *pats, **opts):
3661 def status(ui, repo, *pats, **opts):
3647 """show changed files in the working directory
3662 """show changed files in the working directory
3648
3663
3649 Show status of files in the repository. If names are given, only
3664 Show status of files in the repository. If names are given, only
3650 files that match are shown. Files that are clean or ignored or
3665 files that match are shown. Files that are clean or ignored or
3651 the source of a copy/move operation, are not listed unless
3666 the source of a copy/move operation, are not listed unless
3652 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3667 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3653 Unless options described with "show only ..." are given, the
3668 Unless options described with "show only ..." are given, the
3654 options -mardu are used.
3669 options -mardu are used.
3655
3670
3656 Option -q/--quiet hides untracked (unknown and ignored) files
3671 Option -q/--quiet hides untracked (unknown and ignored) files
3657 unless explicitly requested with -u/--unknown or -i/--ignored.
3672 unless explicitly requested with -u/--unknown or -i/--ignored.
3658
3673
3659 .. note::
3674 .. note::
3660 status may appear to disagree with diff if permissions have
3675 status may appear to disagree with diff if permissions have
3661 changed or a merge has occurred. The standard diff format does
3676 changed or a merge has occurred. The standard diff format does
3662 not report permission changes and diff only reports changes
3677 not report permission changes and diff only reports changes
3663 relative to one merge parent.
3678 relative to one merge parent.
3664
3679
3665 If one revision is given, it is used as the base revision.
3680 If one revision is given, it is used as the base revision.
3666 If two revisions are given, the differences between them are
3681 If two revisions are given, the differences between them are
3667 shown. The --change option can also be used as a shortcut to list
3682 shown. The --change option can also be used as a shortcut to list
3668 the changed files of a revision from its first parent.
3683 the changed files of a revision from its first parent.
3669
3684
3670 The codes used to show the status of files are::
3685 The codes used to show the status of files are::
3671
3686
3672 M = modified
3687 M = modified
3673 A = added
3688 A = added
3674 R = removed
3689 R = removed
3675 C = clean
3690 C = clean
3676 ! = missing (deleted by non-hg command, but still tracked)
3691 ! = missing (deleted by non-hg command, but still tracked)
3677 ? = not tracked
3692 ? = not tracked
3678 I = ignored
3693 I = ignored
3679 = origin of the previous file listed as A (added)
3694 = origin of the previous file listed as A (added)
3680
3695
3681 Returns 0 on success.
3696 Returns 0 on success.
3682 """
3697 """
3683
3698
3684 revs = opts.get('rev')
3699 revs = opts.get('rev')
3685 change = opts.get('change')
3700 change = opts.get('change')
3686
3701
3687 if revs and change:
3702 if revs and change:
3688 msg = _('cannot specify --rev and --change at the same time')
3703 msg = _('cannot specify --rev and --change at the same time')
3689 raise util.Abort(msg)
3704 raise util.Abort(msg)
3690 elif change:
3705 elif change:
3691 node2 = repo.lookup(change)
3706 node2 = repo.lookup(change)
3692 node1 = repo[node2].parents()[0].node()
3707 node1 = repo[node2].parents()[0].node()
3693 else:
3708 else:
3694 node1, node2 = cmdutil.revpair(repo, revs)
3709 node1, node2 = cmdutil.revpair(repo, revs)
3695
3710
3696 cwd = (pats and repo.getcwd()) or ''
3711 cwd = (pats and repo.getcwd()) or ''
3697 end = opts.get('print0') and '\0' or '\n'
3712 end = opts.get('print0') and '\0' or '\n'
3698 copy = {}
3713 copy = {}
3699 states = 'modified added removed deleted unknown ignored clean'.split()
3714 states = 'modified added removed deleted unknown ignored clean'.split()
3700 show = [k for k in states if opts.get(k)]
3715 show = [k for k in states if opts.get(k)]
3701 if opts.get('all'):
3716 if opts.get('all'):
3702 show += ui.quiet and (states[:4] + ['clean']) or states
3717 show += ui.quiet and (states[:4] + ['clean']) or states
3703 if not show:
3718 if not show:
3704 show = ui.quiet and states[:4] or states[:5]
3719 show = ui.quiet and states[:4] or states[:5]
3705
3720
3706 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3721 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3707 'ignored' in show, 'clean' in show, 'unknown' in show,
3722 'ignored' in show, 'clean' in show, 'unknown' in show,
3708 opts.get('subrepos'))
3723 opts.get('subrepos'))
3709 changestates = zip(states, 'MAR!?IC', stat)
3724 changestates = zip(states, 'MAR!?IC', stat)
3710
3725
3711 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3726 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3712 ctxn = repo[nullid]
3727 ctxn = repo[nullid]
3713 ctx1 = repo[node1]
3728 ctx1 = repo[node1]
3714 ctx2 = repo[node2]
3729 ctx2 = repo[node2]
3715 added = stat[1]
3730 added = stat[1]
3716 if node2 is None:
3731 if node2 is None:
3717 added = stat[0] + stat[1] # merged?
3732 added = stat[0] + stat[1] # merged?
3718
3733
3719 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3734 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3720 if k in added:
3735 if k in added:
3721 copy[k] = v
3736 copy[k] = v
3722 elif v in added:
3737 elif v in added:
3723 copy[v] = k
3738 copy[v] = k
3724
3739
3725 for state, char, files in changestates:
3740 for state, char, files in changestates:
3726 if state in show:
3741 if state in show:
3727 format = "%s %%s%s" % (char, end)
3742 format = "%s %%s%s" % (char, end)
3728 if opts.get('no_status'):
3743 if opts.get('no_status'):
3729 format = "%%s%s" % end
3744 format = "%%s%s" % end
3730
3745
3731 for f in files:
3746 for f in files:
3732 ui.write(format % repo.pathto(f, cwd),
3747 ui.write(format % repo.pathto(f, cwd),
3733 label='status.' + state)
3748 label='status.' + state)
3734 if f in copy:
3749 if f in copy:
3735 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3750 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3736 label='status.copied')
3751 label='status.copied')
3737
3752
3738 def summary(ui, repo, **opts):
3753 def summary(ui, repo, **opts):
3739 """summarize working directory state
3754 """summarize working directory state
3740
3755
3741 This generates a brief summary of the working directory state,
3756 This generates a brief summary of the working directory state,
3742 including parents, branch, commit status, and available updates.
3757 including parents, branch, commit status, and available updates.
3743
3758
3744 With the --remote option, this will check the default paths for
3759 With the --remote option, this will check the default paths for
3745 incoming and outgoing changes. This can be time-consuming.
3760 incoming and outgoing changes. This can be time-consuming.
3746
3761
3747 Returns 0 on success.
3762 Returns 0 on success.
3748 """
3763 """
3749
3764
3750 ctx = repo[None]
3765 ctx = repo[None]
3751 parents = ctx.parents()
3766 parents = ctx.parents()
3752 pnode = parents[0].node()
3767 pnode = parents[0].node()
3753
3768
3754 for p in parents:
3769 for p in parents:
3755 # label with log.changeset (instead of log.parent) since this
3770 # label with log.changeset (instead of log.parent) since this
3756 # shows a working directory parent *changeset*:
3771 # shows a working directory parent *changeset*:
3757 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3772 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3758 label='log.changeset')
3773 label='log.changeset')
3759 ui.write(' '.join(p.tags()), label='log.tag')
3774 ui.write(' '.join(p.tags()), label='log.tag')
3760 if p.bookmarks():
3775 if p.bookmarks():
3761 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3776 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3762 if p.rev() == -1:
3777 if p.rev() == -1:
3763 if not len(repo):
3778 if not len(repo):
3764 ui.write(_(' (empty repository)'))
3779 ui.write(_(' (empty repository)'))
3765 else:
3780 else:
3766 ui.write(_(' (no revision checked out)'))
3781 ui.write(_(' (no revision checked out)'))
3767 ui.write('\n')
3782 ui.write('\n')
3768 if p.description():
3783 if p.description():
3769 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3784 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3770 label='log.summary')
3785 label='log.summary')
3771
3786
3772 branch = ctx.branch()
3787 branch = ctx.branch()
3773 bheads = repo.branchheads(branch)
3788 bheads = repo.branchheads(branch)
3774 m = _('branch: %s\n') % branch
3789 m = _('branch: %s\n') % branch
3775 if branch != 'default':
3790 if branch != 'default':
3776 ui.write(m, label='log.branch')
3791 ui.write(m, label='log.branch')
3777 else:
3792 else:
3778 ui.status(m, label='log.branch')
3793 ui.status(m, label='log.branch')
3779
3794
3780 st = list(repo.status(unknown=True))[:6]
3795 st = list(repo.status(unknown=True))[:6]
3781
3796
3782 c = repo.dirstate.copies()
3797 c = repo.dirstate.copies()
3783 copied, renamed = [], []
3798 copied, renamed = [], []
3784 for d, s in c.iteritems():
3799 for d, s in c.iteritems():
3785 if s in st[2]:
3800 if s in st[2]:
3786 st[2].remove(s)
3801 st[2].remove(s)
3787 renamed.append(d)
3802 renamed.append(d)
3788 else:
3803 else:
3789 copied.append(d)
3804 copied.append(d)
3790 if d in st[1]:
3805 if d in st[1]:
3791 st[1].remove(d)
3806 st[1].remove(d)
3792 st.insert(3, renamed)
3807 st.insert(3, renamed)
3793 st.insert(4, copied)
3808 st.insert(4, copied)
3794
3809
3795 ms = mergemod.mergestate(repo)
3810 ms = mergemod.mergestate(repo)
3796 st.append([f for f in ms if ms[f] == 'u'])
3811 st.append([f for f in ms if ms[f] == 'u'])
3797
3812
3798 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3813 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3799 st.append(subs)
3814 st.append(subs)
3800
3815
3801 labels = [ui.label(_('%d modified'), 'status.modified'),
3816 labels = [ui.label(_('%d modified'), 'status.modified'),
3802 ui.label(_('%d added'), 'status.added'),
3817 ui.label(_('%d added'), 'status.added'),
3803 ui.label(_('%d removed'), 'status.removed'),
3818 ui.label(_('%d removed'), 'status.removed'),
3804 ui.label(_('%d renamed'), 'status.copied'),
3819 ui.label(_('%d renamed'), 'status.copied'),
3805 ui.label(_('%d copied'), 'status.copied'),
3820 ui.label(_('%d copied'), 'status.copied'),
3806 ui.label(_('%d deleted'), 'status.deleted'),
3821 ui.label(_('%d deleted'), 'status.deleted'),
3807 ui.label(_('%d unknown'), 'status.unknown'),
3822 ui.label(_('%d unknown'), 'status.unknown'),
3808 ui.label(_('%d ignored'), 'status.ignored'),
3823 ui.label(_('%d ignored'), 'status.ignored'),
3809 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3824 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3810 ui.label(_('%d subrepos'), 'status.modified')]
3825 ui.label(_('%d subrepos'), 'status.modified')]
3811 t = []
3826 t = []
3812 for s, l in zip(st, labels):
3827 for s, l in zip(st, labels):
3813 if s:
3828 if s:
3814 t.append(l % len(s))
3829 t.append(l % len(s))
3815
3830
3816 t = ', '.join(t)
3831 t = ', '.join(t)
3817 cleanworkdir = False
3832 cleanworkdir = False
3818
3833
3819 if len(parents) > 1:
3834 if len(parents) > 1:
3820 t += _(' (merge)')
3835 t += _(' (merge)')
3821 elif branch != parents[0].branch():
3836 elif branch != parents[0].branch():
3822 t += _(' (new branch)')
3837 t += _(' (new branch)')
3823 elif (parents[0].extra().get('close') and
3838 elif (parents[0].extra().get('close') and
3824 pnode in repo.branchheads(branch, closed=True)):
3839 pnode in repo.branchheads(branch, closed=True)):
3825 t += _(' (head closed)')
3840 t += _(' (head closed)')
3826 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3841 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3827 t += _(' (clean)')
3842 t += _(' (clean)')
3828 cleanworkdir = True
3843 cleanworkdir = True
3829 elif pnode not in bheads:
3844 elif pnode not in bheads:
3830 t += _(' (new branch head)')
3845 t += _(' (new branch head)')
3831
3846
3832 if cleanworkdir:
3847 if cleanworkdir:
3833 ui.status(_('commit: %s\n') % t.strip())
3848 ui.status(_('commit: %s\n') % t.strip())
3834 else:
3849 else:
3835 ui.write(_('commit: %s\n') % t.strip())
3850 ui.write(_('commit: %s\n') % t.strip())
3836
3851
3837 # all ancestors of branch heads - all ancestors of parent = new csets
3852 # all ancestors of branch heads - all ancestors of parent = new csets
3838 new = [0] * len(repo)
3853 new = [0] * len(repo)
3839 cl = repo.changelog
3854 cl = repo.changelog
3840 for a in [cl.rev(n) for n in bheads]:
3855 for a in [cl.rev(n) for n in bheads]:
3841 new[a] = 1
3856 new[a] = 1
3842 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3857 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3843 new[a] = 1
3858 new[a] = 1
3844 for a in [p.rev() for p in parents]:
3859 for a in [p.rev() for p in parents]:
3845 if a >= 0:
3860 if a >= 0:
3846 new[a] = 0
3861 new[a] = 0
3847 for a in cl.ancestors(*[p.rev() for p in parents]):
3862 for a in cl.ancestors(*[p.rev() for p in parents]):
3848 new[a] = 0
3863 new[a] = 0
3849 new = sum(new)
3864 new = sum(new)
3850
3865
3851 if new == 0:
3866 if new == 0:
3852 ui.status(_('update: (current)\n'))
3867 ui.status(_('update: (current)\n'))
3853 elif pnode not in bheads:
3868 elif pnode not in bheads:
3854 ui.write(_('update: %d new changesets (update)\n') % new)
3869 ui.write(_('update: %d new changesets (update)\n') % new)
3855 else:
3870 else:
3856 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3871 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3857 (new, len(bheads)))
3872 (new, len(bheads)))
3858
3873
3859 if opts.get('remote'):
3874 if opts.get('remote'):
3860 t = []
3875 t = []
3861 source, branches = hg.parseurl(ui.expandpath('default'))
3876 source, branches = hg.parseurl(ui.expandpath('default'))
3862 other = hg.repository(hg.remoteui(repo, {}), source)
3877 other = hg.repository(hg.remoteui(repo, {}), source)
3863 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3878 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3864 ui.debug('comparing with %s\n' % url.hidepassword(source))
3879 ui.debug('comparing with %s\n' % url.hidepassword(source))
3865 repo.ui.pushbuffer()
3880 repo.ui.pushbuffer()
3866 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3881 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3867 repo.ui.popbuffer()
3882 repo.ui.popbuffer()
3868 if incoming:
3883 if incoming:
3869 t.append(_('1 or more incoming'))
3884 t.append(_('1 or more incoming'))
3870
3885
3871 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3886 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3872 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3887 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3873 other = hg.repository(hg.remoteui(repo, {}), dest)
3888 other = hg.repository(hg.remoteui(repo, {}), dest)
3874 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3889 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3875 repo.ui.pushbuffer()
3890 repo.ui.pushbuffer()
3876 o = discovery.findoutgoing(repo, other)
3891 o = discovery.findoutgoing(repo, other)
3877 repo.ui.popbuffer()
3892 repo.ui.popbuffer()
3878 o = repo.changelog.nodesbetween(o, None)[0]
3893 o = repo.changelog.nodesbetween(o, None)[0]
3879 if o:
3894 if o:
3880 t.append(_('%d outgoing') % len(o))
3895 t.append(_('%d outgoing') % len(o))
3881 if 'bookmarks' in other.listkeys('namespaces'):
3896 if 'bookmarks' in other.listkeys('namespaces'):
3882 lmarks = repo.listkeys('bookmarks')
3897 lmarks = repo.listkeys('bookmarks')
3883 rmarks = other.listkeys('bookmarks')
3898 rmarks = other.listkeys('bookmarks')
3884 diff = set(rmarks) - set(lmarks)
3899 diff = set(rmarks) - set(lmarks)
3885 if len(diff) > 0:
3900 if len(diff) > 0:
3886 t.append(_('%d incoming bookmarks') % len(diff))
3901 t.append(_('%d incoming bookmarks') % len(diff))
3887 diff = set(lmarks) - set(rmarks)
3902 diff = set(lmarks) - set(rmarks)
3888 if len(diff) > 0:
3903 if len(diff) > 0:
3889 t.append(_('%d outgoing bookmarks') % len(diff))
3904 t.append(_('%d outgoing bookmarks') % len(diff))
3890
3905
3891 if t:
3906 if t:
3892 ui.write(_('remote: %s\n') % (', '.join(t)))
3907 ui.write(_('remote: %s\n') % (', '.join(t)))
3893 else:
3908 else:
3894 ui.status(_('remote: (synced)\n'))
3909 ui.status(_('remote: (synced)\n'))
3895
3910
3896 def tag(ui, repo, name1, *names, **opts):
3911 def tag(ui, repo, name1, *names, **opts):
3897 """add one or more tags for the current or given revision
3912 """add one or more tags for the current or given revision
3898
3913
3899 Name a particular revision using <name>.
3914 Name a particular revision using <name>.
3900
3915
3901 Tags are used to name particular revisions of the repository and are
3916 Tags are used to name particular revisions of the repository and are
3902 very useful to compare different revisions, to go back to significant
3917 very useful to compare different revisions, to go back to significant
3903 earlier versions or to mark branch points as releases, etc. Changing
3918 earlier versions or to mark branch points as releases, etc. Changing
3904 an existing tag is normally disallowed; use -f/--force to override.
3919 an existing tag is normally disallowed; use -f/--force to override.
3905
3920
3906 If no revision is given, the parent of the working directory is
3921 If no revision is given, the parent of the working directory is
3907 used, or tip if no revision is checked out.
3922 used, or tip if no revision is checked out.
3908
3923
3909 To facilitate version control, distribution, and merging of tags,
3924 To facilitate version control, distribution, and merging of tags,
3910 they are stored as a file named ".hgtags" which is managed similarly
3925 they are stored as a file named ".hgtags" which is managed similarly
3911 to other project files and can be hand-edited if necessary. This
3926 to other project files and can be hand-edited if necessary. This
3912 also means that tagging creates a new commit. The file
3927 also means that tagging creates a new commit. The file
3913 ".hg/localtags" is used for local tags (not shared among
3928 ".hg/localtags" is used for local tags (not shared among
3914 repositories).
3929 repositories).
3915
3930
3916 Tag commits are usually made at the head of a branch. If the parent
3931 Tag commits are usually made at the head of a branch. If the parent
3917 of the working directory is not a branch head, :hg:`tag` aborts; use
3932 of the working directory is not a branch head, :hg:`tag` aborts; use
3918 -f/--force to force the tag commit to be based on a non-head
3933 -f/--force to force the tag commit to be based on a non-head
3919 changeset.
3934 changeset.
3920
3935
3921 See :hg:`help dates` for a list of formats valid for -d/--date.
3936 See :hg:`help dates` for a list of formats valid for -d/--date.
3922
3937
3923 Since tag names have priority over branch names during revision
3938 Since tag names have priority over branch names during revision
3924 lookup, using an existing branch name as a tag name is discouraged.
3939 lookup, using an existing branch name as a tag name is discouraged.
3925
3940
3926 Returns 0 on success.
3941 Returns 0 on success.
3927 """
3942 """
3928
3943
3929 rev_ = "."
3944 rev_ = "."
3930 names = [t.strip() for t in (name1,) + names]
3945 names = [t.strip() for t in (name1,) + names]
3931 if len(names) != len(set(names)):
3946 if len(names) != len(set(names)):
3932 raise util.Abort(_('tag names must be unique'))
3947 raise util.Abort(_('tag names must be unique'))
3933 for n in names:
3948 for n in names:
3934 if n in ['tip', '.', 'null']:
3949 if n in ['tip', '.', 'null']:
3935 raise util.Abort(_('the name \'%s\' is reserved') % n)
3950 raise util.Abort(_('the name \'%s\' is reserved') % n)
3936 if not n:
3951 if not n:
3937 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3952 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3938 if opts.get('rev') and opts.get('remove'):
3953 if opts.get('rev') and opts.get('remove'):
3939 raise util.Abort(_("--rev and --remove are incompatible"))
3954 raise util.Abort(_("--rev and --remove are incompatible"))
3940 if opts.get('rev'):
3955 if opts.get('rev'):
3941 rev_ = opts['rev']
3956 rev_ = opts['rev']
3942 message = opts.get('message')
3957 message = opts.get('message')
3943 if opts.get('remove'):
3958 if opts.get('remove'):
3944 expectedtype = opts.get('local') and 'local' or 'global'
3959 expectedtype = opts.get('local') and 'local' or 'global'
3945 for n in names:
3960 for n in names:
3946 if not repo.tagtype(n):
3961 if not repo.tagtype(n):
3947 raise util.Abort(_('tag \'%s\' does not exist') % n)
3962 raise util.Abort(_('tag \'%s\' does not exist') % n)
3948 if repo.tagtype(n) != expectedtype:
3963 if repo.tagtype(n) != expectedtype:
3949 if expectedtype == 'global':
3964 if expectedtype == 'global':
3950 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3965 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3951 else:
3966 else:
3952 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3967 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3953 rev_ = nullid
3968 rev_ = nullid
3954 if not message:
3969 if not message:
3955 # we don't translate commit messages
3970 # we don't translate commit messages
3956 message = 'Removed tag %s' % ', '.join(names)
3971 message = 'Removed tag %s' % ', '.join(names)
3957 elif not opts.get('force'):
3972 elif not opts.get('force'):
3958 for n in names:
3973 for n in names:
3959 if n in repo.tags():
3974 if n in repo.tags():
3960 raise util.Abort(_('tag \'%s\' already exists '
3975 raise util.Abort(_('tag \'%s\' already exists '
3961 '(use -f to force)') % n)
3976 '(use -f to force)') % n)
3962 if not opts.get('local'):
3977 if not opts.get('local'):
3963 p1, p2 = repo.dirstate.parents()
3978 p1, p2 = repo.dirstate.parents()
3964 if p2 != nullid:
3979 if p2 != nullid:
3965 raise util.Abort(_('uncommitted merge'))
3980 raise util.Abort(_('uncommitted merge'))
3966 bheads = repo.branchheads()
3981 bheads = repo.branchheads()
3967 if not opts.get('force') and bheads and p1 not in bheads:
3982 if not opts.get('force') and bheads and p1 not in bheads:
3968 raise util.Abort(_('not at a branch head (use -f to force)'))
3983 raise util.Abort(_('not at a branch head (use -f to force)'))
3969 r = cmdutil.revsingle(repo, rev_).node()
3984 r = cmdutil.revsingle(repo, rev_).node()
3970
3985
3971 if not message:
3986 if not message:
3972 # we don't translate commit messages
3987 # we don't translate commit messages
3973 message = ('Added tag %s for changeset %s' %
3988 message = ('Added tag %s for changeset %s' %
3974 (', '.join(names), short(r)))
3989 (', '.join(names), short(r)))
3975
3990
3976 date = opts.get('date')
3991 date = opts.get('date')
3977 if date:
3992 if date:
3978 date = util.parsedate(date)
3993 date = util.parsedate(date)
3979
3994
3980 if opts.get('edit'):
3995 if opts.get('edit'):
3981 message = ui.edit(message, ui.username())
3996 message = ui.edit(message, ui.username())
3982
3997
3983 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3998 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3984
3999
3985 def tags(ui, repo):
4000 def tags(ui, repo):
3986 """list repository tags
4001 """list repository tags
3987
4002
3988 This lists both regular and local tags. When the -v/--verbose
4003 This lists both regular and local tags. When the -v/--verbose
3989 switch is used, a third column "local" is printed for local tags.
4004 switch is used, a third column "local" is printed for local tags.
3990
4005
3991 Returns 0 on success.
4006 Returns 0 on success.
3992 """
4007 """
3993
4008
3994 hexfunc = ui.debugflag and hex or short
4009 hexfunc = ui.debugflag and hex or short
3995 tagtype = ""
4010 tagtype = ""
3996
4011
3997 for t, n in reversed(repo.tagslist()):
4012 for t, n in reversed(repo.tagslist()):
3998 if ui.quiet:
4013 if ui.quiet:
3999 ui.write("%s\n" % t)
4014 ui.write("%s\n" % t)
4000 continue
4015 continue
4001
4016
4002 try:
4017 try:
4003 hn = hexfunc(n)
4018 hn = hexfunc(n)
4004 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4019 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4005 except error.LookupError:
4020 except error.LookupError:
4006 r = " ?:%s" % hn
4021 r = " ?:%s" % hn
4007 else:
4022 else:
4008 spaces = " " * (30 - encoding.colwidth(t))
4023 spaces = " " * (30 - encoding.colwidth(t))
4009 if ui.verbose:
4024 if ui.verbose:
4010 if repo.tagtype(t) == 'local':
4025 if repo.tagtype(t) == 'local':
4011 tagtype = " local"
4026 tagtype = " local"
4012 else:
4027 else:
4013 tagtype = ""
4028 tagtype = ""
4014 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4029 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4015
4030
4016 def tip(ui, repo, **opts):
4031 def tip(ui, repo, **opts):
4017 """show the tip revision
4032 """show the tip revision
4018
4033
4019 The tip revision (usually just called the tip) is the changeset
4034 The tip revision (usually just called the tip) is the changeset
4020 most recently added to the repository (and therefore the most
4035 most recently added to the repository (and therefore the most
4021 recently changed head).
4036 recently changed head).
4022
4037
4023 If you have just made a commit, that commit will be the tip. If
4038 If you have just made a commit, that commit will be the tip. If
4024 you have just pulled changes from another repository, the tip of
4039 you have just pulled changes from another repository, the tip of
4025 that repository becomes the current tip. The "tip" tag is special
4040 that repository becomes the current tip. The "tip" tag is special
4026 and cannot be renamed or assigned to a different changeset.
4041 and cannot be renamed or assigned to a different changeset.
4027
4042
4028 Returns 0 on success.
4043 Returns 0 on success.
4029 """
4044 """
4030 displayer = cmdutil.show_changeset(ui, repo, opts)
4045 displayer = cmdutil.show_changeset(ui, repo, opts)
4031 displayer.show(repo[len(repo) - 1])
4046 displayer.show(repo[len(repo) - 1])
4032 displayer.close()
4047 displayer.close()
4033
4048
4034 def unbundle(ui, repo, fname1, *fnames, **opts):
4049 def unbundle(ui, repo, fname1, *fnames, **opts):
4035 """apply one or more changegroup files
4050 """apply one or more changegroup files
4036
4051
4037 Apply one or more compressed changegroup files generated by the
4052 Apply one or more compressed changegroup files generated by the
4038 bundle command.
4053 bundle command.
4039
4054
4040 Returns 0 on success, 1 if an update has unresolved files.
4055 Returns 0 on success, 1 if an update has unresolved files.
4041 """
4056 """
4042 fnames = (fname1,) + fnames
4057 fnames = (fname1,) + fnames
4043
4058
4044 lock = repo.lock()
4059 lock = repo.lock()
4045 wc = repo['.']
4060 wc = repo['.']
4046 try:
4061 try:
4047 for fname in fnames:
4062 for fname in fnames:
4048 f = url.open(ui, fname)
4063 f = url.open(ui, fname)
4049 gen = changegroup.readbundle(f, fname)
4064 gen = changegroup.readbundle(f, fname)
4050 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4065 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4051 lock=lock)
4066 lock=lock)
4052 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4067 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4053 finally:
4068 finally:
4054 lock.release()
4069 lock.release()
4055 return postincoming(ui, repo, modheads, opts.get('update'), None)
4070 return postincoming(ui, repo, modheads, opts.get('update'), None)
4056
4071
4057 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4072 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4058 """update working directory (or switch revisions)
4073 """update working directory (or switch revisions)
4059
4074
4060 Update the repository's working directory to the specified
4075 Update the repository's working directory to the specified
4061 changeset. If no changeset is specified, update to the tip of the
4076 changeset. If no changeset is specified, update to the tip of the
4062 current named branch.
4077 current named branch.
4063
4078
4064 If the changeset is not a descendant of the working directory's
4079 If the changeset is not a descendant of the working directory's
4065 parent, the update is aborted. With the -c/--check option, the
4080 parent, the update is aborted. With the -c/--check option, the
4066 working directory is checked for uncommitted changes; if none are
4081 working directory is checked for uncommitted changes; if none are
4067 found, the working directory is updated to the specified
4082 found, the working directory is updated to the specified
4068 changeset.
4083 changeset.
4069
4084
4070 The following rules apply when the working directory contains
4085 The following rules apply when the working directory contains
4071 uncommitted changes:
4086 uncommitted changes:
4072
4087
4073 1. If neither -c/--check nor -C/--clean is specified, and if
4088 1. If neither -c/--check nor -C/--clean is specified, and if
4074 the requested changeset is an ancestor or descendant of
4089 the requested changeset is an ancestor or descendant of
4075 the working directory's parent, the uncommitted changes
4090 the working directory's parent, the uncommitted changes
4076 are merged into the requested changeset and the merged
4091 are merged into the requested changeset and the merged
4077 result is left uncommitted. If the requested changeset is
4092 result is left uncommitted. If the requested changeset is
4078 not an ancestor or descendant (that is, it is on another
4093 not an ancestor or descendant (that is, it is on another
4079 branch), the update is aborted and the uncommitted changes
4094 branch), the update is aborted and the uncommitted changes
4080 are preserved.
4095 are preserved.
4081
4096
4082 2. With the -c/--check option, the update is aborted and the
4097 2. With the -c/--check option, the update is aborted and the
4083 uncommitted changes are preserved.
4098 uncommitted changes are preserved.
4084
4099
4085 3. With the -C/--clean option, uncommitted changes are discarded and
4100 3. With the -C/--clean option, uncommitted changes are discarded and
4086 the working directory is updated to the requested changeset.
4101 the working directory is updated to the requested changeset.
4087
4102
4088 Use null as the changeset to remove the working directory (like
4103 Use null as the changeset to remove the working directory (like
4089 :hg:`clone -U`).
4104 :hg:`clone -U`).
4090
4105
4091 If you want to update just one file to an older changeset, use
4106 If you want to update just one file to an older changeset, use
4092 :hg:`revert`.
4107 :hg:`revert`.
4093
4108
4094 See :hg:`help dates` for a list of formats valid for -d/--date.
4109 See :hg:`help dates` for a list of formats valid for -d/--date.
4095
4110
4096 Returns 0 on success, 1 if there are unresolved files.
4111 Returns 0 on success, 1 if there are unresolved files.
4097 """
4112 """
4098 if rev and node:
4113 if rev and node:
4099 raise util.Abort(_("please specify just one revision"))
4114 raise util.Abort(_("please specify just one revision"))
4100
4115
4101 if rev is None or rev == '':
4116 if rev is None or rev == '':
4102 rev = node
4117 rev = node
4103
4118
4104 # if we defined a bookmark, we have to remember the original bookmark name
4119 # if we defined a bookmark, we have to remember the original bookmark name
4105 brev = rev
4120 brev = rev
4106 rev = cmdutil.revsingle(repo, rev, rev).rev()
4121 rev = cmdutil.revsingle(repo, rev, rev).rev()
4107
4122
4108 if check and clean:
4123 if check and clean:
4109 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4124 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4110
4125
4111 if check:
4126 if check:
4112 # we could use dirty() but we can ignore merge and branch trivia
4127 # we could use dirty() but we can ignore merge and branch trivia
4113 c = repo[None]
4128 c = repo[None]
4114 if c.modified() or c.added() or c.removed():
4129 if c.modified() or c.added() or c.removed():
4115 raise util.Abort(_("uncommitted local changes"))
4130 raise util.Abort(_("uncommitted local changes"))
4116
4131
4117 if date:
4132 if date:
4118 if rev:
4133 if rev:
4119 raise util.Abort(_("you can't specify a revision and a date"))
4134 raise util.Abort(_("you can't specify a revision and a date"))
4120 rev = cmdutil.finddate(ui, repo, date)
4135 rev = cmdutil.finddate(ui, repo, date)
4121
4136
4122 if clean or check:
4137 if clean or check:
4123 ret = hg.clean(repo, rev)
4138 ret = hg.clean(repo, rev)
4124 else:
4139 else:
4125 ret = hg.update(repo, rev)
4140 ret = hg.update(repo, rev)
4126
4141
4127 if brev in repo._bookmarks:
4142 if brev in repo._bookmarks:
4128 bookmarks.setcurrent(repo, brev)
4143 bookmarks.setcurrent(repo, brev)
4129
4144
4130 return ret
4145 return ret
4131
4146
4132 def verify(ui, repo):
4147 def verify(ui, repo):
4133 """verify the integrity of the repository
4148 """verify the integrity of the repository
4134
4149
4135 Verify the integrity of the current repository.
4150 Verify the integrity of the current repository.
4136
4151
4137 This will perform an extensive check of the repository's
4152 This will perform an extensive check of the repository's
4138 integrity, validating the hashes and checksums of each entry in
4153 integrity, validating the hashes and checksums of each entry in
4139 the changelog, manifest, and tracked files, as well as the
4154 the changelog, manifest, and tracked files, as well as the
4140 integrity of their crosslinks and indices.
4155 integrity of their crosslinks and indices.
4141
4156
4142 Returns 0 on success, 1 if errors are encountered.
4157 Returns 0 on success, 1 if errors are encountered.
4143 """
4158 """
4144 return hg.verify(repo)
4159 return hg.verify(repo)
4145
4160
4146 def version_(ui):
4161 def version_(ui):
4147 """output version and copyright information"""
4162 """output version and copyright information"""
4148 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4163 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4149 % util.version())
4164 % util.version())
4150 ui.status(_(
4165 ui.status(_(
4151 "(see http://mercurial.selenic.com for more information)\n"
4166 "(see http://mercurial.selenic.com for more information)\n"
4152 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4167 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4153 "This is free software; see the source for copying conditions. "
4168 "This is free software; see the source for copying conditions. "
4154 "There is NO\nwarranty; "
4169 "There is NO\nwarranty; "
4155 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4170 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4156 ))
4171 ))
4157
4172
4158 # Command options and aliases are listed here, alphabetically
4173 # Command options and aliases are listed here, alphabetically
4159
4174
4160 globalopts = [
4175 globalopts = [
4161 ('R', 'repository', '',
4176 ('R', 'repository', '',
4162 _('repository root directory or name of overlay bundle file'),
4177 _('repository root directory or name of overlay bundle file'),
4163 _('REPO')),
4178 _('REPO')),
4164 ('', 'cwd', '',
4179 ('', 'cwd', '',
4165 _('change working directory'), _('DIR')),
4180 _('change working directory'), _('DIR')),
4166 ('y', 'noninteractive', None,
4181 ('y', 'noninteractive', None,
4167 _('do not prompt, assume \'yes\' for any required answers')),
4182 _('do not prompt, assume \'yes\' for any required answers')),
4168 ('q', 'quiet', None, _('suppress output')),
4183 ('q', 'quiet', None, _('suppress output')),
4169 ('v', 'verbose', None, _('enable additional output')),
4184 ('v', 'verbose', None, _('enable additional output')),
4170 ('', 'config', [],
4185 ('', 'config', [],
4171 _('set/override config option (use \'section.name=value\')'),
4186 _('set/override config option (use \'section.name=value\')'),
4172 _('CONFIG')),
4187 _('CONFIG')),
4173 ('', 'debug', None, _('enable debugging output')),
4188 ('', 'debug', None, _('enable debugging output')),
4174 ('', 'debugger', None, _('start debugger')),
4189 ('', 'debugger', None, _('start debugger')),
4175 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4190 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4176 _('ENCODE')),
4191 _('ENCODE')),
4177 ('', 'encodingmode', encoding.encodingmode,
4192 ('', 'encodingmode', encoding.encodingmode,
4178 _('set the charset encoding mode'), _('MODE')),
4193 _('set the charset encoding mode'), _('MODE')),
4179 ('', 'traceback', None, _('always print a traceback on exception')),
4194 ('', 'traceback', None, _('always print a traceback on exception')),
4180 ('', 'time', None, _('time how long the command takes')),
4195 ('', 'time', None, _('time how long the command takes')),
4181 ('', 'profile', None, _('print command execution profile')),
4196 ('', 'profile', None, _('print command execution profile')),
4182 ('', 'version', None, _('output version information and exit')),
4197 ('', 'version', None, _('output version information and exit')),
4183 ('h', 'help', None, _('display help and exit')),
4198 ('h', 'help', None, _('display help and exit')),
4184 ]
4199 ]
4185
4200
4186 dryrunopts = [('n', 'dry-run', None,
4201 dryrunopts = [('n', 'dry-run', None,
4187 _('do not perform actions, just print output'))]
4202 _('do not perform actions, just print output'))]
4188
4203
4189 remoteopts = [
4204 remoteopts = [
4190 ('e', 'ssh', '',
4205 ('e', 'ssh', '',
4191 _('specify ssh command to use'), _('CMD')),
4206 _('specify ssh command to use'), _('CMD')),
4192 ('', 'remotecmd', '',
4207 ('', 'remotecmd', '',
4193 _('specify hg command to run on the remote side'), _('CMD')),
4208 _('specify hg command to run on the remote side'), _('CMD')),
4194 ('', 'insecure', None,
4209 ('', 'insecure', None,
4195 _('do not verify server certificate (ignoring web.cacerts config)')),
4210 _('do not verify server certificate (ignoring web.cacerts config)')),
4196 ]
4211 ]
4197
4212
4198 walkopts = [
4213 walkopts = [
4199 ('I', 'include', [],
4214 ('I', 'include', [],
4200 _('include names matching the given patterns'), _('PATTERN')),
4215 _('include names matching the given patterns'), _('PATTERN')),
4201 ('X', 'exclude', [],
4216 ('X', 'exclude', [],
4202 _('exclude names matching the given patterns'), _('PATTERN')),
4217 _('exclude names matching the given patterns'), _('PATTERN')),
4203 ]
4218 ]
4204
4219
4205 commitopts = [
4220 commitopts = [
4206 ('m', 'message', '',
4221 ('m', 'message', '',
4207 _('use text as commit message'), _('TEXT')),
4222 _('use text as commit message'), _('TEXT')),
4208 ('l', 'logfile', '',
4223 ('l', 'logfile', '',
4209 _('read commit message from file'), _('FILE')),
4224 _('read commit message from file'), _('FILE')),
4210 ]
4225 ]
4211
4226
4212 commitopts2 = [
4227 commitopts2 = [
4213 ('d', 'date', '',
4228 ('d', 'date', '',
4214 _('record datecode as commit date'), _('DATE')),
4229 _('record datecode as commit date'), _('DATE')),
4215 ('u', 'user', '',
4230 ('u', 'user', '',
4216 _('record the specified user as committer'), _('USER')),
4231 _('record the specified user as committer'), _('USER')),
4217 ]
4232 ]
4218
4233
4219 templateopts = [
4234 templateopts = [
4220 ('', 'style', '',
4235 ('', 'style', '',
4221 _('display using template map file'), _('STYLE')),
4236 _('display using template map file'), _('STYLE')),
4222 ('', 'template', '',
4237 ('', 'template', '',
4223 _('display with template'), _('TEMPLATE')),
4238 _('display with template'), _('TEMPLATE')),
4224 ]
4239 ]
4225
4240
4226 logopts = [
4241 logopts = [
4227 ('p', 'patch', None, _('show patch')),
4242 ('p', 'patch', None, _('show patch')),
4228 ('g', 'git', None, _('use git extended diff format')),
4243 ('g', 'git', None, _('use git extended diff format')),
4229 ('l', 'limit', '',
4244 ('l', 'limit', '',
4230 _('limit number of changes displayed'), _('NUM')),
4245 _('limit number of changes displayed'), _('NUM')),
4231 ('M', 'no-merges', None, _('do not show merges')),
4246 ('M', 'no-merges', None, _('do not show merges')),
4232 ('', 'stat', None, _('output diffstat-style summary of changes')),
4247 ('', 'stat', None, _('output diffstat-style summary of changes')),
4233 ] + templateopts
4248 ] + templateopts
4234
4249
4235 diffopts = [
4250 diffopts = [
4236 ('a', 'text', None, _('treat all files as text')),
4251 ('a', 'text', None, _('treat all files as text')),
4237 ('g', 'git', None, _('use git extended diff format')),
4252 ('g', 'git', None, _('use git extended diff format')),
4238 ('', 'nodates', None, _('omit dates from diff headers'))
4253 ('', 'nodates', None, _('omit dates from diff headers'))
4239 ]
4254 ]
4240
4255
4241 diffopts2 = [
4256 diffopts2 = [
4242 ('p', 'show-function', None, _('show which function each change is in')),
4257 ('p', 'show-function', None, _('show which function each change is in')),
4243 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4258 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4244 ('w', 'ignore-all-space', None,
4259 ('w', 'ignore-all-space', None,
4245 _('ignore white space when comparing lines')),
4260 _('ignore white space when comparing lines')),
4246 ('b', 'ignore-space-change', None,
4261 ('b', 'ignore-space-change', None,
4247 _('ignore changes in the amount of white space')),
4262 _('ignore changes in the amount of white space')),
4248 ('B', 'ignore-blank-lines', None,
4263 ('B', 'ignore-blank-lines', None,
4249 _('ignore changes whose lines are all blank')),
4264 _('ignore changes whose lines are all blank')),
4250 ('U', 'unified', '',
4265 ('U', 'unified', '',
4251 _('number of lines of context to show'), _('NUM')),
4266 _('number of lines of context to show'), _('NUM')),
4252 ('', 'stat', None, _('output diffstat-style summary of changes')),
4267 ('', 'stat', None, _('output diffstat-style summary of changes')),
4253 ]
4268 ]
4254
4269
4255 similarityopts = [
4270 similarityopts = [
4256 ('s', 'similarity', '',
4271 ('s', 'similarity', '',
4257 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4272 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4258 ]
4273 ]
4259
4274
4260 subrepoopts = [
4275 subrepoopts = [
4261 ('S', 'subrepos', None,
4276 ('S', 'subrepos', None,
4262 _('recurse into subrepositories'))
4277 _('recurse into subrepositories'))
4263 ]
4278 ]
4264
4279
4265 table = {
4280 table = {
4266 "^add": (add, walkopts + subrepoopts + dryrunopts,
4281 "^add": (add, walkopts + subrepoopts + dryrunopts,
4267 _('[OPTION]... [FILE]...')),
4282 _('[OPTION]... [FILE]...')),
4268 "addremove":
4283 "addremove":
4269 (addremove, similarityopts + walkopts + dryrunopts,
4284 (addremove, similarityopts + walkopts + dryrunopts,
4270 _('[OPTION]... [FILE]...')),
4285 _('[OPTION]... [FILE]...')),
4271 "^annotate|blame":
4286 "^annotate|blame":
4272 (annotate,
4287 (annotate,
4273 [('r', 'rev', '',
4288 [('r', 'rev', '',
4274 _('annotate the specified revision'), _('REV')),
4289 _('annotate the specified revision'), _('REV')),
4275 ('', 'follow', None,
4290 ('', 'follow', None,
4276 _('follow copies/renames and list the filename (DEPRECATED)')),
4291 _('follow copies/renames and list the filename (DEPRECATED)')),
4277 ('', 'no-follow', None, _("don't follow copies and renames")),
4292 ('', 'no-follow', None, _("don't follow copies and renames")),
4278 ('a', 'text', None, _('treat all files as text')),
4293 ('a', 'text', None, _('treat all files as text')),
4279 ('u', 'user', None, _('list the author (long with -v)')),
4294 ('u', 'user', None, _('list the author (long with -v)')),
4280 ('f', 'file', None, _('list the filename')),
4295 ('f', 'file', None, _('list the filename')),
4281 ('d', 'date', None, _('list the date (short with -q)')),
4296 ('d', 'date', None, _('list the date (short with -q)')),
4282 ('n', 'number', None, _('list the revision number (default)')),
4297 ('n', 'number', None, _('list the revision number (default)')),
4283 ('c', 'changeset', None, _('list the changeset')),
4298 ('c', 'changeset', None, _('list the changeset')),
4284 ('l', 'line-number', None,
4299 ('l', 'line-number', None,
4285 _('show line number at the first appearance'))
4300 _('show line number at the first appearance'))
4286 ] + walkopts,
4301 ] + walkopts,
4287 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4302 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4288 "archive":
4303 "archive":
4289 (archive,
4304 (archive,
4290 [('', 'no-decode', None, _('do not pass files through decoders')),
4305 [('', 'no-decode', None, _('do not pass files through decoders')),
4291 ('p', 'prefix', '',
4306 ('p', 'prefix', '',
4292 _('directory prefix for files in archive'), _('PREFIX')),
4307 _('directory prefix for files in archive'), _('PREFIX')),
4293 ('r', 'rev', '',
4308 ('r', 'rev', '',
4294 _('revision to distribute'), _('REV')),
4309 _('revision to distribute'), _('REV')),
4295 ('t', 'type', '',
4310 ('t', 'type', '',
4296 _('type of distribution to create'), _('TYPE')),
4311 _('type of distribution to create'), _('TYPE')),
4297 ] + subrepoopts + walkopts,
4312 ] + subrepoopts + walkopts,
4298 _('[OPTION]... DEST')),
4313 _('[OPTION]... DEST')),
4299 "backout":
4314 "backout":
4300 (backout,
4315 (backout,
4301 [('', 'merge', None,
4316 [('', 'merge', None,
4302 _('merge with old dirstate parent after backout')),
4317 _('merge with old dirstate parent after backout')),
4303 ('', 'parent', '',
4318 ('', 'parent', '',
4304 _('parent to choose when backing out merge'), _('REV')),
4319 _('parent to choose when backing out merge'), _('REV')),
4305 ('t', 'tool', '',
4320 ('t', 'tool', '',
4306 _('specify merge tool')),
4321 _('specify merge tool')),
4307 ('r', 'rev', '',
4322 ('r', 'rev', '',
4308 _('revision to backout'), _('REV')),
4323 _('revision to backout'), _('REV')),
4309 ] + walkopts + commitopts + commitopts2,
4324 ] + walkopts + commitopts + commitopts2,
4310 _('[OPTION]... [-r] REV')),
4325 _('[OPTION]... [-r] REV')),
4311 "bisect":
4326 "bisect":
4312 (bisect,
4327 (bisect,
4313 [('r', 'reset', False, _('reset bisect state')),
4328 [('r', 'reset', False, _('reset bisect state')),
4314 ('g', 'good', False, _('mark changeset good')),
4329 ('g', 'good', False, _('mark changeset good')),
4315 ('b', 'bad', False, _('mark changeset bad')),
4330 ('b', 'bad', False, _('mark changeset bad')),
4316 ('s', 'skip', False, _('skip testing changeset')),
4331 ('s', 'skip', False, _('skip testing changeset')),
4317 ('e', 'extend', False, _('extend the bisect range')),
4332 ('e', 'extend', False, _('extend the bisect range')),
4318 ('c', 'command', '',
4333 ('c', 'command', '',
4319 _('use command to check changeset state'), _('CMD')),
4334 _('use command to check changeset state'), _('CMD')),
4320 ('U', 'noupdate', False, _('do not update to target'))],
4335 ('U', 'noupdate', False, _('do not update to target'))],
4321 _("[-gbsr] [-U] [-c CMD] [REV]")),
4336 _("[-gbsr] [-U] [-c CMD] [REV]")),
4322 "bookmarks":
4337 "bookmarks":
4323 (bookmark,
4338 (bookmark,
4324 [('f', 'force', False, _('force')),
4339 [('f', 'force', False, _('force')),
4325 ('r', 'rev', '', _('revision'), _('REV')),
4340 ('r', 'rev', '', _('revision'), _('REV')),
4326 ('d', 'delete', False, _('delete a given bookmark')),
4341 ('d', 'delete', False, _('delete a given bookmark')),
4327 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4342 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4328 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4343 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4329 "branch":
4344 "branch":
4330 (branch,
4345 (branch,
4331 [('f', 'force', None,
4346 [('f', 'force', None,
4332 _('set branch name even if it shadows an existing branch')),
4347 _('set branch name even if it shadows an existing branch')),
4333 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4348 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4334 _('[-fC] [NAME]')),
4349 _('[-fC] [NAME]')),
4335 "branches":
4350 "branches":
4336 (branches,
4351 (branches,
4337 [('a', 'active', False,
4352 [('a', 'active', False,
4338 _('show only branches that have unmerged heads')),
4353 _('show only branches that have unmerged heads')),
4339 ('c', 'closed', False,
4354 ('c', 'closed', False,
4340 _('show normal and closed branches'))],
4355 _('show normal and closed branches'))],
4341 _('[-ac]')),
4356 _('[-ac]')),
4342 "bundle":
4357 "bundle":
4343 (bundle,
4358 (bundle,
4344 [('f', 'force', None,
4359 [('f', 'force', None,
4345 _('run even when the destination is unrelated')),
4360 _('run even when the destination is unrelated')),
4346 ('r', 'rev', [],
4361 ('r', 'rev', [],
4347 _('a changeset intended to be added to the destination'),
4362 _('a changeset intended to be added to the destination'),
4348 _('REV')),
4363 _('REV')),
4349 ('b', 'branch', [],
4364 ('b', 'branch', [],
4350 _('a specific branch you would like to bundle'),
4365 _('a specific branch you would like to bundle'),
4351 _('BRANCH')),
4366 _('BRANCH')),
4352 ('', 'base', [],
4367 ('', 'base', [],
4353 _('a base changeset assumed to be available at the destination'),
4368 _('a base changeset assumed to be available at the destination'),
4354 _('REV')),
4369 _('REV')),
4355 ('a', 'all', None, _('bundle all changesets in the repository')),
4370 ('a', 'all', None, _('bundle all changesets in the repository')),
4356 ('t', 'type', 'bzip2',
4371 ('t', 'type', 'bzip2',
4357 _('bundle compression type to use'), _('TYPE')),
4372 _('bundle compression type to use'), _('TYPE')),
4358 ] + remoteopts,
4373 ] + remoteopts,
4359 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4374 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4360 "cat":
4375 "cat":
4361 (cat,
4376 (cat,
4362 [('o', 'output', '',
4377 [('o', 'output', '',
4363 _('print output to file with formatted name'), _('FORMAT')),
4378 _('print output to file with formatted name'), _('FORMAT')),
4364 ('r', 'rev', '',
4379 ('r', 'rev', '',
4365 _('print the given revision'), _('REV')),
4380 _('print the given revision'), _('REV')),
4366 ('', 'decode', None, _('apply any matching decode filter')),
4381 ('', 'decode', None, _('apply any matching decode filter')),
4367 ] + walkopts,
4382 ] + walkopts,
4368 _('[OPTION]... FILE...')),
4383 _('[OPTION]... FILE...')),
4369 "^clone":
4384 "^clone":
4370 (clone,
4385 (clone,
4371 [('U', 'noupdate', None,
4386 [('U', 'noupdate', None,
4372 _('the clone will include an empty working copy (only a repository)')),
4387 _('the clone will include an empty working copy (only a repository)')),
4373 ('u', 'updaterev', '',
4388 ('u', 'updaterev', '',
4374 _('revision, tag or branch to check out'), _('REV')),
4389 _('revision, tag or branch to check out'), _('REV')),
4375 ('r', 'rev', [],
4390 ('r', 'rev', [],
4376 _('include the specified changeset'), _('REV')),
4391 _('include the specified changeset'), _('REV')),
4377 ('b', 'branch', [],
4392 ('b', 'branch', [],
4378 _('clone only the specified branch'), _('BRANCH')),
4393 _('clone only the specified branch'), _('BRANCH')),
4379 ('', 'pull', None, _('use pull protocol to copy metadata')),
4394 ('', 'pull', None, _('use pull protocol to copy metadata')),
4380 ('', 'uncompressed', None,
4395 ('', 'uncompressed', None,
4381 _('use uncompressed transfer (fast over LAN)')),
4396 _('use uncompressed transfer (fast over LAN)')),
4382 ] + remoteopts,
4397 ] + remoteopts,
4383 _('[OPTION]... SOURCE [DEST]')),
4398 _('[OPTION]... SOURCE [DEST]')),
4384 "^commit|ci":
4399 "^commit|ci":
4385 (commit,
4400 (commit,
4386 [('A', 'addremove', None,
4401 [('A', 'addremove', None,
4387 _('mark new/missing files as added/removed before committing')),
4402 _('mark new/missing files as added/removed before committing')),
4388 ('', 'close-branch', None,
4403 ('', 'close-branch', None,
4389 _('mark a branch as closed, hiding it from the branch list')),
4404 _('mark a branch as closed, hiding it from the branch list')),
4390 ] + walkopts + commitopts + commitopts2,
4405 ] + walkopts + commitopts + commitopts2,
4391 _('[OPTION]... [FILE]...')),
4406 _('[OPTION]... [FILE]...')),
4392 "copy|cp":
4407 "copy|cp":
4393 (copy,
4408 (copy,
4394 [('A', 'after', None, _('record a copy that has already occurred')),
4409 [('A', 'after', None, _('record a copy that has already occurred')),
4395 ('f', 'force', None,
4410 ('f', 'force', None,
4396 _('forcibly copy over an existing managed file')),
4411 _('forcibly copy over an existing managed file')),
4397 ] + walkopts + dryrunopts,
4412 ] + walkopts + dryrunopts,
4398 _('[OPTION]... [SOURCE]... DEST')),
4413 _('[OPTION]... [SOURCE]... DEST')),
4399 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4414 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4400 "debugbuilddag":
4415 "debugbuilddag":
4401 (debugbuilddag,
4416 (debugbuilddag,
4402 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4417 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4403 ('a', 'appended-file', None, _('add single file all revs append to')),
4418 ('a', 'appended-file', None, _('add single file all revs append to')),
4404 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4419 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4405 ('n', 'new-file', None, _('add new file at each rev')),
4420 ('n', 'new-file', None, _('add new file at each rev')),
4406 ],
4421 ],
4407 _('[OPTION]... TEXT')),
4422 _('[OPTION]... TEXT')),
4408 "debugcheckstate": (debugcheckstate, [], ''),
4423 "debugcheckstate": (debugcheckstate, [], ''),
4409 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4424 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4410 "debugcomplete":
4425 "debugcomplete":
4411 (debugcomplete,
4426 (debugcomplete,
4412 [('o', 'options', None, _('show the command options'))],
4427 [('o', 'options', None, _('show the command options'))],
4413 _('[-o] CMD')),
4428 _('[-o] CMD')),
4414 "debugdag":
4429 "debugdag":
4415 (debugdag,
4430 (debugdag,
4416 [('t', 'tags', None, _('use tags as labels')),
4431 [('t', 'tags', None, _('use tags as labels')),
4417 ('b', 'branches', None, _('annotate with branch names')),
4432 ('b', 'branches', None, _('annotate with branch names')),
4418 ('', 'dots', None, _('use dots for runs')),
4433 ('', 'dots', None, _('use dots for runs')),
4419 ('s', 'spaces', None, _('separate elements by spaces')),
4434 ('s', 'spaces', None, _('separate elements by spaces')),
4420 ],
4435 ],
4421 _('[OPTION]... [FILE [REV]...]')),
4436 _('[OPTION]... [FILE [REV]...]')),
4422 "debugdate":
4437 "debugdate":
4423 (debugdate,
4438 (debugdate,
4424 [('e', 'extended', None, _('try extended date formats'))],
4439 [('e', 'extended', None, _('try extended date formats'))],
4425 _('[-e] DATE [RANGE]')),
4440 _('[-e] DATE [RANGE]')),
4426 "debugdata": (debugdata, [], _('FILE REV')),
4441 "debugdata": (debugdata, [], _('FILE REV')),
4427 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4442 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4428 "debugignore": (debugignore, [], ''),
4443 "debugignore": (debugignore, [], ''),
4429 "debugindex": (debugindex,
4444 "debugindex": (debugindex,
4430 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4445 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4431 _('FILE')),
4446 _('FILE')),
4432 "debugindexdot": (debugindexdot, [], _('FILE')),
4447 "debugindexdot": (debugindexdot, [], _('FILE')),
4433 "debuginstall": (debuginstall, [], ''),
4448 "debuginstall": (debuginstall, [], ''),
4434 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4449 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4435 "debugrebuildstate":
4450 "debugrebuildstate":
4436 (debugrebuildstate,
4451 (debugrebuildstate,
4437 [('r', 'rev', '',
4452 [('r', 'rev', '',
4438 _('revision to rebuild to'), _('REV'))],
4453 _('revision to rebuild to'), _('REV'))],
4439 _('[-r REV] [REV]')),
4454 _('[-r REV] [REV]')),
4440 "debugrename":
4455 "debugrename":
4441 (debugrename,
4456 (debugrename,
4442 [('r', 'rev', '',
4457 [('r', 'rev', '',
4443 _('revision to debug'), _('REV'))],
4458 _('revision to debug'), _('REV'))],
4444 _('[-r REV] FILE')),
4459 _('[-r REV] FILE')),
4445 "debugrevspec":
4460 "debugrevspec":
4446 (debugrevspec, [], ('REVSPEC')),
4461 (debugrevspec, [], ('REVSPEC')),
4447 "debugsetparents":
4462 "debugsetparents":
4448 (debugsetparents, [], _('REV1 [REV2]')),
4463 (debugsetparents, [], _('REV1 [REV2]')),
4449 "debugstate":
4464 "debugstate":
4450 (debugstate,
4465 (debugstate,
4451 [('', 'nodates', None, _('do not display the saved mtime'))],
4466 [('', 'nodates', None, _('do not display the saved mtime'))],
4452 _('[OPTION]...')),
4467 _('[OPTION]...')),
4453 "debugsub":
4468 "debugsub":
4454 (debugsub,
4469 (debugsub,
4455 [('r', 'rev', '',
4470 [('r', 'rev', '',
4456 _('revision to check'), _('REV'))],
4471 _('revision to check'), _('REV'))],
4457 _('[-r REV] [REV]')),
4472 _('[-r REV] [REV]')),
4458 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4473 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4474 "debugwireargs":
4475 (debugwireargs,
4476 [('', 'three', '', 'three'),
4477 ('', 'four', '', 'four'),
4478 ] + remoteopts,
4479 _('REPO [OPTIONS]... [ONE [TWO]]')),
4459 "^diff":
4480 "^diff":
4460 (diff,
4481 (diff,
4461 [('r', 'rev', [],
4482 [('r', 'rev', [],
4462 _('revision'), _('REV')),
4483 _('revision'), _('REV')),
4463 ('c', 'change', '',
4484 ('c', 'change', '',
4464 _('change made by revision'), _('REV'))
4485 _('change made by revision'), _('REV'))
4465 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4486 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4466 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4487 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4467 "^export":
4488 "^export":
4468 (export,
4489 (export,
4469 [('o', 'output', '',
4490 [('o', 'output', '',
4470 _('print output to file with formatted name'), _('FORMAT')),
4491 _('print output to file with formatted name'), _('FORMAT')),
4471 ('', 'switch-parent', None, _('diff against the second parent')),
4492 ('', 'switch-parent', None, _('diff against the second parent')),
4472 ('r', 'rev', [],
4493 ('r', 'rev', [],
4473 _('revisions to export'), _('REV')),
4494 _('revisions to export'), _('REV')),
4474 ] + diffopts,
4495 ] + diffopts,
4475 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4496 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4476 "^forget":
4497 "^forget":
4477 (forget,
4498 (forget,
4478 [] + walkopts,
4499 [] + walkopts,
4479 _('[OPTION]... FILE...')),
4500 _('[OPTION]... FILE...')),
4480 "grep":
4501 "grep":
4481 (grep,
4502 (grep,
4482 [('0', 'print0', None, _('end fields with NUL')),
4503 [('0', 'print0', None, _('end fields with NUL')),
4483 ('', 'all', None, _('print all revisions that match')),
4504 ('', 'all', None, _('print all revisions that match')),
4484 ('f', 'follow', None,
4505 ('f', 'follow', None,
4485 _('follow changeset history,'
4506 _('follow changeset history,'
4486 ' or file history across copies and renames')),
4507 ' or file history across copies and renames')),
4487 ('i', 'ignore-case', None, _('ignore case when matching')),
4508 ('i', 'ignore-case', None, _('ignore case when matching')),
4488 ('l', 'files-with-matches', None,
4509 ('l', 'files-with-matches', None,
4489 _('print only filenames and revisions that match')),
4510 _('print only filenames and revisions that match')),
4490 ('n', 'line-number', None, _('print matching line numbers')),
4511 ('n', 'line-number', None, _('print matching line numbers')),
4491 ('r', 'rev', [],
4512 ('r', 'rev', [],
4492 _('only search files changed within revision range'), _('REV')),
4513 _('only search files changed within revision range'), _('REV')),
4493 ('u', 'user', None, _('list the author (long with -v)')),
4514 ('u', 'user', None, _('list the author (long with -v)')),
4494 ('d', 'date', None, _('list the date (short with -q)')),
4515 ('d', 'date', None, _('list the date (short with -q)')),
4495 ] + walkopts,
4516 ] + walkopts,
4496 _('[OPTION]... PATTERN [FILE]...')),
4517 _('[OPTION]... PATTERN [FILE]...')),
4497 "heads":
4518 "heads":
4498 (heads,
4519 (heads,
4499 [('r', 'rev', '',
4520 [('r', 'rev', '',
4500 _('show only heads which are descendants of STARTREV'),
4521 _('show only heads which are descendants of STARTREV'),
4501 _('STARTREV')),
4522 _('STARTREV')),
4502 ('t', 'topo', False, _('show topological heads only')),
4523 ('t', 'topo', False, _('show topological heads only')),
4503 ('a', 'active', False,
4524 ('a', 'active', False,
4504 _('show active branchheads only (DEPRECATED)')),
4525 _('show active branchheads only (DEPRECATED)')),
4505 ('c', 'closed', False,
4526 ('c', 'closed', False,
4506 _('show normal and closed branch heads')),
4527 _('show normal and closed branch heads')),
4507 ] + templateopts,
4528 ] + templateopts,
4508 _('[-ac] [-r STARTREV] [REV]...')),
4529 _('[-ac] [-r STARTREV] [REV]...')),
4509 "help": (help_, [], _('[TOPIC]')),
4530 "help": (help_, [], _('[TOPIC]')),
4510 "identify|id":
4531 "identify|id":
4511 (identify,
4532 (identify,
4512 [('r', 'rev', '',
4533 [('r', 'rev', '',
4513 _('identify the specified revision'), _('REV')),
4534 _('identify the specified revision'), _('REV')),
4514 ('n', 'num', None, _('show local revision number')),
4535 ('n', 'num', None, _('show local revision number')),
4515 ('i', 'id', None, _('show global revision id')),
4536 ('i', 'id', None, _('show global revision id')),
4516 ('b', 'branch', None, _('show branch')),
4537 ('b', 'branch', None, _('show branch')),
4517 ('t', 'tags', None, _('show tags')),
4538 ('t', 'tags', None, _('show tags')),
4518 ('B', 'bookmarks', None, _('show bookmarks'))],
4539 ('B', 'bookmarks', None, _('show bookmarks'))],
4519 _('[-nibtB] [-r REV] [SOURCE]')),
4540 _('[-nibtB] [-r REV] [SOURCE]')),
4520 "import|patch":
4541 "import|patch":
4521 (import_,
4542 (import_,
4522 [('p', 'strip', 1,
4543 [('p', 'strip', 1,
4523 _('directory strip option for patch. This has the same '
4544 _('directory strip option for patch. This has the same '
4524 'meaning as the corresponding patch option'),
4545 'meaning as the corresponding patch option'),
4525 _('NUM')),
4546 _('NUM')),
4526 ('b', 'base', '',
4547 ('b', 'base', '',
4527 _('base path'), _('PATH')),
4548 _('base path'), _('PATH')),
4528 ('f', 'force', None,
4549 ('f', 'force', None,
4529 _('skip check for outstanding uncommitted changes')),
4550 _('skip check for outstanding uncommitted changes')),
4530 ('', 'no-commit', None,
4551 ('', 'no-commit', None,
4531 _("don't commit, just update the working directory")),
4552 _("don't commit, just update the working directory")),
4532 ('', 'exact', None,
4553 ('', 'exact', None,
4533 _('apply patch to the nodes from which it was generated')),
4554 _('apply patch to the nodes from which it was generated')),
4534 ('', 'import-branch', None,
4555 ('', 'import-branch', None,
4535 _('use any branch information in patch (implied by --exact)'))] +
4556 _('use any branch information in patch (implied by --exact)'))] +
4536 commitopts + commitopts2 + similarityopts,
4557 commitopts + commitopts2 + similarityopts,
4537 _('[OPTION]... PATCH...')),
4558 _('[OPTION]... PATCH...')),
4538 "incoming|in":
4559 "incoming|in":
4539 (incoming,
4560 (incoming,
4540 [('f', 'force', None,
4561 [('f', 'force', None,
4541 _('run even if remote repository is unrelated')),
4562 _('run even if remote repository is unrelated')),
4542 ('n', 'newest-first', None, _('show newest record first')),
4563 ('n', 'newest-first', None, _('show newest record first')),
4543 ('', 'bundle', '',
4564 ('', 'bundle', '',
4544 _('file to store the bundles into'), _('FILE')),
4565 _('file to store the bundles into'), _('FILE')),
4545 ('r', 'rev', [],
4566 ('r', 'rev', [],
4546 _('a remote changeset intended to be added'), _('REV')),
4567 _('a remote changeset intended to be added'), _('REV')),
4547 ('B', 'bookmarks', False, _("compare bookmarks")),
4568 ('B', 'bookmarks', False, _("compare bookmarks")),
4548 ('b', 'branch', [],
4569 ('b', 'branch', [],
4549 _('a specific branch you would like to pull'), _('BRANCH')),
4570 _('a specific branch you would like to pull'), _('BRANCH')),
4550 ] + logopts + remoteopts + subrepoopts,
4571 ] + logopts + remoteopts + subrepoopts,
4551 _('[-p] [-n] [-M] [-f] [-r REV]...'
4572 _('[-p] [-n] [-M] [-f] [-r REV]...'
4552 ' [--bundle FILENAME] [SOURCE]')),
4573 ' [--bundle FILENAME] [SOURCE]')),
4553 "^init":
4574 "^init":
4554 (init,
4575 (init,
4555 remoteopts,
4576 remoteopts,
4556 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4577 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4557 "locate":
4578 "locate":
4558 (locate,
4579 (locate,
4559 [('r', 'rev', '',
4580 [('r', 'rev', '',
4560 _('search the repository as it is in REV'), _('REV')),
4581 _('search the repository as it is in REV'), _('REV')),
4561 ('0', 'print0', None,
4582 ('0', 'print0', None,
4562 _('end filenames with NUL, for use with xargs')),
4583 _('end filenames with NUL, for use with xargs')),
4563 ('f', 'fullpath', None,
4584 ('f', 'fullpath', None,
4564 _('print complete paths from the filesystem root')),
4585 _('print complete paths from the filesystem root')),
4565 ] + walkopts,
4586 ] + walkopts,
4566 _('[OPTION]... [PATTERN]...')),
4587 _('[OPTION]... [PATTERN]...')),
4567 "^log|history":
4588 "^log|history":
4568 (log,
4589 (log,
4569 [('f', 'follow', None,
4590 [('f', 'follow', None,
4570 _('follow changeset history,'
4591 _('follow changeset history,'
4571 ' or file history across copies and renames')),
4592 ' or file history across copies and renames')),
4572 ('', 'follow-first', None,
4593 ('', 'follow-first', None,
4573 _('only follow the first parent of merge changesets')),
4594 _('only follow the first parent of merge changesets')),
4574 ('d', 'date', '',
4595 ('d', 'date', '',
4575 _('show revisions matching date spec'), _('DATE')),
4596 _('show revisions matching date spec'), _('DATE')),
4576 ('C', 'copies', None, _('show copied files')),
4597 ('C', 'copies', None, _('show copied files')),
4577 ('k', 'keyword', [],
4598 ('k', 'keyword', [],
4578 _('do case-insensitive search for a given text'), _('TEXT')),
4599 _('do case-insensitive search for a given text'), _('TEXT')),
4579 ('r', 'rev', [],
4600 ('r', 'rev', [],
4580 _('show the specified revision or range'), _('REV')),
4601 _('show the specified revision or range'), _('REV')),
4581 ('', 'removed', None, _('include revisions where files were removed')),
4602 ('', 'removed', None, _('include revisions where files were removed')),
4582 ('m', 'only-merges', None, _('show only merges')),
4603 ('m', 'only-merges', None, _('show only merges')),
4583 ('u', 'user', [],
4604 ('u', 'user', [],
4584 _('revisions committed by user'), _('USER')),
4605 _('revisions committed by user'), _('USER')),
4585 ('', 'only-branch', [],
4606 ('', 'only-branch', [],
4586 _('show only changesets within the given named branch (DEPRECATED)'),
4607 _('show only changesets within the given named branch (DEPRECATED)'),
4587 _('BRANCH')),
4608 _('BRANCH')),
4588 ('b', 'branch', [],
4609 ('b', 'branch', [],
4589 _('show changesets within the given named branch'), _('BRANCH')),
4610 _('show changesets within the given named branch'), _('BRANCH')),
4590 ('P', 'prune', [],
4611 ('P', 'prune', [],
4591 _('do not display revision or any of its ancestors'), _('REV')),
4612 _('do not display revision or any of its ancestors'), _('REV')),
4592 ] + logopts + walkopts,
4613 ] + logopts + walkopts,
4593 _('[OPTION]... [FILE]')),
4614 _('[OPTION]... [FILE]')),
4594 "manifest":
4615 "manifest":
4595 (manifest,
4616 (manifest,
4596 [('r', 'rev', '',
4617 [('r', 'rev', '',
4597 _('revision to display'), _('REV'))],
4618 _('revision to display'), _('REV'))],
4598 _('[-r REV]')),
4619 _('[-r REV]')),
4599 "^merge":
4620 "^merge":
4600 (merge,
4621 (merge,
4601 [('f', 'force', None, _('force a merge with outstanding changes')),
4622 [('f', 'force', None, _('force a merge with outstanding changes')),
4602 ('t', 'tool', '', _('specify merge tool')),
4623 ('t', 'tool', '', _('specify merge tool')),
4603 ('r', 'rev', '',
4624 ('r', 'rev', '',
4604 _('revision to merge'), _('REV')),
4625 _('revision to merge'), _('REV')),
4605 ('P', 'preview', None,
4626 ('P', 'preview', None,
4606 _('review revisions to merge (no merge is performed)'))],
4627 _('review revisions to merge (no merge is performed)'))],
4607 _('[-P] [-f] [[-r] REV]')),
4628 _('[-P] [-f] [[-r] REV]')),
4608 "outgoing|out":
4629 "outgoing|out":
4609 (outgoing,
4630 (outgoing,
4610 [('f', 'force', None,
4631 [('f', 'force', None,
4611 _('run even when the destination is unrelated')),
4632 _('run even when the destination is unrelated')),
4612 ('r', 'rev', [],
4633 ('r', 'rev', [],
4613 _('a changeset intended to be included in the destination'),
4634 _('a changeset intended to be included in the destination'),
4614 _('REV')),
4635 _('REV')),
4615 ('n', 'newest-first', None, _('show newest record first')),
4636 ('n', 'newest-first', None, _('show newest record first')),
4616 ('B', 'bookmarks', False, _("compare bookmarks")),
4637 ('B', 'bookmarks', False, _("compare bookmarks")),
4617 ('b', 'branch', [],
4638 ('b', 'branch', [],
4618 _('a specific branch you would like to push'), _('BRANCH')),
4639 _('a specific branch you would like to push'), _('BRANCH')),
4619 ] + logopts + remoteopts + subrepoopts,
4640 ] + logopts + remoteopts + subrepoopts,
4620 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4641 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4621 "parents":
4642 "parents":
4622 (parents,
4643 (parents,
4623 [('r', 'rev', '',
4644 [('r', 'rev', '',
4624 _('show parents of the specified revision'), _('REV')),
4645 _('show parents of the specified revision'), _('REV')),
4625 ] + templateopts,
4646 ] + templateopts,
4626 _('[-r REV] [FILE]')),
4647 _('[-r REV] [FILE]')),
4627 "paths": (paths, [], _('[NAME]')),
4648 "paths": (paths, [], _('[NAME]')),
4628 "^pull":
4649 "^pull":
4629 (pull,
4650 (pull,
4630 [('u', 'update', None,
4651 [('u', 'update', None,
4631 _('update to new branch head if changesets were pulled')),
4652 _('update to new branch head if changesets were pulled')),
4632 ('f', 'force', None,
4653 ('f', 'force', None,
4633 _('run even when remote repository is unrelated')),
4654 _('run even when remote repository is unrelated')),
4634 ('r', 'rev', [],
4655 ('r', 'rev', [],
4635 _('a remote changeset intended to be added'), _('REV')),
4656 _('a remote changeset intended to be added'), _('REV')),
4636 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4657 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4637 ('b', 'branch', [],
4658 ('b', 'branch', [],
4638 _('a specific branch you would like to pull'), _('BRANCH')),
4659 _('a specific branch you would like to pull'), _('BRANCH')),
4639 ] + remoteopts,
4660 ] + remoteopts,
4640 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4661 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4641 "^push":
4662 "^push":
4642 (push,
4663 (push,
4643 [('f', 'force', None, _('force push')),
4664 [('f', 'force', None, _('force push')),
4644 ('r', 'rev', [],
4665 ('r', 'rev', [],
4645 _('a changeset intended to be included in the destination'),
4666 _('a changeset intended to be included in the destination'),
4646 _('REV')),
4667 _('REV')),
4647 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4668 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4648 ('b', 'branch', [],
4669 ('b', 'branch', [],
4649 _('a specific branch you would like to push'), _('BRANCH')),
4670 _('a specific branch you would like to push'), _('BRANCH')),
4650 ('', 'new-branch', False, _('allow pushing a new branch')),
4671 ('', 'new-branch', False, _('allow pushing a new branch')),
4651 ] + remoteopts,
4672 ] + remoteopts,
4652 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4673 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4653 "recover": (recover, []),
4674 "recover": (recover, []),
4654 "^remove|rm":
4675 "^remove|rm":
4655 (remove,
4676 (remove,
4656 [('A', 'after', None, _('record delete for missing files')),
4677 [('A', 'after', None, _('record delete for missing files')),
4657 ('f', 'force', None,
4678 ('f', 'force', None,
4658 _('remove (and delete) file even if added or modified')),
4679 _('remove (and delete) file even if added or modified')),
4659 ] + walkopts,
4680 ] + walkopts,
4660 _('[OPTION]... FILE...')),
4681 _('[OPTION]... FILE...')),
4661 "rename|move|mv":
4682 "rename|move|mv":
4662 (rename,
4683 (rename,
4663 [('A', 'after', None, _('record a rename that has already occurred')),
4684 [('A', 'after', None, _('record a rename that has already occurred')),
4664 ('f', 'force', None,
4685 ('f', 'force', None,
4665 _('forcibly copy over an existing managed file')),
4686 _('forcibly copy over an existing managed file')),
4666 ] + walkopts + dryrunopts,
4687 ] + walkopts + dryrunopts,
4667 _('[OPTION]... SOURCE... DEST')),
4688 _('[OPTION]... SOURCE... DEST')),
4668 "resolve":
4689 "resolve":
4669 (resolve,
4690 (resolve,
4670 [('a', 'all', None, _('select all unresolved files')),
4691 [('a', 'all', None, _('select all unresolved files')),
4671 ('l', 'list', None, _('list state of files needing merge')),
4692 ('l', 'list', None, _('list state of files needing merge')),
4672 ('m', 'mark', None, _('mark files as resolved')),
4693 ('m', 'mark', None, _('mark files as resolved')),
4673 ('u', 'unmark', None, _('mark files as unresolved')),
4694 ('u', 'unmark', None, _('mark files as unresolved')),
4674 ('t', 'tool', '', _('specify merge tool')),
4695 ('t', 'tool', '', _('specify merge tool')),
4675 ('n', 'no-status', None, _('hide status prefix'))]
4696 ('n', 'no-status', None, _('hide status prefix'))]
4676 + walkopts,
4697 + walkopts,
4677 _('[OPTION]... [FILE]...')),
4698 _('[OPTION]... [FILE]...')),
4678 "revert":
4699 "revert":
4679 (revert,
4700 (revert,
4680 [('a', 'all', None, _('revert all changes when no arguments given')),
4701 [('a', 'all', None, _('revert all changes when no arguments given')),
4681 ('d', 'date', '',
4702 ('d', 'date', '',
4682 _('tipmost revision matching date'), _('DATE')),
4703 _('tipmost revision matching date'), _('DATE')),
4683 ('r', 'rev', '',
4704 ('r', 'rev', '',
4684 _('revert to the specified revision'), _('REV')),
4705 _('revert to the specified revision'), _('REV')),
4685 ('', 'no-backup', None, _('do not save backup copies of files')),
4706 ('', 'no-backup', None, _('do not save backup copies of files')),
4686 ] + walkopts + dryrunopts,
4707 ] + walkopts + dryrunopts,
4687 _('[OPTION]... [-r REV] [NAME]...')),
4708 _('[OPTION]... [-r REV] [NAME]...')),
4688 "rollback": (rollback, dryrunopts),
4709 "rollback": (rollback, dryrunopts),
4689 "root": (root, []),
4710 "root": (root, []),
4690 "^serve":
4711 "^serve":
4691 (serve,
4712 (serve,
4692 [('A', 'accesslog', '',
4713 [('A', 'accesslog', '',
4693 _('name of access log file to write to'), _('FILE')),
4714 _('name of access log file to write to'), _('FILE')),
4694 ('d', 'daemon', None, _('run server in background')),
4715 ('d', 'daemon', None, _('run server in background')),
4695 ('', 'daemon-pipefds', '',
4716 ('', 'daemon-pipefds', '',
4696 _('used internally by daemon mode'), _('NUM')),
4717 _('used internally by daemon mode'), _('NUM')),
4697 ('E', 'errorlog', '',
4718 ('E', 'errorlog', '',
4698 _('name of error log file to write to'), _('FILE')),
4719 _('name of error log file to write to'), _('FILE')),
4699 # use string type, then we can check if something was passed
4720 # use string type, then we can check if something was passed
4700 ('p', 'port', '',
4721 ('p', 'port', '',
4701 _('port to listen on (default: 8000)'), _('PORT')),
4722 _('port to listen on (default: 8000)'), _('PORT')),
4702 ('a', 'address', '',
4723 ('a', 'address', '',
4703 _('address to listen on (default: all interfaces)'), _('ADDR')),
4724 _('address to listen on (default: all interfaces)'), _('ADDR')),
4704 ('', 'prefix', '',
4725 ('', 'prefix', '',
4705 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4726 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4706 ('n', 'name', '',
4727 ('n', 'name', '',
4707 _('name to show in web pages (default: working directory)'),
4728 _('name to show in web pages (default: working directory)'),
4708 _('NAME')),
4729 _('NAME')),
4709 ('', 'web-conf', '',
4730 ('', 'web-conf', '',
4710 _('name of the hgweb config file (see "hg help hgweb")'),
4731 _('name of the hgweb config file (see "hg help hgweb")'),
4711 _('FILE')),
4732 _('FILE')),
4712 ('', 'webdir-conf', '',
4733 ('', 'webdir-conf', '',
4713 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4734 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4714 ('', 'pid-file', '',
4735 ('', 'pid-file', '',
4715 _('name of file to write process ID to'), _('FILE')),
4736 _('name of file to write process ID to'), _('FILE')),
4716 ('', 'stdio', None, _('for remote clients')),
4737 ('', 'stdio', None, _('for remote clients')),
4717 ('t', 'templates', '',
4738 ('t', 'templates', '',
4718 _('web templates to use'), _('TEMPLATE')),
4739 _('web templates to use'), _('TEMPLATE')),
4719 ('', 'style', '',
4740 ('', 'style', '',
4720 _('template style to use'), _('STYLE')),
4741 _('template style to use'), _('STYLE')),
4721 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4742 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4722 ('', 'certificate', '',
4743 ('', 'certificate', '',
4723 _('SSL certificate file'), _('FILE'))],
4744 _('SSL certificate file'), _('FILE'))],
4724 _('[OPTION]...')),
4745 _('[OPTION]...')),
4725 "showconfig|debugconfig":
4746 "showconfig|debugconfig":
4726 (showconfig,
4747 (showconfig,
4727 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4748 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4728 _('[-u] [NAME]...')),
4749 _('[-u] [NAME]...')),
4729 "^summary|sum":
4750 "^summary|sum":
4730 (summary,
4751 (summary,
4731 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4752 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4732 "^status|st":
4753 "^status|st":
4733 (status,
4754 (status,
4734 [('A', 'all', None, _('show status of all files')),
4755 [('A', 'all', None, _('show status of all files')),
4735 ('m', 'modified', None, _('show only modified files')),
4756 ('m', 'modified', None, _('show only modified files')),
4736 ('a', 'added', None, _('show only added files')),
4757 ('a', 'added', None, _('show only added files')),
4737 ('r', 'removed', None, _('show only removed files')),
4758 ('r', 'removed', None, _('show only removed files')),
4738 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4759 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4739 ('c', 'clean', None, _('show only files without changes')),
4760 ('c', 'clean', None, _('show only files without changes')),
4740 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4761 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4741 ('i', 'ignored', None, _('show only ignored files')),
4762 ('i', 'ignored', None, _('show only ignored files')),
4742 ('n', 'no-status', None, _('hide status prefix')),
4763 ('n', 'no-status', None, _('hide status prefix')),
4743 ('C', 'copies', None, _('show source of copied files')),
4764 ('C', 'copies', None, _('show source of copied files')),
4744 ('0', 'print0', None,
4765 ('0', 'print0', None,
4745 _('end filenames with NUL, for use with xargs')),
4766 _('end filenames with NUL, for use with xargs')),
4746 ('', 'rev', [],
4767 ('', 'rev', [],
4747 _('show difference from revision'), _('REV')),
4768 _('show difference from revision'), _('REV')),
4748 ('', 'change', '',
4769 ('', 'change', '',
4749 _('list the changed files of a revision'), _('REV')),
4770 _('list the changed files of a revision'), _('REV')),
4750 ] + walkopts + subrepoopts,
4771 ] + walkopts + subrepoopts,
4751 _('[OPTION]... [FILE]...')),
4772 _('[OPTION]... [FILE]...')),
4752 "tag":
4773 "tag":
4753 (tag,
4774 (tag,
4754 [('f', 'force', None, _('force tag')),
4775 [('f', 'force', None, _('force tag')),
4755 ('l', 'local', None, _('make the tag local')),
4776 ('l', 'local', None, _('make the tag local')),
4756 ('r', 'rev', '',
4777 ('r', 'rev', '',
4757 _('revision to tag'), _('REV')),
4778 _('revision to tag'), _('REV')),
4758 ('', 'remove', None, _('remove a tag')),
4779 ('', 'remove', None, _('remove a tag')),
4759 # -l/--local is already there, commitopts cannot be used
4780 # -l/--local is already there, commitopts cannot be used
4760 ('e', 'edit', None, _('edit commit message')),
4781 ('e', 'edit', None, _('edit commit message')),
4761 ('m', 'message', '',
4782 ('m', 'message', '',
4762 _('use <text> as commit message'), _('TEXT')),
4783 _('use <text> as commit message'), _('TEXT')),
4763 ] + commitopts2,
4784 ] + commitopts2,
4764 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4785 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4765 "tags": (tags, [], ''),
4786 "tags": (tags, [], ''),
4766 "tip":
4787 "tip":
4767 (tip,
4788 (tip,
4768 [('p', 'patch', None, _('show patch')),
4789 [('p', 'patch', None, _('show patch')),
4769 ('g', 'git', None, _('use git extended diff format')),
4790 ('g', 'git', None, _('use git extended diff format')),
4770 ] + templateopts,
4791 ] + templateopts,
4771 _('[-p] [-g]')),
4792 _('[-p] [-g]')),
4772 "unbundle":
4793 "unbundle":
4773 (unbundle,
4794 (unbundle,
4774 [('u', 'update', None,
4795 [('u', 'update', None,
4775 _('update to new branch head if changesets were unbundled'))],
4796 _('update to new branch head if changesets were unbundled'))],
4776 _('[-u] FILE...')),
4797 _('[-u] FILE...')),
4777 "^update|up|checkout|co":
4798 "^update|up|checkout|co":
4778 (update,
4799 (update,
4779 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4800 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4780 ('c', 'check', None,
4801 ('c', 'check', None,
4781 _('update across branches if no uncommitted changes')),
4802 _('update across branches if no uncommitted changes')),
4782 ('d', 'date', '',
4803 ('d', 'date', '',
4783 _('tipmost revision matching date'), _('DATE')),
4804 _('tipmost revision matching date'), _('DATE')),
4784 ('r', 'rev', '',
4805 ('r', 'rev', '',
4785 _('revision'), _('REV'))],
4806 _('revision'), _('REV'))],
4786 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4807 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4787 "verify": (verify, []),
4808 "verify": (verify, []),
4788 "version": (version_, []),
4809 "version": (version_, []),
4789 }
4810 }
4790
4811
4791 norepo = ("clone init version help debugcommands debugcomplete"
4812 norepo = ("clone init version help debugcommands debugcomplete"
4792 " debugdate debuginstall debugfsinfo debugpushkey")
4813 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs")
4793 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4814 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4794 " debugdata debugindex debugindexdot")
4815 " debugdata debugindex debugindexdot")
@@ -1,1920 +1,1924 b''
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class 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 bin, hex, nullid, nullrev, short
8 from node import bin, hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import repo, changegroup, subrepo, discovery, pushkey
10 import repo, changegroup, subrepo, discovery, pushkey
11 import changelog, dirstate, filelog, manifest, context, bookmarks
11 import changelog, dirstate, filelog, manifest, context, bookmarks
12 import lock, transaction, store, encoding
12 import lock, transaction, store, encoding
13 import util, extensions, hook, error
13 import util, extensions, hook, error
14 import match as matchmod
14 import match as matchmod
15 import merge as mergemod
15 import merge as mergemod
16 import tags as tagsmod
16 import tags as tagsmod
17 import url as urlmod
17 import url as urlmod
18 from lock import release
18 from lock import release
19 import weakref, errno, os, time, inspect
19 import weakref, errno, os, time, inspect
20 propertycache = util.propertycache
20 propertycache = util.propertycache
21
21
22 class localrepository(repo.repository):
22 class localrepository(repo.repository):
23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey'))
23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey'))
24 supportedformats = set(('revlogv1', 'parentdelta'))
24 supportedformats = set(('revlogv1', 'parentdelta'))
25 supported = supportedformats | set(('store', 'fncache', 'shared',
25 supported = supportedformats | set(('store', 'fncache', 'shared',
26 'dotencode'))
26 'dotencode'))
27
27
28 def __init__(self, baseui, path=None, create=0):
28 def __init__(self, baseui, path=None, create=0):
29 repo.repository.__init__(self)
29 repo.repository.__init__(self)
30 self.root = os.path.realpath(util.expandpath(path))
30 self.root = os.path.realpath(util.expandpath(path))
31 self.path = os.path.join(self.root, ".hg")
31 self.path = os.path.join(self.root, ".hg")
32 self.origroot = path
32 self.origroot = path
33 self.auditor = util.path_auditor(self.root, self._checknested)
33 self.auditor = util.path_auditor(self.root, self._checknested)
34 self.opener = util.opener(self.path)
34 self.opener = util.opener(self.path)
35 self.wopener = util.opener(self.root)
35 self.wopener = util.opener(self.root)
36 self.baseui = baseui
36 self.baseui = baseui
37 self.ui = baseui.copy()
37 self.ui = baseui.copy()
38
38
39 try:
39 try:
40 self.ui.readconfig(self.join("hgrc"), self.root)
40 self.ui.readconfig(self.join("hgrc"), self.root)
41 extensions.loadall(self.ui)
41 extensions.loadall(self.ui)
42 except IOError:
42 except IOError:
43 pass
43 pass
44
44
45 if not os.path.isdir(self.path):
45 if not os.path.isdir(self.path):
46 if create:
46 if create:
47 if not os.path.exists(path):
47 if not os.path.exists(path):
48 util.makedirs(path)
48 util.makedirs(path)
49 os.mkdir(self.path)
49 os.mkdir(self.path)
50 requirements = ["revlogv1"]
50 requirements = ["revlogv1"]
51 if self.ui.configbool('format', 'usestore', True):
51 if self.ui.configbool('format', 'usestore', True):
52 os.mkdir(os.path.join(self.path, "store"))
52 os.mkdir(os.path.join(self.path, "store"))
53 requirements.append("store")
53 requirements.append("store")
54 if self.ui.configbool('format', 'usefncache', True):
54 if self.ui.configbool('format', 'usefncache', True):
55 requirements.append("fncache")
55 requirements.append("fncache")
56 if self.ui.configbool('format', 'dotencode', True):
56 if self.ui.configbool('format', 'dotencode', True):
57 requirements.append('dotencode')
57 requirements.append('dotencode')
58 # create an invalid changelog
58 # create an invalid changelog
59 self.opener("00changelog.i", "a").write(
59 self.opener("00changelog.i", "a").write(
60 '\0\0\0\2' # represents revlogv2
60 '\0\0\0\2' # represents revlogv2
61 ' dummy changelog to prevent using the old repo layout'
61 ' dummy changelog to prevent using the old repo layout'
62 )
62 )
63 if self.ui.configbool('format', 'parentdelta', False):
63 if self.ui.configbool('format', 'parentdelta', False):
64 requirements.append("parentdelta")
64 requirements.append("parentdelta")
65 else:
65 else:
66 raise error.RepoError(_("repository %s not found") % path)
66 raise error.RepoError(_("repository %s not found") % path)
67 elif create:
67 elif create:
68 raise error.RepoError(_("repository %s already exists") % path)
68 raise error.RepoError(_("repository %s already exists") % path)
69 else:
69 else:
70 # find requirements
70 # find requirements
71 requirements = set()
71 requirements = set()
72 try:
72 try:
73 requirements = set(self.opener("requires").read().splitlines())
73 requirements = set(self.opener("requires").read().splitlines())
74 except IOError, inst:
74 except IOError, inst:
75 if inst.errno != errno.ENOENT:
75 if inst.errno != errno.ENOENT:
76 raise
76 raise
77 for r in requirements - self.supported:
77 for r in requirements - self.supported:
78 raise error.RequirementError(
78 raise error.RequirementError(
79 _("requirement '%s' not supported") % r)
79 _("requirement '%s' not supported") % r)
80
80
81 self.sharedpath = self.path
81 self.sharedpath = self.path
82 try:
82 try:
83 s = os.path.realpath(self.opener("sharedpath").read())
83 s = os.path.realpath(self.opener("sharedpath").read())
84 if not os.path.exists(s):
84 if not os.path.exists(s):
85 raise error.RepoError(
85 raise error.RepoError(
86 _('.hg/sharedpath points to nonexistent directory %s') % s)
86 _('.hg/sharedpath points to nonexistent directory %s') % s)
87 self.sharedpath = s
87 self.sharedpath = s
88 except IOError, inst:
88 except IOError, inst:
89 if inst.errno != errno.ENOENT:
89 if inst.errno != errno.ENOENT:
90 raise
90 raise
91
91
92 self.store = store.store(requirements, self.sharedpath, util.opener)
92 self.store = store.store(requirements, self.sharedpath, util.opener)
93 self.spath = self.store.path
93 self.spath = self.store.path
94 self.sopener = self.store.opener
94 self.sopener = self.store.opener
95 self.sjoin = self.store.join
95 self.sjoin = self.store.join
96 self.opener.createmode = self.store.createmode
96 self.opener.createmode = self.store.createmode
97 self._applyrequirements(requirements)
97 self._applyrequirements(requirements)
98 if create:
98 if create:
99 self._writerequirements()
99 self._writerequirements()
100
100
101 # These two define the set of tags for this repository. _tags
101 # These two define the set of tags for this repository. _tags
102 # maps tag name to node; _tagtypes maps tag name to 'global' or
102 # maps tag name to node; _tagtypes maps tag name to 'global' or
103 # 'local'. (Global tags are defined by .hgtags across all
103 # 'local'. (Global tags are defined by .hgtags across all
104 # heads, and local tags are defined in .hg/localtags.) They
104 # heads, and local tags are defined in .hg/localtags.) They
105 # constitute the in-memory cache of tags.
105 # constitute the in-memory cache of tags.
106 self._tags = None
106 self._tags = None
107 self._tagtypes = None
107 self._tagtypes = None
108
108
109 self._branchcache = None
109 self._branchcache = None
110 self._branchcachetip = None
110 self._branchcachetip = None
111 self.nodetagscache = None
111 self.nodetagscache = None
112 self.filterpats = {}
112 self.filterpats = {}
113 self._datafilters = {}
113 self._datafilters = {}
114 self._transref = self._lockref = self._wlockref = None
114 self._transref = self._lockref = self._wlockref = None
115
115
116 def _applyrequirements(self, requirements):
116 def _applyrequirements(self, requirements):
117 self.requirements = requirements
117 self.requirements = requirements
118 self.sopener.options = {}
118 self.sopener.options = {}
119 if 'parentdelta' in requirements:
119 if 'parentdelta' in requirements:
120 self.sopener.options['parentdelta'] = 1
120 self.sopener.options['parentdelta'] = 1
121
121
122 def _writerequirements(self):
122 def _writerequirements(self):
123 reqfile = self.opener("requires", "w")
123 reqfile = self.opener("requires", "w")
124 for r in self.requirements:
124 for r in self.requirements:
125 reqfile.write("%s\n" % r)
125 reqfile.write("%s\n" % r)
126 reqfile.close()
126 reqfile.close()
127
127
128 def _checknested(self, path):
128 def _checknested(self, path):
129 """Determine if path is a legal nested repository."""
129 """Determine if path is a legal nested repository."""
130 if not path.startswith(self.root):
130 if not path.startswith(self.root):
131 return False
131 return False
132 subpath = path[len(self.root) + 1:]
132 subpath = path[len(self.root) + 1:]
133
133
134 # XXX: Checking against the current working copy is wrong in
134 # XXX: Checking against the current working copy is wrong in
135 # the sense that it can reject things like
135 # the sense that it can reject things like
136 #
136 #
137 # $ hg cat -r 10 sub/x.txt
137 # $ hg cat -r 10 sub/x.txt
138 #
138 #
139 # if sub/ is no longer a subrepository in the working copy
139 # if sub/ is no longer a subrepository in the working copy
140 # parent revision.
140 # parent revision.
141 #
141 #
142 # However, it can of course also allow things that would have
142 # However, it can of course also allow things that would have
143 # been rejected before, such as the above cat command if sub/
143 # been rejected before, such as the above cat command if sub/
144 # is a subrepository now, but was a normal directory before.
144 # is a subrepository now, but was a normal directory before.
145 # The old path auditor would have rejected by mistake since it
145 # The old path auditor would have rejected by mistake since it
146 # panics when it sees sub/.hg/.
146 # panics when it sees sub/.hg/.
147 #
147 #
148 # All in all, checking against the working copy seems sensible
148 # All in all, checking against the working copy seems sensible
149 # since we want to prevent access to nested repositories on
149 # since we want to prevent access to nested repositories on
150 # the filesystem *now*.
150 # the filesystem *now*.
151 ctx = self[None]
151 ctx = self[None]
152 parts = util.splitpath(subpath)
152 parts = util.splitpath(subpath)
153 while parts:
153 while parts:
154 prefix = os.sep.join(parts)
154 prefix = os.sep.join(parts)
155 if prefix in ctx.substate:
155 if prefix in ctx.substate:
156 if prefix == subpath:
156 if prefix == subpath:
157 return True
157 return True
158 else:
158 else:
159 sub = ctx.sub(prefix)
159 sub = ctx.sub(prefix)
160 return sub.checknested(subpath[len(prefix) + 1:])
160 return sub.checknested(subpath[len(prefix) + 1:])
161 else:
161 else:
162 parts.pop()
162 parts.pop()
163 return False
163 return False
164
164
165 @util.propertycache
165 @util.propertycache
166 def _bookmarks(self):
166 def _bookmarks(self):
167 return bookmarks.read(self)
167 return bookmarks.read(self)
168
168
169 @util.propertycache
169 @util.propertycache
170 def _bookmarkcurrent(self):
170 def _bookmarkcurrent(self):
171 return bookmarks.readcurrent(self)
171 return bookmarks.readcurrent(self)
172
172
173 @propertycache
173 @propertycache
174 def changelog(self):
174 def changelog(self):
175 c = changelog.changelog(self.sopener)
175 c = changelog.changelog(self.sopener)
176 if 'HG_PENDING' in os.environ:
176 if 'HG_PENDING' in os.environ:
177 p = os.environ['HG_PENDING']
177 p = os.environ['HG_PENDING']
178 if p.startswith(self.root):
178 if p.startswith(self.root):
179 c.readpending('00changelog.i.a')
179 c.readpending('00changelog.i.a')
180 self.sopener.options['defversion'] = c.version
180 self.sopener.options['defversion'] = c.version
181 return c
181 return c
182
182
183 @propertycache
183 @propertycache
184 def manifest(self):
184 def manifest(self):
185 return manifest.manifest(self.sopener)
185 return manifest.manifest(self.sopener)
186
186
187 @propertycache
187 @propertycache
188 def dirstate(self):
188 def dirstate(self):
189 warned = [0]
189 warned = [0]
190 def validate(node):
190 def validate(node):
191 try:
191 try:
192 r = self.changelog.rev(node)
192 r = self.changelog.rev(node)
193 return node
193 return node
194 except error.LookupError:
194 except error.LookupError:
195 if not warned[0]:
195 if not warned[0]:
196 warned[0] = True
196 warned[0] = True
197 self.ui.warn(_("warning: ignoring unknown"
197 self.ui.warn(_("warning: ignoring unknown"
198 " working parent %s!\n") % short(node))
198 " working parent %s!\n") % short(node))
199 return nullid
199 return nullid
200
200
201 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
201 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
202
202
203 def __getitem__(self, changeid):
203 def __getitem__(self, changeid):
204 if changeid is None:
204 if changeid is None:
205 return context.workingctx(self)
205 return context.workingctx(self)
206 return context.changectx(self, changeid)
206 return context.changectx(self, changeid)
207
207
208 def __contains__(self, changeid):
208 def __contains__(self, changeid):
209 try:
209 try:
210 return bool(self.lookup(changeid))
210 return bool(self.lookup(changeid))
211 except error.RepoLookupError:
211 except error.RepoLookupError:
212 return False
212 return False
213
213
214 def __nonzero__(self):
214 def __nonzero__(self):
215 return True
215 return True
216
216
217 def __len__(self):
217 def __len__(self):
218 return len(self.changelog)
218 return len(self.changelog)
219
219
220 def __iter__(self):
220 def __iter__(self):
221 for i in xrange(len(self)):
221 for i in xrange(len(self)):
222 yield i
222 yield i
223
223
224 def url(self):
224 def url(self):
225 return 'file:' + self.root
225 return 'file:' + self.root
226
226
227 def hook(self, name, throw=False, **args):
227 def hook(self, name, throw=False, **args):
228 return hook.hook(self.ui, self, name, throw, **args)
228 return hook.hook(self.ui, self, name, throw, **args)
229
229
230 tag_disallowed = ':\r\n'
230 tag_disallowed = ':\r\n'
231
231
232 def _tag(self, names, node, message, local, user, date, extra={}):
232 def _tag(self, names, node, message, local, user, date, extra={}):
233 if isinstance(names, str):
233 if isinstance(names, str):
234 allchars = names
234 allchars = names
235 names = (names,)
235 names = (names,)
236 else:
236 else:
237 allchars = ''.join(names)
237 allchars = ''.join(names)
238 for c in self.tag_disallowed:
238 for c in self.tag_disallowed:
239 if c in allchars:
239 if c in allchars:
240 raise util.Abort(_('%r cannot be used in a tag name') % c)
240 raise util.Abort(_('%r cannot be used in a tag name') % c)
241
241
242 branches = self.branchmap()
242 branches = self.branchmap()
243 for name in names:
243 for name in names:
244 self.hook('pretag', throw=True, node=hex(node), tag=name,
244 self.hook('pretag', throw=True, node=hex(node), tag=name,
245 local=local)
245 local=local)
246 if name in branches:
246 if name in branches:
247 self.ui.warn(_("warning: tag %s conflicts with existing"
247 self.ui.warn(_("warning: tag %s conflicts with existing"
248 " branch name\n") % name)
248 " branch name\n") % name)
249
249
250 def writetags(fp, names, munge, prevtags):
250 def writetags(fp, names, munge, prevtags):
251 fp.seek(0, 2)
251 fp.seek(0, 2)
252 if prevtags and prevtags[-1] != '\n':
252 if prevtags and prevtags[-1] != '\n':
253 fp.write('\n')
253 fp.write('\n')
254 for name in names:
254 for name in names:
255 m = munge and munge(name) or name
255 m = munge and munge(name) or name
256 if self._tagtypes and name in self._tagtypes:
256 if self._tagtypes and name in self._tagtypes:
257 old = self._tags.get(name, nullid)
257 old = self._tags.get(name, nullid)
258 fp.write('%s %s\n' % (hex(old), m))
258 fp.write('%s %s\n' % (hex(old), m))
259 fp.write('%s %s\n' % (hex(node), m))
259 fp.write('%s %s\n' % (hex(node), m))
260 fp.close()
260 fp.close()
261
261
262 prevtags = ''
262 prevtags = ''
263 if local:
263 if local:
264 try:
264 try:
265 fp = self.opener('localtags', 'r+')
265 fp = self.opener('localtags', 'r+')
266 except IOError:
266 except IOError:
267 fp = self.opener('localtags', 'a')
267 fp = self.opener('localtags', 'a')
268 else:
268 else:
269 prevtags = fp.read()
269 prevtags = fp.read()
270
270
271 # local tags are stored in the current charset
271 # local tags are stored in the current charset
272 writetags(fp, names, None, prevtags)
272 writetags(fp, names, None, prevtags)
273 for name in names:
273 for name in names:
274 self.hook('tag', node=hex(node), tag=name, local=local)
274 self.hook('tag', node=hex(node), tag=name, local=local)
275 return
275 return
276
276
277 try:
277 try:
278 fp = self.wfile('.hgtags', 'rb+')
278 fp = self.wfile('.hgtags', 'rb+')
279 except IOError:
279 except IOError:
280 fp = self.wfile('.hgtags', 'ab')
280 fp = self.wfile('.hgtags', 'ab')
281 else:
281 else:
282 prevtags = fp.read()
282 prevtags = fp.read()
283
283
284 # committed tags are stored in UTF-8
284 # committed tags are stored in UTF-8
285 writetags(fp, names, encoding.fromlocal, prevtags)
285 writetags(fp, names, encoding.fromlocal, prevtags)
286
286
287 fp.close()
287 fp.close()
288
288
289 if '.hgtags' not in self.dirstate:
289 if '.hgtags' not in self.dirstate:
290 self[None].add(['.hgtags'])
290 self[None].add(['.hgtags'])
291
291
292 m = matchmod.exact(self.root, '', ['.hgtags'])
292 m = matchmod.exact(self.root, '', ['.hgtags'])
293 tagnode = self.commit(message, user, date, extra=extra, match=m)
293 tagnode = self.commit(message, user, date, extra=extra, match=m)
294
294
295 for name in names:
295 for name in names:
296 self.hook('tag', node=hex(node), tag=name, local=local)
296 self.hook('tag', node=hex(node), tag=name, local=local)
297
297
298 return tagnode
298 return tagnode
299
299
300 def tag(self, names, node, message, local, user, date):
300 def tag(self, names, node, message, local, user, date):
301 '''tag a revision with one or more symbolic names.
301 '''tag a revision with one or more symbolic names.
302
302
303 names is a list of strings or, when adding a single tag, names may be a
303 names is a list of strings or, when adding a single tag, names may be a
304 string.
304 string.
305
305
306 if local is True, the tags are stored in a per-repository file.
306 if local is True, the tags are stored in a per-repository file.
307 otherwise, they are stored in the .hgtags file, and a new
307 otherwise, they are stored in the .hgtags file, and a new
308 changeset is committed with the change.
308 changeset is committed with the change.
309
309
310 keyword arguments:
310 keyword arguments:
311
311
312 local: whether to store tags in non-version-controlled file
312 local: whether to store tags in non-version-controlled file
313 (default False)
313 (default False)
314
314
315 message: commit message to use if committing
315 message: commit message to use if committing
316
316
317 user: name of user to use if committing
317 user: name of user to use if committing
318
318
319 date: date tuple to use if committing'''
319 date: date tuple to use if committing'''
320
320
321 if not local:
321 if not local:
322 for x in self.status()[:5]:
322 for x in self.status()[:5]:
323 if '.hgtags' in x:
323 if '.hgtags' in x:
324 raise util.Abort(_('working copy of .hgtags is changed '
324 raise util.Abort(_('working copy of .hgtags is changed '
325 '(please commit .hgtags manually)'))
325 '(please commit .hgtags manually)'))
326
326
327 self.tags() # instantiate the cache
327 self.tags() # instantiate the cache
328 self._tag(names, node, message, local, user, date)
328 self._tag(names, node, message, local, user, date)
329
329
330 def tags(self):
330 def tags(self):
331 '''return a mapping of tag to node'''
331 '''return a mapping of tag to node'''
332 if self._tags is None:
332 if self._tags is None:
333 (self._tags, self._tagtypes) = self._findtags()
333 (self._tags, self._tagtypes) = self._findtags()
334
334
335 return self._tags
335 return self._tags
336
336
337 def _findtags(self):
337 def _findtags(self):
338 '''Do the hard work of finding tags. Return a pair of dicts
338 '''Do the hard work of finding tags. Return a pair of dicts
339 (tags, tagtypes) where tags maps tag name to node, and tagtypes
339 (tags, tagtypes) where tags maps tag name to node, and tagtypes
340 maps tag name to a string like \'global\' or \'local\'.
340 maps tag name to a string like \'global\' or \'local\'.
341 Subclasses or extensions are free to add their own tags, but
341 Subclasses or extensions are free to add their own tags, but
342 should be aware that the returned dicts will be retained for the
342 should be aware that the returned dicts will be retained for the
343 duration of the localrepo object.'''
343 duration of the localrepo object.'''
344
344
345 # XXX what tagtype should subclasses/extensions use? Currently
345 # XXX what tagtype should subclasses/extensions use? Currently
346 # mq and bookmarks add tags, but do not set the tagtype at all.
346 # mq and bookmarks add tags, but do not set the tagtype at all.
347 # Should each extension invent its own tag type? Should there
347 # Should each extension invent its own tag type? Should there
348 # be one tagtype for all such "virtual" tags? Or is the status
348 # be one tagtype for all such "virtual" tags? Or is the status
349 # quo fine?
349 # quo fine?
350
350
351 alltags = {} # map tag name to (node, hist)
351 alltags = {} # map tag name to (node, hist)
352 tagtypes = {}
352 tagtypes = {}
353
353
354 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
354 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
355 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
355 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
356
356
357 # Build the return dicts. Have to re-encode tag names because
357 # Build the return dicts. Have to re-encode tag names because
358 # the tags module always uses UTF-8 (in order not to lose info
358 # the tags module always uses UTF-8 (in order not to lose info
359 # writing to the cache), but the rest of Mercurial wants them in
359 # writing to the cache), but the rest of Mercurial wants them in
360 # local encoding.
360 # local encoding.
361 tags = {}
361 tags = {}
362 for (name, (node, hist)) in alltags.iteritems():
362 for (name, (node, hist)) in alltags.iteritems():
363 if node != nullid:
363 if node != nullid:
364 tags[encoding.tolocal(name)] = node
364 tags[encoding.tolocal(name)] = node
365 tags['tip'] = self.changelog.tip()
365 tags['tip'] = self.changelog.tip()
366 tagtypes = dict([(encoding.tolocal(name), value)
366 tagtypes = dict([(encoding.tolocal(name), value)
367 for (name, value) in tagtypes.iteritems()])
367 for (name, value) in tagtypes.iteritems()])
368 return (tags, tagtypes)
368 return (tags, tagtypes)
369
369
370 def tagtype(self, tagname):
370 def tagtype(self, tagname):
371 '''
371 '''
372 return the type of the given tag. result can be:
372 return the type of the given tag. result can be:
373
373
374 'local' : a local tag
374 'local' : a local tag
375 'global' : a global tag
375 'global' : a global tag
376 None : tag does not exist
376 None : tag does not exist
377 '''
377 '''
378
378
379 self.tags()
379 self.tags()
380
380
381 return self._tagtypes.get(tagname)
381 return self._tagtypes.get(tagname)
382
382
383 def tagslist(self):
383 def tagslist(self):
384 '''return a list of tags ordered by revision'''
384 '''return a list of tags ordered by revision'''
385 l = []
385 l = []
386 for t, n in self.tags().iteritems():
386 for t, n in self.tags().iteritems():
387 try:
387 try:
388 r = self.changelog.rev(n)
388 r = self.changelog.rev(n)
389 except:
389 except:
390 r = -2 # sort to the beginning of the list if unknown
390 r = -2 # sort to the beginning of the list if unknown
391 l.append((r, t, n))
391 l.append((r, t, n))
392 return [(t, n) for r, t, n in sorted(l)]
392 return [(t, n) for r, t, n in sorted(l)]
393
393
394 def nodetags(self, node):
394 def nodetags(self, node):
395 '''return the tags associated with a node'''
395 '''return the tags associated with a node'''
396 if not self.nodetagscache:
396 if not self.nodetagscache:
397 self.nodetagscache = {}
397 self.nodetagscache = {}
398 for t, n in self.tags().iteritems():
398 for t, n in self.tags().iteritems():
399 self.nodetagscache.setdefault(n, []).append(t)
399 self.nodetagscache.setdefault(n, []).append(t)
400 for tags in self.nodetagscache.itervalues():
400 for tags in self.nodetagscache.itervalues():
401 tags.sort()
401 tags.sort()
402 return self.nodetagscache.get(node, [])
402 return self.nodetagscache.get(node, [])
403
403
404 def nodebookmarks(self, node):
404 def nodebookmarks(self, node):
405 marks = []
405 marks = []
406 for bookmark, n in self._bookmarks.iteritems():
406 for bookmark, n in self._bookmarks.iteritems():
407 if n == node:
407 if n == node:
408 marks.append(bookmark)
408 marks.append(bookmark)
409 return sorted(marks)
409 return sorted(marks)
410
410
411 def _branchtags(self, partial, lrev):
411 def _branchtags(self, partial, lrev):
412 # TODO: rename this function?
412 # TODO: rename this function?
413 tiprev = len(self) - 1
413 tiprev = len(self) - 1
414 if lrev != tiprev:
414 if lrev != tiprev:
415 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
415 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
416 self._updatebranchcache(partial, ctxgen)
416 self._updatebranchcache(partial, ctxgen)
417 self._writebranchcache(partial, self.changelog.tip(), tiprev)
417 self._writebranchcache(partial, self.changelog.tip(), tiprev)
418
418
419 return partial
419 return partial
420
420
421 def updatebranchcache(self):
421 def updatebranchcache(self):
422 tip = self.changelog.tip()
422 tip = self.changelog.tip()
423 if self._branchcache is not None and self._branchcachetip == tip:
423 if self._branchcache is not None and self._branchcachetip == tip:
424 return self._branchcache
424 return self._branchcache
425
425
426 oldtip = self._branchcachetip
426 oldtip = self._branchcachetip
427 self._branchcachetip = tip
427 self._branchcachetip = tip
428 if oldtip is None or oldtip not in self.changelog.nodemap:
428 if oldtip is None or oldtip not in self.changelog.nodemap:
429 partial, last, lrev = self._readbranchcache()
429 partial, last, lrev = self._readbranchcache()
430 else:
430 else:
431 lrev = self.changelog.rev(oldtip)
431 lrev = self.changelog.rev(oldtip)
432 partial = self._branchcache
432 partial = self._branchcache
433
433
434 self._branchtags(partial, lrev)
434 self._branchtags(partial, lrev)
435 # this private cache holds all heads (not just tips)
435 # this private cache holds all heads (not just tips)
436 self._branchcache = partial
436 self._branchcache = partial
437
437
438 def branchmap(self):
438 def branchmap(self):
439 '''returns a dictionary {branch: [branchheads]}'''
439 '''returns a dictionary {branch: [branchheads]}'''
440 self.updatebranchcache()
440 self.updatebranchcache()
441 return self._branchcache
441 return self._branchcache
442
442
443 def branchtags(self):
443 def branchtags(self):
444 '''return a dict where branch names map to the tipmost head of
444 '''return a dict where branch names map to the tipmost head of
445 the branch, open heads come before closed'''
445 the branch, open heads come before closed'''
446 bt = {}
446 bt = {}
447 for bn, heads in self.branchmap().iteritems():
447 for bn, heads in self.branchmap().iteritems():
448 tip = heads[-1]
448 tip = heads[-1]
449 for h in reversed(heads):
449 for h in reversed(heads):
450 if 'close' not in self.changelog.read(h)[5]:
450 if 'close' not in self.changelog.read(h)[5]:
451 tip = h
451 tip = h
452 break
452 break
453 bt[bn] = tip
453 bt[bn] = tip
454 return bt
454 return bt
455
455
456 def _readbranchcache(self):
456 def _readbranchcache(self):
457 partial = {}
457 partial = {}
458 try:
458 try:
459 f = self.opener("cache/branchheads")
459 f = self.opener("cache/branchheads")
460 lines = f.read().split('\n')
460 lines = f.read().split('\n')
461 f.close()
461 f.close()
462 except (IOError, OSError):
462 except (IOError, OSError):
463 return {}, nullid, nullrev
463 return {}, nullid, nullrev
464
464
465 try:
465 try:
466 last, lrev = lines.pop(0).split(" ", 1)
466 last, lrev = lines.pop(0).split(" ", 1)
467 last, lrev = bin(last), int(lrev)
467 last, lrev = bin(last), int(lrev)
468 if lrev >= len(self) or self[lrev].node() != last:
468 if lrev >= len(self) or self[lrev].node() != last:
469 # invalidate the cache
469 # invalidate the cache
470 raise ValueError('invalidating branch cache (tip differs)')
470 raise ValueError('invalidating branch cache (tip differs)')
471 for l in lines:
471 for l in lines:
472 if not l:
472 if not l:
473 continue
473 continue
474 node, label = l.split(" ", 1)
474 node, label = l.split(" ", 1)
475 label = encoding.tolocal(label.strip())
475 label = encoding.tolocal(label.strip())
476 partial.setdefault(label, []).append(bin(node))
476 partial.setdefault(label, []).append(bin(node))
477 except KeyboardInterrupt:
477 except KeyboardInterrupt:
478 raise
478 raise
479 except Exception, inst:
479 except Exception, inst:
480 if self.ui.debugflag:
480 if self.ui.debugflag:
481 self.ui.warn(str(inst), '\n')
481 self.ui.warn(str(inst), '\n')
482 partial, last, lrev = {}, nullid, nullrev
482 partial, last, lrev = {}, nullid, nullrev
483 return partial, last, lrev
483 return partial, last, lrev
484
484
485 def _writebranchcache(self, branches, tip, tiprev):
485 def _writebranchcache(self, branches, tip, tiprev):
486 try:
486 try:
487 f = self.opener("cache/branchheads", "w", atomictemp=True)
487 f = self.opener("cache/branchheads", "w", atomictemp=True)
488 f.write("%s %s\n" % (hex(tip), tiprev))
488 f.write("%s %s\n" % (hex(tip), tiprev))
489 for label, nodes in branches.iteritems():
489 for label, nodes in branches.iteritems():
490 for node in nodes:
490 for node in nodes:
491 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
491 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
492 f.rename()
492 f.rename()
493 except (IOError, OSError):
493 except (IOError, OSError):
494 pass
494 pass
495
495
496 def _updatebranchcache(self, partial, ctxgen):
496 def _updatebranchcache(self, partial, ctxgen):
497 # collect new branch entries
497 # collect new branch entries
498 newbranches = {}
498 newbranches = {}
499 for c in ctxgen:
499 for c in ctxgen:
500 newbranches.setdefault(c.branch(), []).append(c.node())
500 newbranches.setdefault(c.branch(), []).append(c.node())
501 # if older branchheads are reachable from new ones, they aren't
501 # if older branchheads are reachable from new ones, they aren't
502 # really branchheads. Note checking parents is insufficient:
502 # really branchheads. Note checking parents is insufficient:
503 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
503 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
504 for branch, newnodes in newbranches.iteritems():
504 for branch, newnodes in newbranches.iteritems():
505 bheads = partial.setdefault(branch, [])
505 bheads = partial.setdefault(branch, [])
506 bheads.extend(newnodes)
506 bheads.extend(newnodes)
507 if len(bheads) <= 1:
507 if len(bheads) <= 1:
508 continue
508 continue
509 # starting from tip means fewer passes over reachable
509 # starting from tip means fewer passes over reachable
510 while newnodes:
510 while newnodes:
511 latest = newnodes.pop()
511 latest = newnodes.pop()
512 if latest not in bheads:
512 if latest not in bheads:
513 continue
513 continue
514 minbhrev = self[min([self[bh].rev() for bh in bheads])].node()
514 minbhrev = self[min([self[bh].rev() for bh in bheads])].node()
515 reachable = self.changelog.reachable(latest, minbhrev)
515 reachable = self.changelog.reachable(latest, minbhrev)
516 reachable.remove(latest)
516 reachable.remove(latest)
517 bheads = [b for b in bheads if b not in reachable]
517 bheads = [b for b in bheads if b not in reachable]
518 partial[branch] = bheads
518 partial[branch] = bheads
519
519
520 def lookup(self, key):
520 def lookup(self, key):
521 if isinstance(key, int):
521 if isinstance(key, int):
522 return self.changelog.node(key)
522 return self.changelog.node(key)
523 elif key == '.':
523 elif key == '.':
524 return self.dirstate.parents()[0]
524 return self.dirstate.parents()[0]
525 elif key == 'null':
525 elif key == 'null':
526 return nullid
526 return nullid
527 elif key == 'tip':
527 elif key == 'tip':
528 return self.changelog.tip()
528 return self.changelog.tip()
529 n = self.changelog._match(key)
529 n = self.changelog._match(key)
530 if n:
530 if n:
531 return n
531 return n
532 if key in self._bookmarks:
532 if key in self._bookmarks:
533 return self._bookmarks[key]
533 return self._bookmarks[key]
534 if key in self.tags():
534 if key in self.tags():
535 return self.tags()[key]
535 return self.tags()[key]
536 if key in self.branchtags():
536 if key in self.branchtags():
537 return self.branchtags()[key]
537 return self.branchtags()[key]
538 n = self.changelog._partialmatch(key)
538 n = self.changelog._partialmatch(key)
539 if n:
539 if n:
540 return n
540 return n
541
541
542 # can't find key, check if it might have come from damaged dirstate
542 # can't find key, check if it might have come from damaged dirstate
543 if key in self.dirstate.parents():
543 if key in self.dirstate.parents():
544 raise error.Abort(_("working directory has unknown parent '%s'!")
544 raise error.Abort(_("working directory has unknown parent '%s'!")
545 % short(key))
545 % short(key))
546 try:
546 try:
547 if len(key) == 20:
547 if len(key) == 20:
548 key = hex(key)
548 key = hex(key)
549 except:
549 except:
550 pass
550 pass
551 raise error.RepoLookupError(_("unknown revision '%s'") % key)
551 raise error.RepoLookupError(_("unknown revision '%s'") % key)
552
552
553 def lookupbranch(self, key, remote=None):
553 def lookupbranch(self, key, remote=None):
554 repo = remote or self
554 repo = remote or self
555 if key in repo.branchmap():
555 if key in repo.branchmap():
556 return key
556 return key
557
557
558 repo = (remote and remote.local()) and remote or self
558 repo = (remote and remote.local()) and remote or self
559 return repo[key].branch()
559 return repo[key].branch()
560
560
561 def local(self):
561 def local(self):
562 return True
562 return True
563
563
564 def join(self, f):
564 def join(self, f):
565 return os.path.join(self.path, f)
565 return os.path.join(self.path, f)
566
566
567 def wjoin(self, f):
567 def wjoin(self, f):
568 return os.path.join(self.root, f)
568 return os.path.join(self.root, f)
569
569
570 def file(self, f):
570 def file(self, f):
571 if f[0] == '/':
571 if f[0] == '/':
572 f = f[1:]
572 f = f[1:]
573 return filelog.filelog(self.sopener, f)
573 return filelog.filelog(self.sopener, f)
574
574
575 def changectx(self, changeid):
575 def changectx(self, changeid):
576 return self[changeid]
576 return self[changeid]
577
577
578 def parents(self, changeid=None):
578 def parents(self, changeid=None):
579 '''get list of changectxs for parents of changeid'''
579 '''get list of changectxs for parents of changeid'''
580 return self[changeid].parents()
580 return self[changeid].parents()
581
581
582 def filectx(self, path, changeid=None, fileid=None):
582 def filectx(self, path, changeid=None, fileid=None):
583 """changeid can be a changeset revision, node, or tag.
583 """changeid can be a changeset revision, node, or tag.
584 fileid can be a file revision or node."""
584 fileid can be a file revision or node."""
585 return context.filectx(self, path, changeid, fileid)
585 return context.filectx(self, path, changeid, fileid)
586
586
587 def getcwd(self):
587 def getcwd(self):
588 return self.dirstate.getcwd()
588 return self.dirstate.getcwd()
589
589
590 def pathto(self, f, cwd=None):
590 def pathto(self, f, cwd=None):
591 return self.dirstate.pathto(f, cwd)
591 return self.dirstate.pathto(f, cwd)
592
592
593 def wfile(self, f, mode='r'):
593 def wfile(self, f, mode='r'):
594 return self.wopener(f, mode)
594 return self.wopener(f, mode)
595
595
596 def _link(self, f):
596 def _link(self, f):
597 return os.path.islink(self.wjoin(f))
597 return os.path.islink(self.wjoin(f))
598
598
599 def _loadfilter(self, filter):
599 def _loadfilter(self, filter):
600 if filter not in self.filterpats:
600 if filter not in self.filterpats:
601 l = []
601 l = []
602 for pat, cmd in self.ui.configitems(filter):
602 for pat, cmd in self.ui.configitems(filter):
603 if cmd == '!':
603 if cmd == '!':
604 continue
604 continue
605 mf = matchmod.match(self.root, '', [pat])
605 mf = matchmod.match(self.root, '', [pat])
606 fn = None
606 fn = None
607 params = cmd
607 params = cmd
608 for name, filterfn in self._datafilters.iteritems():
608 for name, filterfn in self._datafilters.iteritems():
609 if cmd.startswith(name):
609 if cmd.startswith(name):
610 fn = filterfn
610 fn = filterfn
611 params = cmd[len(name):].lstrip()
611 params = cmd[len(name):].lstrip()
612 break
612 break
613 if not fn:
613 if not fn:
614 fn = lambda s, c, **kwargs: util.filter(s, c)
614 fn = lambda s, c, **kwargs: util.filter(s, c)
615 # Wrap old filters not supporting keyword arguments
615 # Wrap old filters not supporting keyword arguments
616 if not inspect.getargspec(fn)[2]:
616 if not inspect.getargspec(fn)[2]:
617 oldfn = fn
617 oldfn = fn
618 fn = lambda s, c, **kwargs: oldfn(s, c)
618 fn = lambda s, c, **kwargs: oldfn(s, c)
619 l.append((mf, fn, params))
619 l.append((mf, fn, params))
620 self.filterpats[filter] = l
620 self.filterpats[filter] = l
621 return self.filterpats[filter]
621 return self.filterpats[filter]
622
622
623 def _filter(self, filterpats, filename, data):
623 def _filter(self, filterpats, filename, data):
624 for mf, fn, cmd in filterpats:
624 for mf, fn, cmd in filterpats:
625 if mf(filename):
625 if mf(filename):
626 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
626 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
627 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
627 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
628 break
628 break
629
629
630 return data
630 return data
631
631
632 @propertycache
632 @propertycache
633 def _encodefilterpats(self):
633 def _encodefilterpats(self):
634 return self._loadfilter('encode')
634 return self._loadfilter('encode')
635
635
636 @propertycache
636 @propertycache
637 def _decodefilterpats(self):
637 def _decodefilterpats(self):
638 return self._loadfilter('decode')
638 return self._loadfilter('decode')
639
639
640 def adddatafilter(self, name, filter):
640 def adddatafilter(self, name, filter):
641 self._datafilters[name] = filter
641 self._datafilters[name] = filter
642
642
643 def wread(self, filename):
643 def wread(self, filename):
644 if self._link(filename):
644 if self._link(filename):
645 data = os.readlink(self.wjoin(filename))
645 data = os.readlink(self.wjoin(filename))
646 else:
646 else:
647 data = self.wopener(filename, 'r').read()
647 data = self.wopener(filename, 'r').read()
648 return self._filter(self._encodefilterpats, filename, data)
648 return self._filter(self._encodefilterpats, filename, data)
649
649
650 def wwrite(self, filename, data, flags):
650 def wwrite(self, filename, data, flags):
651 data = self._filter(self._decodefilterpats, filename, data)
651 data = self._filter(self._decodefilterpats, filename, data)
652 if 'l' in flags:
652 if 'l' in flags:
653 self.wopener.symlink(data, filename)
653 self.wopener.symlink(data, filename)
654 else:
654 else:
655 self.wopener(filename, 'w').write(data)
655 self.wopener(filename, 'w').write(data)
656 if 'x' in flags:
656 if 'x' in flags:
657 util.set_flags(self.wjoin(filename), False, True)
657 util.set_flags(self.wjoin(filename), False, True)
658
658
659 def wwritedata(self, filename, data):
659 def wwritedata(self, filename, data):
660 return self._filter(self._decodefilterpats, filename, data)
660 return self._filter(self._decodefilterpats, filename, data)
661
661
662 def transaction(self, desc):
662 def transaction(self, desc):
663 tr = self._transref and self._transref() or None
663 tr = self._transref and self._transref() or None
664 if tr and tr.running():
664 if tr and tr.running():
665 return tr.nest()
665 return tr.nest()
666
666
667 # abort here if the journal already exists
667 # abort here if the journal already exists
668 if os.path.exists(self.sjoin("journal")):
668 if os.path.exists(self.sjoin("journal")):
669 raise error.RepoError(
669 raise error.RepoError(
670 _("abandoned transaction found - run hg recover"))
670 _("abandoned transaction found - run hg recover"))
671
671
672 # save dirstate for rollback
672 # save dirstate for rollback
673 try:
673 try:
674 ds = self.opener("dirstate").read()
674 ds = self.opener("dirstate").read()
675 except IOError:
675 except IOError:
676 ds = ""
676 ds = ""
677 self.opener("journal.dirstate", "w").write(ds)
677 self.opener("journal.dirstate", "w").write(ds)
678 self.opener("journal.branch", "w").write(
678 self.opener("journal.branch", "w").write(
679 encoding.fromlocal(self.dirstate.branch()))
679 encoding.fromlocal(self.dirstate.branch()))
680 self.opener("journal.desc", "w").write("%d\n%s\n" % (len(self), desc))
680 self.opener("journal.desc", "w").write("%d\n%s\n" % (len(self), desc))
681
681
682 renames = [(self.sjoin("journal"), self.sjoin("undo")),
682 renames = [(self.sjoin("journal"), self.sjoin("undo")),
683 (self.join("journal.dirstate"), self.join("undo.dirstate")),
683 (self.join("journal.dirstate"), self.join("undo.dirstate")),
684 (self.join("journal.branch"), self.join("undo.branch")),
684 (self.join("journal.branch"), self.join("undo.branch")),
685 (self.join("journal.desc"), self.join("undo.desc"))]
685 (self.join("journal.desc"), self.join("undo.desc"))]
686 tr = transaction.transaction(self.ui.warn, self.sopener,
686 tr = transaction.transaction(self.ui.warn, self.sopener,
687 self.sjoin("journal"),
687 self.sjoin("journal"),
688 aftertrans(renames),
688 aftertrans(renames),
689 self.store.createmode)
689 self.store.createmode)
690 self._transref = weakref.ref(tr)
690 self._transref = weakref.ref(tr)
691 return tr
691 return tr
692
692
693 def recover(self):
693 def recover(self):
694 lock = self.lock()
694 lock = self.lock()
695 try:
695 try:
696 if os.path.exists(self.sjoin("journal")):
696 if os.path.exists(self.sjoin("journal")):
697 self.ui.status(_("rolling back interrupted transaction\n"))
697 self.ui.status(_("rolling back interrupted transaction\n"))
698 transaction.rollback(self.sopener, self.sjoin("journal"),
698 transaction.rollback(self.sopener, self.sjoin("journal"),
699 self.ui.warn)
699 self.ui.warn)
700 self.invalidate()
700 self.invalidate()
701 return True
701 return True
702 else:
702 else:
703 self.ui.warn(_("no interrupted transaction available\n"))
703 self.ui.warn(_("no interrupted transaction available\n"))
704 return False
704 return False
705 finally:
705 finally:
706 lock.release()
706 lock.release()
707
707
708 def rollback(self, dryrun=False):
708 def rollback(self, dryrun=False):
709 wlock = lock = None
709 wlock = lock = None
710 try:
710 try:
711 wlock = self.wlock()
711 wlock = self.wlock()
712 lock = self.lock()
712 lock = self.lock()
713 if os.path.exists(self.sjoin("undo")):
713 if os.path.exists(self.sjoin("undo")):
714 try:
714 try:
715 args = self.opener("undo.desc", "r").read().splitlines()
715 args = self.opener("undo.desc", "r").read().splitlines()
716 if len(args) >= 3 and self.ui.verbose:
716 if len(args) >= 3 and self.ui.verbose:
717 desc = _("repository tip rolled back to revision %s"
717 desc = _("repository tip rolled back to revision %s"
718 " (undo %s: %s)\n") % (
718 " (undo %s: %s)\n") % (
719 int(args[0]) - 1, args[1], args[2])
719 int(args[0]) - 1, args[1], args[2])
720 elif len(args) >= 2:
720 elif len(args) >= 2:
721 desc = _("repository tip rolled back to revision %s"
721 desc = _("repository tip rolled back to revision %s"
722 " (undo %s)\n") % (
722 " (undo %s)\n") % (
723 int(args[0]) - 1, args[1])
723 int(args[0]) - 1, args[1])
724 except IOError:
724 except IOError:
725 desc = _("rolling back unknown transaction\n")
725 desc = _("rolling back unknown transaction\n")
726 self.ui.status(desc)
726 self.ui.status(desc)
727 if dryrun:
727 if dryrun:
728 return
728 return
729 transaction.rollback(self.sopener, self.sjoin("undo"),
729 transaction.rollback(self.sopener, self.sjoin("undo"),
730 self.ui.warn)
730 self.ui.warn)
731 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
731 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
732 if os.path.exists(self.join('undo.bookmarks')):
732 if os.path.exists(self.join('undo.bookmarks')):
733 util.rename(self.join('undo.bookmarks'),
733 util.rename(self.join('undo.bookmarks'),
734 self.join('bookmarks'))
734 self.join('bookmarks'))
735 try:
735 try:
736 branch = self.opener("undo.branch").read()
736 branch = self.opener("undo.branch").read()
737 self.dirstate.setbranch(branch)
737 self.dirstate.setbranch(branch)
738 except IOError:
738 except IOError:
739 self.ui.warn(_("Named branch could not be reset, "
739 self.ui.warn(_("Named branch could not be reset, "
740 "current branch still is: %s\n")
740 "current branch still is: %s\n")
741 % self.dirstate.branch())
741 % self.dirstate.branch())
742 self.invalidate()
742 self.invalidate()
743 self.dirstate.invalidate()
743 self.dirstate.invalidate()
744 self.destroyed()
744 self.destroyed()
745 parents = tuple([p.rev() for p in self.parents()])
745 parents = tuple([p.rev() for p in self.parents()])
746 if len(parents) > 1:
746 if len(parents) > 1:
747 self.ui.status(_("working directory now based on "
747 self.ui.status(_("working directory now based on "
748 "revisions %d and %d\n") % parents)
748 "revisions %d and %d\n") % parents)
749 else:
749 else:
750 self.ui.status(_("working directory now based on "
750 self.ui.status(_("working directory now based on "
751 "revision %d\n") % parents)
751 "revision %d\n") % parents)
752 else:
752 else:
753 self.ui.warn(_("no rollback information available\n"))
753 self.ui.warn(_("no rollback information available\n"))
754 return 1
754 return 1
755 finally:
755 finally:
756 release(lock, wlock)
756 release(lock, wlock)
757
757
758 def invalidatecaches(self):
758 def invalidatecaches(self):
759 self._tags = None
759 self._tags = None
760 self._tagtypes = None
760 self._tagtypes = None
761 self.nodetagscache = None
761 self.nodetagscache = None
762 self._branchcache = None # in UTF-8
762 self._branchcache = None # in UTF-8
763 self._branchcachetip = None
763 self._branchcachetip = None
764
764
765 def invalidate(self):
765 def invalidate(self):
766 for a in ("changelog", "manifest", "_bookmarks", "_bookmarkcurrent"):
766 for a in ("changelog", "manifest", "_bookmarks", "_bookmarkcurrent"):
767 if a in self.__dict__:
767 if a in self.__dict__:
768 delattr(self, a)
768 delattr(self, a)
769 self.invalidatecaches()
769 self.invalidatecaches()
770
770
771 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
771 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
772 try:
772 try:
773 l = lock.lock(lockname, 0, releasefn, desc=desc)
773 l = lock.lock(lockname, 0, releasefn, desc=desc)
774 except error.LockHeld, inst:
774 except error.LockHeld, inst:
775 if not wait:
775 if not wait:
776 raise
776 raise
777 self.ui.warn(_("waiting for lock on %s held by %r\n") %
777 self.ui.warn(_("waiting for lock on %s held by %r\n") %
778 (desc, inst.locker))
778 (desc, inst.locker))
779 # default to 600 seconds timeout
779 # default to 600 seconds timeout
780 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
780 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
781 releasefn, desc=desc)
781 releasefn, desc=desc)
782 if acquirefn:
782 if acquirefn:
783 acquirefn()
783 acquirefn()
784 return l
784 return l
785
785
786 def lock(self, wait=True):
786 def lock(self, wait=True):
787 '''Lock the repository store (.hg/store) and return a weak reference
787 '''Lock the repository store (.hg/store) and return a weak reference
788 to the lock. Use this before modifying the store (e.g. committing or
788 to the lock. Use this before modifying the store (e.g. committing or
789 stripping). If you are opening a transaction, get a lock as well.)'''
789 stripping). If you are opening a transaction, get a lock as well.)'''
790 l = self._lockref and self._lockref()
790 l = self._lockref and self._lockref()
791 if l is not None and l.held:
791 if l is not None and l.held:
792 l.lock()
792 l.lock()
793 return l
793 return l
794
794
795 l = self._lock(self.sjoin("lock"), wait, self.store.write,
795 l = self._lock(self.sjoin("lock"), wait, self.store.write,
796 self.invalidate, _('repository %s') % self.origroot)
796 self.invalidate, _('repository %s') % self.origroot)
797 self._lockref = weakref.ref(l)
797 self._lockref = weakref.ref(l)
798 return l
798 return l
799
799
800 def wlock(self, wait=True):
800 def wlock(self, wait=True):
801 '''Lock the non-store parts of the repository (everything under
801 '''Lock the non-store parts of the repository (everything under
802 .hg except .hg/store) and return a weak reference to the lock.
802 .hg except .hg/store) and return a weak reference to the lock.
803 Use this before modifying files in .hg.'''
803 Use this before modifying files in .hg.'''
804 l = self._wlockref and self._wlockref()
804 l = self._wlockref and self._wlockref()
805 if l is not None and l.held:
805 if l is not None and l.held:
806 l.lock()
806 l.lock()
807 return l
807 return l
808
808
809 l = self._lock(self.join("wlock"), wait, self.dirstate.write,
809 l = self._lock(self.join("wlock"), wait, self.dirstate.write,
810 self.dirstate.invalidate, _('working directory of %s') %
810 self.dirstate.invalidate, _('working directory of %s') %
811 self.origroot)
811 self.origroot)
812 self._wlockref = weakref.ref(l)
812 self._wlockref = weakref.ref(l)
813 return l
813 return l
814
814
815 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
815 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
816 """
816 """
817 commit an individual file as part of a larger transaction
817 commit an individual file as part of a larger transaction
818 """
818 """
819
819
820 fname = fctx.path()
820 fname = fctx.path()
821 text = fctx.data()
821 text = fctx.data()
822 flog = self.file(fname)
822 flog = self.file(fname)
823 fparent1 = manifest1.get(fname, nullid)
823 fparent1 = manifest1.get(fname, nullid)
824 fparent2 = fparent2o = manifest2.get(fname, nullid)
824 fparent2 = fparent2o = manifest2.get(fname, nullid)
825
825
826 meta = {}
826 meta = {}
827 copy = fctx.renamed()
827 copy = fctx.renamed()
828 if copy and copy[0] != fname:
828 if copy and copy[0] != fname:
829 # Mark the new revision of this file as a copy of another
829 # Mark the new revision of this file as a copy of another
830 # file. This copy data will effectively act as a parent
830 # file. This copy data will effectively act as a parent
831 # of this new revision. If this is a merge, the first
831 # of this new revision. If this is a merge, the first
832 # parent will be the nullid (meaning "look up the copy data")
832 # parent will be the nullid (meaning "look up the copy data")
833 # and the second one will be the other parent. For example:
833 # and the second one will be the other parent. For example:
834 #
834 #
835 # 0 --- 1 --- 3 rev1 changes file foo
835 # 0 --- 1 --- 3 rev1 changes file foo
836 # \ / rev2 renames foo to bar and changes it
836 # \ / rev2 renames foo to bar and changes it
837 # \- 2 -/ rev3 should have bar with all changes and
837 # \- 2 -/ rev3 should have bar with all changes and
838 # should record that bar descends from
838 # should record that bar descends from
839 # bar in rev2 and foo in rev1
839 # bar in rev2 and foo in rev1
840 #
840 #
841 # this allows this merge to succeed:
841 # this allows this merge to succeed:
842 #
842 #
843 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
843 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
844 # \ / merging rev3 and rev4 should use bar@rev2
844 # \ / merging rev3 and rev4 should use bar@rev2
845 # \- 2 --- 4 as the merge base
845 # \- 2 --- 4 as the merge base
846 #
846 #
847
847
848 cfname = copy[0]
848 cfname = copy[0]
849 crev = manifest1.get(cfname)
849 crev = manifest1.get(cfname)
850 newfparent = fparent2
850 newfparent = fparent2
851
851
852 if manifest2: # branch merge
852 if manifest2: # branch merge
853 if fparent2 == nullid or crev is None: # copied on remote side
853 if fparent2 == nullid or crev is None: # copied on remote side
854 if cfname in manifest2:
854 if cfname in manifest2:
855 crev = manifest2[cfname]
855 crev = manifest2[cfname]
856 newfparent = fparent1
856 newfparent = fparent1
857
857
858 # find source in nearest ancestor if we've lost track
858 # find source in nearest ancestor if we've lost track
859 if not crev:
859 if not crev:
860 self.ui.debug(" %s: searching for copy revision for %s\n" %
860 self.ui.debug(" %s: searching for copy revision for %s\n" %
861 (fname, cfname))
861 (fname, cfname))
862 for ancestor in self[None].ancestors():
862 for ancestor in self[None].ancestors():
863 if cfname in ancestor:
863 if cfname in ancestor:
864 crev = ancestor[cfname].filenode()
864 crev = ancestor[cfname].filenode()
865 break
865 break
866
866
867 if crev:
867 if crev:
868 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
868 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
869 meta["copy"] = cfname
869 meta["copy"] = cfname
870 meta["copyrev"] = hex(crev)
870 meta["copyrev"] = hex(crev)
871 fparent1, fparent2 = nullid, newfparent
871 fparent1, fparent2 = nullid, newfparent
872 else:
872 else:
873 self.ui.warn(_("warning: can't find ancestor for '%s' "
873 self.ui.warn(_("warning: can't find ancestor for '%s' "
874 "copied from '%s'!\n") % (fname, cfname))
874 "copied from '%s'!\n") % (fname, cfname))
875
875
876 elif fparent2 != nullid:
876 elif fparent2 != nullid:
877 # is one parent an ancestor of the other?
877 # is one parent an ancestor of the other?
878 fparentancestor = flog.ancestor(fparent1, fparent2)
878 fparentancestor = flog.ancestor(fparent1, fparent2)
879 if fparentancestor == fparent1:
879 if fparentancestor == fparent1:
880 fparent1, fparent2 = fparent2, nullid
880 fparent1, fparent2 = fparent2, nullid
881 elif fparentancestor == fparent2:
881 elif fparentancestor == fparent2:
882 fparent2 = nullid
882 fparent2 = nullid
883
883
884 # is the file changed?
884 # is the file changed?
885 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
885 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
886 changelist.append(fname)
886 changelist.append(fname)
887 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
887 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
888
888
889 # are just the flags changed during merge?
889 # are just the flags changed during merge?
890 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
890 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
891 changelist.append(fname)
891 changelist.append(fname)
892
892
893 return fparent1
893 return fparent1
894
894
895 def commit(self, text="", user=None, date=None, match=None, force=False,
895 def commit(self, text="", user=None, date=None, match=None, force=False,
896 editor=False, extra={}):
896 editor=False, extra={}):
897 """Add a new revision to current repository.
897 """Add a new revision to current repository.
898
898
899 Revision information is gathered from the working directory,
899 Revision information is gathered from the working directory,
900 match can be used to filter the committed files. If editor is
900 match can be used to filter the committed files. If editor is
901 supplied, it is called to get a commit message.
901 supplied, it is called to get a commit message.
902 """
902 """
903
903
904 def fail(f, msg):
904 def fail(f, msg):
905 raise util.Abort('%s: %s' % (f, msg))
905 raise util.Abort('%s: %s' % (f, msg))
906
906
907 if not match:
907 if not match:
908 match = matchmod.always(self.root, '')
908 match = matchmod.always(self.root, '')
909
909
910 if not force:
910 if not force:
911 vdirs = []
911 vdirs = []
912 match.dir = vdirs.append
912 match.dir = vdirs.append
913 match.bad = fail
913 match.bad = fail
914
914
915 wlock = self.wlock()
915 wlock = self.wlock()
916 try:
916 try:
917 wctx = self[None]
917 wctx = self[None]
918 merge = len(wctx.parents()) > 1
918 merge = len(wctx.parents()) > 1
919
919
920 if (not force and merge and match and
920 if (not force and merge and match and
921 (match.files() or match.anypats())):
921 (match.files() or match.anypats())):
922 raise util.Abort(_('cannot partially commit a merge '
922 raise util.Abort(_('cannot partially commit a merge '
923 '(do not specify files or patterns)'))
923 '(do not specify files or patterns)'))
924
924
925 changes = self.status(match=match, clean=force)
925 changes = self.status(match=match, clean=force)
926 if force:
926 if force:
927 changes[0].extend(changes[6]) # mq may commit unchanged files
927 changes[0].extend(changes[6]) # mq may commit unchanged files
928
928
929 # check subrepos
929 # check subrepos
930 subs = []
930 subs = []
931 removedsubs = set()
931 removedsubs = set()
932 for p in wctx.parents():
932 for p in wctx.parents():
933 removedsubs.update(s for s in p.substate if match(s))
933 removedsubs.update(s for s in p.substate if match(s))
934 for s in wctx.substate:
934 for s in wctx.substate:
935 removedsubs.discard(s)
935 removedsubs.discard(s)
936 if match(s) and wctx.sub(s).dirty():
936 if match(s) and wctx.sub(s).dirty():
937 subs.append(s)
937 subs.append(s)
938 if (subs or removedsubs):
938 if (subs or removedsubs):
939 if (not match('.hgsub') and
939 if (not match('.hgsub') and
940 '.hgsub' in (wctx.modified() + wctx.added())):
940 '.hgsub' in (wctx.modified() + wctx.added())):
941 raise util.Abort(_("can't commit subrepos without .hgsub"))
941 raise util.Abort(_("can't commit subrepos without .hgsub"))
942 if '.hgsubstate' not in changes[0]:
942 if '.hgsubstate' not in changes[0]:
943 changes[0].insert(0, '.hgsubstate')
943 changes[0].insert(0, '.hgsubstate')
944
944
945 if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
945 if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
946 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
946 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
947 if changedsubs:
947 if changedsubs:
948 raise util.Abort(_("uncommitted changes in subrepo %s")
948 raise util.Abort(_("uncommitted changes in subrepo %s")
949 % changedsubs[0])
949 % changedsubs[0])
950
950
951 # make sure all explicit patterns are matched
951 # make sure all explicit patterns are matched
952 if not force and match.files():
952 if not force and match.files():
953 matched = set(changes[0] + changes[1] + changes[2])
953 matched = set(changes[0] + changes[1] + changes[2])
954
954
955 for f in match.files():
955 for f in match.files():
956 if f == '.' or f in matched or f in wctx.substate:
956 if f == '.' or f in matched or f in wctx.substate:
957 continue
957 continue
958 if f in changes[3]: # missing
958 if f in changes[3]: # missing
959 fail(f, _('file not found!'))
959 fail(f, _('file not found!'))
960 if f in vdirs: # visited directory
960 if f in vdirs: # visited directory
961 d = f + '/'
961 d = f + '/'
962 for mf in matched:
962 for mf in matched:
963 if mf.startswith(d):
963 if mf.startswith(d):
964 break
964 break
965 else:
965 else:
966 fail(f, _("no match under directory!"))
966 fail(f, _("no match under directory!"))
967 elif f not in self.dirstate:
967 elif f not in self.dirstate:
968 fail(f, _("file not tracked!"))
968 fail(f, _("file not tracked!"))
969
969
970 if (not force and not extra.get("close") and not merge
970 if (not force and not extra.get("close") and not merge
971 and not (changes[0] or changes[1] or changes[2])
971 and not (changes[0] or changes[1] or changes[2])
972 and wctx.branch() == wctx.p1().branch()):
972 and wctx.branch() == wctx.p1().branch()):
973 return None
973 return None
974
974
975 ms = mergemod.mergestate(self)
975 ms = mergemod.mergestate(self)
976 for f in changes[0]:
976 for f in changes[0]:
977 if f in ms and ms[f] == 'u':
977 if f in ms and ms[f] == 'u':
978 raise util.Abort(_("unresolved merge conflicts "
978 raise util.Abort(_("unresolved merge conflicts "
979 "(see hg help resolve)"))
979 "(see hg help resolve)"))
980
980
981 cctx = context.workingctx(self, text, user, date, extra, changes)
981 cctx = context.workingctx(self, text, user, date, extra, changes)
982 if editor:
982 if editor:
983 cctx._text = editor(self, cctx, subs)
983 cctx._text = editor(self, cctx, subs)
984 edited = (text != cctx._text)
984 edited = (text != cctx._text)
985
985
986 # commit subs
986 # commit subs
987 if subs or removedsubs:
987 if subs or removedsubs:
988 state = wctx.substate.copy()
988 state = wctx.substate.copy()
989 for s in sorted(subs):
989 for s in sorted(subs):
990 sub = wctx.sub(s)
990 sub = wctx.sub(s)
991 self.ui.status(_('committing subrepository %s\n') %
991 self.ui.status(_('committing subrepository %s\n') %
992 subrepo.subrelpath(sub))
992 subrepo.subrelpath(sub))
993 sr = sub.commit(cctx._text, user, date)
993 sr = sub.commit(cctx._text, user, date)
994 state[s] = (state[s][0], sr)
994 state[s] = (state[s][0], sr)
995 subrepo.writestate(self, state)
995 subrepo.writestate(self, state)
996
996
997 # Save commit message in case this transaction gets rolled back
997 # Save commit message in case this transaction gets rolled back
998 # (e.g. by a pretxncommit hook). Leave the content alone on
998 # (e.g. by a pretxncommit hook). Leave the content alone on
999 # the assumption that the user will use the same editor again.
999 # the assumption that the user will use the same editor again.
1000 msgfile = self.opener('last-message.txt', 'wb')
1000 msgfile = self.opener('last-message.txt', 'wb')
1001 msgfile.write(cctx._text)
1001 msgfile.write(cctx._text)
1002 msgfile.close()
1002 msgfile.close()
1003
1003
1004 p1, p2 = self.dirstate.parents()
1004 p1, p2 = self.dirstate.parents()
1005 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1005 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1006 try:
1006 try:
1007 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1007 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1008 ret = self.commitctx(cctx, True)
1008 ret = self.commitctx(cctx, True)
1009 except:
1009 except:
1010 if edited:
1010 if edited:
1011 msgfn = self.pathto(msgfile.name[len(self.root)+1:])
1011 msgfn = self.pathto(msgfile.name[len(self.root)+1:])
1012 self.ui.write(
1012 self.ui.write(
1013 _('note: commit message saved in %s\n') % msgfn)
1013 _('note: commit message saved in %s\n') % msgfn)
1014 raise
1014 raise
1015
1015
1016 # update bookmarks, dirstate and mergestate
1016 # update bookmarks, dirstate and mergestate
1017 parents = (p1, p2)
1017 parents = (p1, p2)
1018 if p2 == nullid:
1018 if p2 == nullid:
1019 parents = (p1,)
1019 parents = (p1,)
1020 bookmarks.update(self, parents, ret)
1020 bookmarks.update(self, parents, ret)
1021 for f in changes[0] + changes[1]:
1021 for f in changes[0] + changes[1]:
1022 self.dirstate.normal(f)
1022 self.dirstate.normal(f)
1023 for f in changes[2]:
1023 for f in changes[2]:
1024 self.dirstate.forget(f)
1024 self.dirstate.forget(f)
1025 self.dirstate.setparents(ret)
1025 self.dirstate.setparents(ret)
1026 ms.reset()
1026 ms.reset()
1027 finally:
1027 finally:
1028 wlock.release()
1028 wlock.release()
1029
1029
1030 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1030 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1031 return ret
1031 return ret
1032
1032
1033 def commitctx(self, ctx, error=False):
1033 def commitctx(self, ctx, error=False):
1034 """Add a new revision to current repository.
1034 """Add a new revision to current repository.
1035 Revision information is passed via the context argument.
1035 Revision information is passed via the context argument.
1036 """
1036 """
1037
1037
1038 tr = lock = None
1038 tr = lock = None
1039 removed = list(ctx.removed())
1039 removed = list(ctx.removed())
1040 p1, p2 = ctx.p1(), ctx.p2()
1040 p1, p2 = ctx.p1(), ctx.p2()
1041 m1 = p1.manifest().copy()
1041 m1 = p1.manifest().copy()
1042 m2 = p2.manifest()
1042 m2 = p2.manifest()
1043 user = ctx.user()
1043 user = ctx.user()
1044
1044
1045 lock = self.lock()
1045 lock = self.lock()
1046 try:
1046 try:
1047 tr = self.transaction("commit")
1047 tr = self.transaction("commit")
1048 trp = weakref.proxy(tr)
1048 trp = weakref.proxy(tr)
1049
1049
1050 # check in files
1050 # check in files
1051 new = {}
1051 new = {}
1052 changed = []
1052 changed = []
1053 linkrev = len(self)
1053 linkrev = len(self)
1054 for f in sorted(ctx.modified() + ctx.added()):
1054 for f in sorted(ctx.modified() + ctx.added()):
1055 self.ui.note(f + "\n")
1055 self.ui.note(f + "\n")
1056 try:
1056 try:
1057 fctx = ctx[f]
1057 fctx = ctx[f]
1058 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1058 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1059 changed)
1059 changed)
1060 m1.set(f, fctx.flags())
1060 m1.set(f, fctx.flags())
1061 except OSError, inst:
1061 except OSError, inst:
1062 self.ui.warn(_("trouble committing %s!\n") % f)
1062 self.ui.warn(_("trouble committing %s!\n") % f)
1063 raise
1063 raise
1064 except IOError, inst:
1064 except IOError, inst:
1065 errcode = getattr(inst, 'errno', errno.ENOENT)
1065 errcode = getattr(inst, 'errno', errno.ENOENT)
1066 if error or errcode and errcode != errno.ENOENT:
1066 if error or errcode and errcode != errno.ENOENT:
1067 self.ui.warn(_("trouble committing %s!\n") % f)
1067 self.ui.warn(_("trouble committing %s!\n") % f)
1068 raise
1068 raise
1069 else:
1069 else:
1070 removed.append(f)
1070 removed.append(f)
1071
1071
1072 # update manifest
1072 # update manifest
1073 m1.update(new)
1073 m1.update(new)
1074 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1074 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1075 drop = [f for f in removed if f in m1]
1075 drop = [f for f in removed if f in m1]
1076 for f in drop:
1076 for f in drop:
1077 del m1[f]
1077 del m1[f]
1078 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1078 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1079 p2.manifestnode(), (new, drop))
1079 p2.manifestnode(), (new, drop))
1080
1080
1081 # update changelog
1081 # update changelog
1082 self.changelog.delayupdate()
1082 self.changelog.delayupdate()
1083 n = self.changelog.add(mn, changed + removed, ctx.description(),
1083 n = self.changelog.add(mn, changed + removed, ctx.description(),
1084 trp, p1.node(), p2.node(),
1084 trp, p1.node(), p2.node(),
1085 user, ctx.date(), ctx.extra().copy())
1085 user, ctx.date(), ctx.extra().copy())
1086 p = lambda: self.changelog.writepending() and self.root or ""
1086 p = lambda: self.changelog.writepending() and self.root or ""
1087 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1087 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1088 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1088 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1089 parent2=xp2, pending=p)
1089 parent2=xp2, pending=p)
1090 self.changelog.finalize(trp)
1090 self.changelog.finalize(trp)
1091 tr.close()
1091 tr.close()
1092
1092
1093 if self._branchcache:
1093 if self._branchcache:
1094 self.updatebranchcache()
1094 self.updatebranchcache()
1095 return n
1095 return n
1096 finally:
1096 finally:
1097 if tr:
1097 if tr:
1098 tr.release()
1098 tr.release()
1099 lock.release()
1099 lock.release()
1100
1100
1101 def destroyed(self):
1101 def destroyed(self):
1102 '''Inform the repository that nodes have been destroyed.
1102 '''Inform the repository that nodes have been destroyed.
1103 Intended for use by strip and rollback, so there's a common
1103 Intended for use by strip and rollback, so there's a common
1104 place for anything that has to be done after destroying history.'''
1104 place for anything that has to be done after destroying history.'''
1105 # XXX it might be nice if we could take the list of destroyed
1105 # XXX it might be nice if we could take the list of destroyed
1106 # nodes, but I don't see an easy way for rollback() to do that
1106 # nodes, but I don't see an easy way for rollback() to do that
1107
1107
1108 # Ensure the persistent tag cache is updated. Doing it now
1108 # Ensure the persistent tag cache is updated. Doing it now
1109 # means that the tag cache only has to worry about destroyed
1109 # means that the tag cache only has to worry about destroyed
1110 # heads immediately after a strip/rollback. That in turn
1110 # heads immediately after a strip/rollback. That in turn
1111 # guarantees that "cachetip == currenttip" (comparing both rev
1111 # guarantees that "cachetip == currenttip" (comparing both rev
1112 # and node) always means no nodes have been added or destroyed.
1112 # and node) always means no nodes have been added or destroyed.
1113
1113
1114 # XXX this is suboptimal when qrefresh'ing: we strip the current
1114 # XXX this is suboptimal when qrefresh'ing: we strip the current
1115 # head, refresh the tag cache, then immediately add a new head.
1115 # head, refresh the tag cache, then immediately add a new head.
1116 # But I think doing it this way is necessary for the "instant
1116 # But I think doing it this way is necessary for the "instant
1117 # tag cache retrieval" case to work.
1117 # tag cache retrieval" case to work.
1118 self.invalidatecaches()
1118 self.invalidatecaches()
1119
1119
1120 def walk(self, match, node=None):
1120 def walk(self, match, node=None):
1121 '''
1121 '''
1122 walk recursively through the directory tree or a given
1122 walk recursively through the directory tree or a given
1123 changeset, finding all files matched by the match
1123 changeset, finding all files matched by the match
1124 function
1124 function
1125 '''
1125 '''
1126 return self[node].walk(match)
1126 return self[node].walk(match)
1127
1127
1128 def status(self, node1='.', node2=None, match=None,
1128 def status(self, node1='.', node2=None, match=None,
1129 ignored=False, clean=False, unknown=False,
1129 ignored=False, clean=False, unknown=False,
1130 listsubrepos=False):
1130 listsubrepos=False):
1131 """return status of files between two nodes or node and working directory
1131 """return status of files between two nodes or node and working directory
1132
1132
1133 If node1 is None, use the first dirstate parent instead.
1133 If node1 is None, use the first dirstate parent instead.
1134 If node2 is None, compare node1 with working directory.
1134 If node2 is None, compare node1 with working directory.
1135 """
1135 """
1136
1136
1137 def mfmatches(ctx):
1137 def mfmatches(ctx):
1138 mf = ctx.manifest().copy()
1138 mf = ctx.manifest().copy()
1139 for fn in mf.keys():
1139 for fn in mf.keys():
1140 if not match(fn):
1140 if not match(fn):
1141 del mf[fn]
1141 del mf[fn]
1142 return mf
1142 return mf
1143
1143
1144 if isinstance(node1, context.changectx):
1144 if isinstance(node1, context.changectx):
1145 ctx1 = node1
1145 ctx1 = node1
1146 else:
1146 else:
1147 ctx1 = self[node1]
1147 ctx1 = self[node1]
1148 if isinstance(node2, context.changectx):
1148 if isinstance(node2, context.changectx):
1149 ctx2 = node2
1149 ctx2 = node2
1150 else:
1150 else:
1151 ctx2 = self[node2]
1151 ctx2 = self[node2]
1152
1152
1153 working = ctx2.rev() is None
1153 working = ctx2.rev() is None
1154 parentworking = working and ctx1 == self['.']
1154 parentworking = working and ctx1 == self['.']
1155 match = match or matchmod.always(self.root, self.getcwd())
1155 match = match or matchmod.always(self.root, self.getcwd())
1156 listignored, listclean, listunknown = ignored, clean, unknown
1156 listignored, listclean, listunknown = ignored, clean, unknown
1157
1157
1158 # load earliest manifest first for caching reasons
1158 # load earliest manifest first for caching reasons
1159 if not working and ctx2.rev() < ctx1.rev():
1159 if not working and ctx2.rev() < ctx1.rev():
1160 ctx2.manifest()
1160 ctx2.manifest()
1161
1161
1162 if not parentworking:
1162 if not parentworking:
1163 def bad(f, msg):
1163 def bad(f, msg):
1164 if f not in ctx1:
1164 if f not in ctx1:
1165 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1165 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1166 match.bad = bad
1166 match.bad = bad
1167
1167
1168 if working: # we need to scan the working dir
1168 if working: # we need to scan the working dir
1169 subrepos = []
1169 subrepos = []
1170 if '.hgsub' in self.dirstate:
1170 if '.hgsub' in self.dirstate:
1171 subrepos = ctx1.substate.keys()
1171 subrepos = ctx1.substate.keys()
1172 s = self.dirstate.status(match, subrepos, listignored,
1172 s = self.dirstate.status(match, subrepos, listignored,
1173 listclean, listunknown)
1173 listclean, listunknown)
1174 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1174 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1175
1175
1176 # check for any possibly clean files
1176 # check for any possibly clean files
1177 if parentworking and cmp:
1177 if parentworking and cmp:
1178 fixup = []
1178 fixup = []
1179 # do a full compare of any files that might have changed
1179 # do a full compare of any files that might have changed
1180 for f in sorted(cmp):
1180 for f in sorted(cmp):
1181 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1181 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1182 or ctx1[f].cmp(ctx2[f])):
1182 or ctx1[f].cmp(ctx2[f])):
1183 modified.append(f)
1183 modified.append(f)
1184 else:
1184 else:
1185 fixup.append(f)
1185 fixup.append(f)
1186
1186
1187 # update dirstate for files that are actually clean
1187 # update dirstate for files that are actually clean
1188 if fixup:
1188 if fixup:
1189 if listclean:
1189 if listclean:
1190 clean += fixup
1190 clean += fixup
1191
1191
1192 try:
1192 try:
1193 # updating the dirstate is optional
1193 # updating the dirstate is optional
1194 # so we don't wait on the lock
1194 # so we don't wait on the lock
1195 wlock = self.wlock(False)
1195 wlock = self.wlock(False)
1196 try:
1196 try:
1197 for f in fixup:
1197 for f in fixup:
1198 self.dirstate.normal(f)
1198 self.dirstate.normal(f)
1199 finally:
1199 finally:
1200 wlock.release()
1200 wlock.release()
1201 except error.LockError:
1201 except error.LockError:
1202 pass
1202 pass
1203
1203
1204 if not parentworking:
1204 if not parentworking:
1205 mf1 = mfmatches(ctx1)
1205 mf1 = mfmatches(ctx1)
1206 if working:
1206 if working:
1207 # we are comparing working dir against non-parent
1207 # we are comparing working dir against non-parent
1208 # generate a pseudo-manifest for the working dir
1208 # generate a pseudo-manifest for the working dir
1209 mf2 = mfmatches(self['.'])
1209 mf2 = mfmatches(self['.'])
1210 for f in cmp + modified + added:
1210 for f in cmp + modified + added:
1211 mf2[f] = None
1211 mf2[f] = None
1212 mf2.set(f, ctx2.flags(f))
1212 mf2.set(f, ctx2.flags(f))
1213 for f in removed:
1213 for f in removed:
1214 if f in mf2:
1214 if f in mf2:
1215 del mf2[f]
1215 del mf2[f]
1216 else:
1216 else:
1217 # we are comparing two revisions
1217 # we are comparing two revisions
1218 deleted, unknown, ignored = [], [], []
1218 deleted, unknown, ignored = [], [], []
1219 mf2 = mfmatches(ctx2)
1219 mf2 = mfmatches(ctx2)
1220
1220
1221 modified, added, clean = [], [], []
1221 modified, added, clean = [], [], []
1222 for fn in mf2:
1222 for fn in mf2:
1223 if fn in mf1:
1223 if fn in mf1:
1224 if (mf1.flags(fn) != mf2.flags(fn) or
1224 if (mf1.flags(fn) != mf2.flags(fn) or
1225 (mf1[fn] != mf2[fn] and
1225 (mf1[fn] != mf2[fn] and
1226 (mf2[fn] or ctx1[fn].cmp(ctx2[fn])))):
1226 (mf2[fn] or ctx1[fn].cmp(ctx2[fn])))):
1227 modified.append(fn)
1227 modified.append(fn)
1228 elif listclean:
1228 elif listclean:
1229 clean.append(fn)
1229 clean.append(fn)
1230 del mf1[fn]
1230 del mf1[fn]
1231 else:
1231 else:
1232 added.append(fn)
1232 added.append(fn)
1233 removed = mf1.keys()
1233 removed = mf1.keys()
1234
1234
1235 r = modified, added, removed, deleted, unknown, ignored, clean
1235 r = modified, added, removed, deleted, unknown, ignored, clean
1236
1236
1237 if listsubrepos:
1237 if listsubrepos:
1238 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1238 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1239 if working:
1239 if working:
1240 rev2 = None
1240 rev2 = None
1241 else:
1241 else:
1242 rev2 = ctx2.substate[subpath][1]
1242 rev2 = ctx2.substate[subpath][1]
1243 try:
1243 try:
1244 submatch = matchmod.narrowmatcher(subpath, match)
1244 submatch = matchmod.narrowmatcher(subpath, match)
1245 s = sub.status(rev2, match=submatch, ignored=listignored,
1245 s = sub.status(rev2, match=submatch, ignored=listignored,
1246 clean=listclean, unknown=listunknown,
1246 clean=listclean, unknown=listunknown,
1247 listsubrepos=True)
1247 listsubrepos=True)
1248 for rfiles, sfiles in zip(r, s):
1248 for rfiles, sfiles in zip(r, s):
1249 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1249 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1250 except error.LookupError:
1250 except error.LookupError:
1251 self.ui.status(_("skipping missing subrepository: %s\n")
1251 self.ui.status(_("skipping missing subrepository: %s\n")
1252 % subpath)
1252 % subpath)
1253
1253
1254 for l in r:
1254 for l in r:
1255 l.sort()
1255 l.sort()
1256 return r
1256 return r
1257
1257
1258 def heads(self, start=None):
1258 def heads(self, start=None):
1259 heads = self.changelog.heads(start)
1259 heads = self.changelog.heads(start)
1260 # sort the output in rev descending order
1260 # sort the output in rev descending order
1261 return sorted(heads, key=self.changelog.rev, reverse=True)
1261 return sorted(heads, key=self.changelog.rev, reverse=True)
1262
1262
1263 def branchheads(self, branch=None, start=None, closed=False):
1263 def branchheads(self, branch=None, start=None, closed=False):
1264 '''return a (possibly filtered) list of heads for the given branch
1264 '''return a (possibly filtered) list of heads for the given branch
1265
1265
1266 Heads are returned in topological order, from newest to oldest.
1266 Heads are returned in topological order, from newest to oldest.
1267 If branch is None, use the dirstate branch.
1267 If branch is None, use the dirstate branch.
1268 If start is not None, return only heads reachable from start.
1268 If start is not None, return only heads reachable from start.
1269 If closed is True, return heads that are marked as closed as well.
1269 If closed is True, return heads that are marked as closed as well.
1270 '''
1270 '''
1271 if branch is None:
1271 if branch is None:
1272 branch = self[None].branch()
1272 branch = self[None].branch()
1273 branches = self.branchmap()
1273 branches = self.branchmap()
1274 if branch not in branches:
1274 if branch not in branches:
1275 return []
1275 return []
1276 # the cache returns heads ordered lowest to highest
1276 # the cache returns heads ordered lowest to highest
1277 bheads = list(reversed(branches[branch]))
1277 bheads = list(reversed(branches[branch]))
1278 if start is not None:
1278 if start is not None:
1279 # filter out the heads that cannot be reached from startrev
1279 # filter out the heads that cannot be reached from startrev
1280 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1280 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1281 bheads = [h for h in bheads if h in fbheads]
1281 bheads = [h for h in bheads if h in fbheads]
1282 if not closed:
1282 if not closed:
1283 bheads = [h for h in bheads if
1283 bheads = [h for h in bheads if
1284 ('close' not in self.changelog.read(h)[5])]
1284 ('close' not in self.changelog.read(h)[5])]
1285 return bheads
1285 return bheads
1286
1286
1287 def branches(self, nodes):
1287 def branches(self, nodes):
1288 if not nodes:
1288 if not nodes:
1289 nodes = [self.changelog.tip()]
1289 nodes = [self.changelog.tip()]
1290 b = []
1290 b = []
1291 for n in nodes:
1291 for n in nodes:
1292 t = n
1292 t = n
1293 while 1:
1293 while 1:
1294 p = self.changelog.parents(n)
1294 p = self.changelog.parents(n)
1295 if p[1] != nullid or p[0] == nullid:
1295 if p[1] != nullid or p[0] == nullid:
1296 b.append((t, n, p[0], p[1]))
1296 b.append((t, n, p[0], p[1]))
1297 break
1297 break
1298 n = p[0]
1298 n = p[0]
1299 return b
1299 return b
1300
1300
1301 def between(self, pairs):
1301 def between(self, pairs):
1302 r = []
1302 r = []
1303
1303
1304 for top, bottom in pairs:
1304 for top, bottom in pairs:
1305 n, l, i = top, [], 0
1305 n, l, i = top, [], 0
1306 f = 1
1306 f = 1
1307
1307
1308 while n != bottom and n != nullid:
1308 while n != bottom and n != nullid:
1309 p = self.changelog.parents(n)[0]
1309 p = self.changelog.parents(n)[0]
1310 if i == f:
1310 if i == f:
1311 l.append(n)
1311 l.append(n)
1312 f = f * 2
1312 f = f * 2
1313 n = p
1313 n = p
1314 i += 1
1314 i += 1
1315
1315
1316 r.append(l)
1316 r.append(l)
1317
1317
1318 return r
1318 return r
1319
1319
1320 def pull(self, remote, heads=None, force=False):
1320 def pull(self, remote, heads=None, force=False):
1321 lock = self.lock()
1321 lock = self.lock()
1322 try:
1322 try:
1323 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1323 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1324 force=force)
1324 force=force)
1325 common, fetch, rheads = tmp
1325 common, fetch, rheads = tmp
1326 if not fetch:
1326 if not fetch:
1327 self.ui.status(_("no changes found\n"))
1327 self.ui.status(_("no changes found\n"))
1328 result = 0
1328 result = 0
1329 else:
1329 else:
1330 if heads is None and fetch == [nullid]:
1330 if heads is None and fetch == [nullid]:
1331 self.ui.status(_("requesting all changes\n"))
1331 self.ui.status(_("requesting all changes\n"))
1332 elif heads is None and remote.capable('changegroupsubset'):
1332 elif heads is None and remote.capable('changegroupsubset'):
1333 # issue1320, avoid a race if remote changed after discovery
1333 # issue1320, avoid a race if remote changed after discovery
1334 heads = rheads
1334 heads = rheads
1335
1335
1336 if heads is None:
1336 if heads is None:
1337 cg = remote.changegroup(fetch, 'pull')
1337 cg = remote.changegroup(fetch, 'pull')
1338 elif not remote.capable('changegroupsubset'):
1338 elif not remote.capable('changegroupsubset'):
1339 raise util.Abort(_("partial pull cannot be done because "
1339 raise util.Abort(_("partial pull cannot be done because "
1340 "other repository doesn't support "
1340 "other repository doesn't support "
1341 "changegroupsubset."))
1341 "changegroupsubset."))
1342 else:
1342 else:
1343 cg = remote.changegroupsubset(fetch, heads, 'pull')
1343 cg = remote.changegroupsubset(fetch, heads, 'pull')
1344 result = self.addchangegroup(cg, 'pull', remote.url(),
1344 result = self.addchangegroup(cg, 'pull', remote.url(),
1345 lock=lock)
1345 lock=lock)
1346 finally:
1346 finally:
1347 lock.release()
1347 lock.release()
1348
1348
1349 return result
1349 return result
1350
1350
1351 def checkpush(self, force, revs):
1351 def checkpush(self, force, revs):
1352 """Extensions can override this function if additional checks have
1352 """Extensions can override this function if additional checks have
1353 to be performed before pushing, or call it if they override push
1353 to be performed before pushing, or call it if they override push
1354 command.
1354 command.
1355 """
1355 """
1356 pass
1356 pass
1357
1357
1358 def push(self, remote, force=False, revs=None, newbranch=False):
1358 def push(self, remote, force=False, revs=None, newbranch=False):
1359 '''Push outgoing changesets (limited by revs) from the current
1359 '''Push outgoing changesets (limited by revs) from the current
1360 repository to remote. Return an integer:
1360 repository to remote. Return an integer:
1361 - 0 means HTTP error *or* nothing to push
1361 - 0 means HTTP error *or* nothing to push
1362 - 1 means we pushed and remote head count is unchanged *or*
1362 - 1 means we pushed and remote head count is unchanged *or*
1363 we have outgoing changesets but refused to push
1363 we have outgoing changesets but refused to push
1364 - other values as described by addchangegroup()
1364 - other values as described by addchangegroup()
1365 '''
1365 '''
1366 # there are two ways to push to remote repo:
1366 # there are two ways to push to remote repo:
1367 #
1367 #
1368 # addchangegroup assumes local user can lock remote
1368 # addchangegroup assumes local user can lock remote
1369 # repo (local filesystem, old ssh servers).
1369 # repo (local filesystem, old ssh servers).
1370 #
1370 #
1371 # unbundle assumes local user cannot lock remote repo (new ssh
1371 # unbundle assumes local user cannot lock remote repo (new ssh
1372 # servers, http servers).
1372 # servers, http servers).
1373
1373
1374 self.checkpush(force, revs)
1374 self.checkpush(force, revs)
1375 lock = None
1375 lock = None
1376 unbundle = remote.capable('unbundle')
1376 unbundle = remote.capable('unbundle')
1377 if not unbundle:
1377 if not unbundle:
1378 lock = remote.lock()
1378 lock = remote.lock()
1379 try:
1379 try:
1380 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1380 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1381 newbranch)
1381 newbranch)
1382 ret = remote_heads
1382 ret = remote_heads
1383 if cg is not None:
1383 if cg is not None:
1384 if unbundle:
1384 if unbundle:
1385 # local repo finds heads on server, finds out what
1385 # local repo finds heads on server, finds out what
1386 # revs it must push. once revs transferred, if server
1386 # revs it must push. once revs transferred, if server
1387 # finds it has different heads (someone else won
1387 # finds it has different heads (someone else won
1388 # commit/push race), server aborts.
1388 # commit/push race), server aborts.
1389 if force:
1389 if force:
1390 remote_heads = ['force']
1390 remote_heads = ['force']
1391 # ssh: return remote's addchangegroup()
1391 # ssh: return remote's addchangegroup()
1392 # http: return remote's addchangegroup() or 0 for error
1392 # http: return remote's addchangegroup() or 0 for error
1393 ret = remote.unbundle(cg, remote_heads, 'push')
1393 ret = remote.unbundle(cg, remote_heads, 'push')
1394 else:
1394 else:
1395 # we return an integer indicating remote head count change
1395 # we return an integer indicating remote head count change
1396 ret = remote.addchangegroup(cg, 'push', self.url(),
1396 ret = remote.addchangegroup(cg, 'push', self.url(),
1397 lock=lock)
1397 lock=lock)
1398 finally:
1398 finally:
1399 if lock is not None:
1399 if lock is not None:
1400 lock.release()
1400 lock.release()
1401
1401
1402 self.ui.debug("checking for updated bookmarks\n")
1402 self.ui.debug("checking for updated bookmarks\n")
1403 rb = remote.listkeys('bookmarks')
1403 rb = remote.listkeys('bookmarks')
1404 for k in rb.keys():
1404 for k in rb.keys():
1405 if k in self._bookmarks:
1405 if k in self._bookmarks:
1406 nr, nl = rb[k], hex(self._bookmarks[k])
1406 nr, nl = rb[k], hex(self._bookmarks[k])
1407 if nr in self:
1407 if nr in self:
1408 cr = self[nr]
1408 cr = self[nr]
1409 cl = self[nl]
1409 cl = self[nl]
1410 if cl in cr.descendants():
1410 if cl in cr.descendants():
1411 r = remote.pushkey('bookmarks', k, nr, nl)
1411 r = remote.pushkey('bookmarks', k, nr, nl)
1412 if r:
1412 if r:
1413 self.ui.status(_("updating bookmark %s\n") % k)
1413 self.ui.status(_("updating bookmark %s\n") % k)
1414 else:
1414 else:
1415 self.ui.warn(_('updating bookmark %s'
1415 self.ui.warn(_('updating bookmark %s'
1416 ' failed!\n') % k)
1416 ' failed!\n') % k)
1417
1417
1418 return ret
1418 return ret
1419
1419
1420 def changegroupinfo(self, nodes, source):
1420 def changegroupinfo(self, nodes, source):
1421 if self.ui.verbose or source == 'bundle':
1421 if self.ui.verbose or source == 'bundle':
1422 self.ui.status(_("%d changesets found\n") % len(nodes))
1422 self.ui.status(_("%d changesets found\n") % len(nodes))
1423 if self.ui.debugflag:
1423 if self.ui.debugflag:
1424 self.ui.debug("list of changesets:\n")
1424 self.ui.debug("list of changesets:\n")
1425 for node in nodes:
1425 for node in nodes:
1426 self.ui.debug("%s\n" % hex(node))
1426 self.ui.debug("%s\n" % hex(node))
1427
1427
1428 def changegroupsubset(self, bases, heads, source):
1428 def changegroupsubset(self, bases, heads, source):
1429 """Compute a changegroup consisting of all the nodes that are
1429 """Compute a changegroup consisting of all the nodes that are
1430 descendents of any of the bases and ancestors of any of the heads.
1430 descendents of any of the bases and ancestors of any of the heads.
1431 Return a chunkbuffer object whose read() method will return
1431 Return a chunkbuffer object whose read() method will return
1432 successive changegroup chunks.
1432 successive changegroup chunks.
1433
1433
1434 It is fairly complex as determining which filenodes and which
1434 It is fairly complex as determining which filenodes and which
1435 manifest nodes need to be included for the changeset to be complete
1435 manifest nodes need to be included for the changeset to be complete
1436 is non-trivial.
1436 is non-trivial.
1437
1437
1438 Another wrinkle is doing the reverse, figuring out which changeset in
1438 Another wrinkle is doing the reverse, figuring out which changeset in
1439 the changegroup a particular filenode or manifestnode belongs to.
1439 the changegroup a particular filenode or manifestnode belongs to.
1440 """
1440 """
1441
1441
1442 cl = self.changelog
1442 cl = self.changelog
1443 mf = self.manifest
1443 mf = self.manifest
1444 mfs = {} # needed manifests
1444 mfs = {} # needed manifests
1445 fnodes = {} # needed file nodes
1445 fnodes = {} # needed file nodes
1446
1446
1447 if not bases:
1447 if not bases:
1448 bases = [nullid]
1448 bases = [nullid]
1449 csets, bases, heads = cl.nodesbetween(bases, heads)
1449 csets, bases, heads = cl.nodesbetween(bases, heads)
1450
1450
1451 # can we go through the fast path ?
1451 # can we go through the fast path ?
1452 heads.sort()
1452 heads.sort()
1453 if heads == sorted(self.heads()):
1453 if heads == sorted(self.heads()):
1454 return self._changegroup(csets, source)
1454 return self._changegroup(csets, source)
1455
1455
1456 # slow path
1456 # slow path
1457 self.hook('preoutgoing', throw=True, source=source)
1457 self.hook('preoutgoing', throw=True, source=source)
1458 self.changegroupinfo(csets, source)
1458 self.changegroupinfo(csets, source)
1459
1459
1460 # We assume that all ancestors of bases are known
1460 # We assume that all ancestors of bases are known
1461 commonrevs = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1461 commonrevs = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1462
1462
1463 # A function generating function that sets up the initial environment
1463 # A function generating function that sets up the initial environment
1464 # the inner function.
1464 # the inner function.
1465 def filenode_collector(changedfiles):
1465 def filenode_collector(changedfiles):
1466 # This gathers information from each manifestnode included in the
1466 # This gathers information from each manifestnode included in the
1467 # changegroup about which filenodes the manifest node references
1467 # changegroup about which filenodes the manifest node references
1468 # so we can include those in the changegroup too.
1468 # so we can include those in the changegroup too.
1469 #
1469 #
1470 # It also remembers which changenode each filenode belongs to. It
1470 # It also remembers which changenode each filenode belongs to. It
1471 # does this by assuming the a filenode belongs to the changenode
1471 # does this by assuming the a filenode belongs to the changenode
1472 # the first manifest that references it belongs to.
1472 # the first manifest that references it belongs to.
1473 def collect(mnode):
1473 def collect(mnode):
1474 r = mf.rev(mnode)
1474 r = mf.rev(mnode)
1475 clnode = mfs[mnode]
1475 clnode = mfs[mnode]
1476 mdata = mf.readfast(mnode)
1476 mdata = mf.readfast(mnode)
1477 for f in changedfiles:
1477 for f in changedfiles:
1478 if f in mdata:
1478 if f in mdata:
1479 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1479 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1480
1480
1481 return collect
1481 return collect
1482
1482
1483 # If we determine that a particular file or manifest node must be a
1483 # If we determine that a particular file or manifest node must be a
1484 # node that the recipient of the changegroup will already have, we can
1484 # node that the recipient of the changegroup will already have, we can
1485 # also assume the recipient will have all the parents. This function
1485 # also assume the recipient will have all the parents. This function
1486 # prunes them from the set of missing nodes.
1486 # prunes them from the set of missing nodes.
1487 def prune(revlog, missingnodes):
1487 def prune(revlog, missingnodes):
1488 # drop any nodes that claim to be part of a cset in commonrevs
1488 # drop any nodes that claim to be part of a cset in commonrevs
1489 drop = set()
1489 drop = set()
1490 for n in missingnodes:
1490 for n in missingnodes:
1491 if revlog.linkrev(revlog.rev(n)) in commonrevs:
1491 if revlog.linkrev(revlog.rev(n)) in commonrevs:
1492 drop.add(n)
1492 drop.add(n)
1493 for n in drop:
1493 for n in drop:
1494 missingnodes.pop(n, None)
1494 missingnodes.pop(n, None)
1495
1495
1496 # Now that we have all theses utility functions to help out and
1496 # Now that we have all theses utility functions to help out and
1497 # logically divide up the task, generate the group.
1497 # logically divide up the task, generate the group.
1498 def gengroup():
1498 def gengroup():
1499 # The set of changed files starts empty.
1499 # The set of changed files starts empty.
1500 changedfiles = set()
1500 changedfiles = set()
1501 collect = changegroup.collector(cl, mfs, changedfiles)
1501 collect = changegroup.collector(cl, mfs, changedfiles)
1502
1502
1503 # Create a changenode group generator that will call our functions
1503 # Create a changenode group generator that will call our functions
1504 # back to lookup the owning changenode and collect information.
1504 # back to lookup the owning changenode and collect information.
1505 group = cl.group(csets, lambda x: x, collect)
1505 group = cl.group(csets, lambda x: x, collect)
1506 for count, chunk in enumerate(group):
1506 for count, chunk in enumerate(group):
1507 yield chunk
1507 yield chunk
1508 # revlog.group yields three entries per node, so
1508 # revlog.group yields three entries per node, so
1509 # dividing by 3 gives an approximation of how many
1509 # dividing by 3 gives an approximation of how many
1510 # nodes have been processed.
1510 # nodes have been processed.
1511 self.ui.progress(_('bundling'), count / 3,
1511 self.ui.progress(_('bundling'), count / 3,
1512 unit=_('changesets'))
1512 unit=_('changesets'))
1513 changecount = count / 3
1513 changecount = count / 3
1514 efiles = len(changedfiles)
1514 efiles = len(changedfiles)
1515 self.ui.progress(_('bundling'), None)
1515 self.ui.progress(_('bundling'), None)
1516
1516
1517 prune(mf, mfs)
1517 prune(mf, mfs)
1518 # Create a generator for the manifestnodes that calls our lookup
1518 # Create a generator for the manifestnodes that calls our lookup
1519 # and data collection functions back.
1519 # and data collection functions back.
1520 group = mf.group(sorted(mfs, key=mf.rev),
1520 group = mf.group(sorted(mfs, key=mf.rev),
1521 lambda mnode: mfs[mnode],
1521 lambda mnode: mfs[mnode],
1522 filenode_collector(changedfiles))
1522 filenode_collector(changedfiles))
1523 for count, chunk in enumerate(group):
1523 for count, chunk in enumerate(group):
1524 yield chunk
1524 yield chunk
1525 # see above comment for why we divide by 3
1525 # see above comment for why we divide by 3
1526 self.ui.progress(_('bundling'), count / 3,
1526 self.ui.progress(_('bundling'), count / 3,
1527 unit=_('manifests'), total=changecount)
1527 unit=_('manifests'), total=changecount)
1528 self.ui.progress(_('bundling'), None)
1528 self.ui.progress(_('bundling'), None)
1529
1529
1530 mfs.clear()
1530 mfs.clear()
1531
1531
1532 # Go through all our files in order sorted by name.
1532 # Go through all our files in order sorted by name.
1533 for idx, fname in enumerate(sorted(changedfiles)):
1533 for idx, fname in enumerate(sorted(changedfiles)):
1534 filerevlog = self.file(fname)
1534 filerevlog = self.file(fname)
1535 if not len(filerevlog):
1535 if not len(filerevlog):
1536 raise util.Abort(_("empty or missing revlog for %s") % fname)
1536 raise util.Abort(_("empty or missing revlog for %s") % fname)
1537 # Toss out the filenodes that the recipient isn't really
1537 # Toss out the filenodes that the recipient isn't really
1538 # missing.
1538 # missing.
1539 missingfnodes = fnodes.pop(fname, {})
1539 missingfnodes = fnodes.pop(fname, {})
1540 prune(filerevlog, missingfnodes)
1540 prune(filerevlog, missingfnodes)
1541 # If any filenodes are left, generate the group for them,
1541 # If any filenodes are left, generate the group for them,
1542 # otherwise don't bother.
1542 # otherwise don't bother.
1543 if missingfnodes:
1543 if missingfnodes:
1544 yield changegroup.chunkheader(len(fname))
1544 yield changegroup.chunkheader(len(fname))
1545 yield fname
1545 yield fname
1546 # Create a group generator and only pass in a changenode
1546 # Create a group generator and only pass in a changenode
1547 # lookup function as we need to collect no information
1547 # lookup function as we need to collect no information
1548 # from filenodes.
1548 # from filenodes.
1549 group = filerevlog.group(
1549 group = filerevlog.group(
1550 sorted(missingfnodes, key=filerevlog.rev),
1550 sorted(missingfnodes, key=filerevlog.rev),
1551 lambda fnode: missingfnodes[fnode])
1551 lambda fnode: missingfnodes[fnode])
1552 for chunk in group:
1552 for chunk in group:
1553 # even though we print the same progress on
1553 # even though we print the same progress on
1554 # most loop iterations, put the progress call
1554 # most loop iterations, put the progress call
1555 # here so that time estimates (if any) can be updated
1555 # here so that time estimates (if any) can be updated
1556 self.ui.progress(
1556 self.ui.progress(
1557 _('bundling'), idx, item=fname,
1557 _('bundling'), idx, item=fname,
1558 unit=_('files'), total=efiles)
1558 unit=_('files'), total=efiles)
1559 yield chunk
1559 yield chunk
1560 # Signal that no more groups are left.
1560 # Signal that no more groups are left.
1561 yield changegroup.closechunk()
1561 yield changegroup.closechunk()
1562 self.ui.progress(_('bundling'), None)
1562 self.ui.progress(_('bundling'), None)
1563
1563
1564 if csets:
1564 if csets:
1565 self.hook('outgoing', node=hex(csets[0]), source=source)
1565 self.hook('outgoing', node=hex(csets[0]), source=source)
1566
1566
1567 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1567 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1568
1568
1569 def changegroup(self, basenodes, source):
1569 def changegroup(self, basenodes, source):
1570 # to avoid a race we use changegroupsubset() (issue1320)
1570 # to avoid a race we use changegroupsubset() (issue1320)
1571 return self.changegroupsubset(basenodes, self.heads(), source)
1571 return self.changegroupsubset(basenodes, self.heads(), source)
1572
1572
1573 def _changegroup(self, nodes, source):
1573 def _changegroup(self, nodes, source):
1574 """Compute the changegroup of all nodes that we have that a recipient
1574 """Compute the changegroup of all nodes that we have that a recipient
1575 doesn't. Return a chunkbuffer object whose read() method will return
1575 doesn't. Return a chunkbuffer object whose read() method will return
1576 successive changegroup chunks.
1576 successive changegroup chunks.
1577
1577
1578 This is much easier than the previous function as we can assume that
1578 This is much easier than the previous function as we can assume that
1579 the recipient has any changenode we aren't sending them.
1579 the recipient has any changenode we aren't sending them.
1580
1580
1581 nodes is the set of nodes to send"""
1581 nodes is the set of nodes to send"""
1582
1582
1583 self.hook('preoutgoing', throw=True, source=source)
1583 self.hook('preoutgoing', throw=True, source=source)
1584
1584
1585 cl = self.changelog
1585 cl = self.changelog
1586 revset = set([cl.rev(n) for n in nodes])
1586 revset = set([cl.rev(n) for n in nodes])
1587 self.changegroupinfo(nodes, source)
1587 self.changegroupinfo(nodes, source)
1588
1588
1589 def gennodelst(log):
1589 def gennodelst(log):
1590 for r in log:
1590 for r in log:
1591 if log.linkrev(r) in revset:
1591 if log.linkrev(r) in revset:
1592 yield log.node(r)
1592 yield log.node(r)
1593
1593
1594 def lookuplinkrev_func(revlog):
1594 def lookuplinkrev_func(revlog):
1595 def lookuplinkrev(n):
1595 def lookuplinkrev(n):
1596 return cl.node(revlog.linkrev(revlog.rev(n)))
1596 return cl.node(revlog.linkrev(revlog.rev(n)))
1597 return lookuplinkrev
1597 return lookuplinkrev
1598
1598
1599 def gengroup():
1599 def gengroup():
1600 '''yield a sequence of changegroup chunks (strings)'''
1600 '''yield a sequence of changegroup chunks (strings)'''
1601 # construct a list of all changed files
1601 # construct a list of all changed files
1602 changedfiles = set()
1602 changedfiles = set()
1603 mmfs = {}
1603 mmfs = {}
1604 collect = changegroup.collector(cl, mmfs, changedfiles)
1604 collect = changegroup.collector(cl, mmfs, changedfiles)
1605
1605
1606 for count, chunk in enumerate(cl.group(nodes, lambda x: x, collect)):
1606 for count, chunk in enumerate(cl.group(nodes, lambda x: x, collect)):
1607 # revlog.group yields three entries per node, so
1607 # revlog.group yields three entries per node, so
1608 # dividing by 3 gives an approximation of how many
1608 # dividing by 3 gives an approximation of how many
1609 # nodes have been processed.
1609 # nodes have been processed.
1610 self.ui.progress(_('bundling'), count / 3, unit=_('changesets'))
1610 self.ui.progress(_('bundling'), count / 3, unit=_('changesets'))
1611 yield chunk
1611 yield chunk
1612 efiles = len(changedfiles)
1612 efiles = len(changedfiles)
1613 changecount = count / 3
1613 changecount = count / 3
1614 self.ui.progress(_('bundling'), None)
1614 self.ui.progress(_('bundling'), None)
1615
1615
1616 mnfst = self.manifest
1616 mnfst = self.manifest
1617 nodeiter = gennodelst(mnfst)
1617 nodeiter = gennodelst(mnfst)
1618 for count, chunk in enumerate(mnfst.group(nodeiter,
1618 for count, chunk in enumerate(mnfst.group(nodeiter,
1619 lookuplinkrev_func(mnfst))):
1619 lookuplinkrev_func(mnfst))):
1620 # see above comment for why we divide by 3
1620 # see above comment for why we divide by 3
1621 self.ui.progress(_('bundling'), count / 3,
1621 self.ui.progress(_('bundling'), count / 3,
1622 unit=_('manifests'), total=changecount)
1622 unit=_('manifests'), total=changecount)
1623 yield chunk
1623 yield chunk
1624 self.ui.progress(_('bundling'), None)
1624 self.ui.progress(_('bundling'), None)
1625
1625
1626 for idx, fname in enumerate(sorted(changedfiles)):
1626 for idx, fname in enumerate(sorted(changedfiles)):
1627 filerevlog = self.file(fname)
1627 filerevlog = self.file(fname)
1628 if not len(filerevlog):
1628 if not len(filerevlog):
1629 raise util.Abort(_("empty or missing revlog for %s") % fname)
1629 raise util.Abort(_("empty or missing revlog for %s") % fname)
1630 nodeiter = gennodelst(filerevlog)
1630 nodeiter = gennodelst(filerevlog)
1631 nodeiter = list(nodeiter)
1631 nodeiter = list(nodeiter)
1632 if nodeiter:
1632 if nodeiter:
1633 yield changegroup.chunkheader(len(fname))
1633 yield changegroup.chunkheader(len(fname))
1634 yield fname
1634 yield fname
1635 lookup = lookuplinkrev_func(filerevlog)
1635 lookup = lookuplinkrev_func(filerevlog)
1636 for chunk in filerevlog.group(nodeiter, lookup):
1636 for chunk in filerevlog.group(nodeiter, lookup):
1637 self.ui.progress(
1637 self.ui.progress(
1638 _('bundling'), idx, item=fname,
1638 _('bundling'), idx, item=fname,
1639 total=efiles, unit=_('files'))
1639 total=efiles, unit=_('files'))
1640 yield chunk
1640 yield chunk
1641 self.ui.progress(_('bundling'), None)
1641 self.ui.progress(_('bundling'), None)
1642
1642
1643 yield changegroup.closechunk()
1643 yield changegroup.closechunk()
1644
1644
1645 if nodes:
1645 if nodes:
1646 self.hook('outgoing', node=hex(nodes[0]), source=source)
1646 self.hook('outgoing', node=hex(nodes[0]), source=source)
1647
1647
1648 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1648 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1649
1649
1650 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1650 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1651 """Add the changegroup returned by source.read() to this repo.
1651 """Add the changegroup returned by source.read() to this repo.
1652 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1652 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1653 the URL of the repo where this changegroup is coming from.
1653 the URL of the repo where this changegroup is coming from.
1654 If lock is not None, the function takes ownership of the lock
1654 If lock is not None, the function takes ownership of the lock
1655 and releases it after the changegroup is added.
1655 and releases it after the changegroup is added.
1656
1656
1657 Return an integer summarizing the change to this repo:
1657 Return an integer summarizing the change to this repo:
1658 - nothing changed or no source: 0
1658 - nothing changed or no source: 0
1659 - more heads than before: 1+added heads (2..n)
1659 - more heads than before: 1+added heads (2..n)
1660 - fewer heads than before: -1-removed heads (-2..-n)
1660 - fewer heads than before: -1-removed heads (-2..-n)
1661 - number of heads stays the same: 1
1661 - number of heads stays the same: 1
1662 """
1662 """
1663 def csmap(x):
1663 def csmap(x):
1664 self.ui.debug("add changeset %s\n" % short(x))
1664 self.ui.debug("add changeset %s\n" % short(x))
1665 return len(cl)
1665 return len(cl)
1666
1666
1667 def revmap(x):
1667 def revmap(x):
1668 return cl.rev(x)
1668 return cl.rev(x)
1669
1669
1670 if not source:
1670 if not source:
1671 return 0
1671 return 0
1672
1672
1673 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1673 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1674
1674
1675 changesets = files = revisions = 0
1675 changesets = files = revisions = 0
1676 efiles = set()
1676 efiles = set()
1677
1677
1678 # write changelog data to temp files so concurrent readers will not see
1678 # write changelog data to temp files so concurrent readers will not see
1679 # inconsistent view
1679 # inconsistent view
1680 cl = self.changelog
1680 cl = self.changelog
1681 cl.delayupdate()
1681 cl.delayupdate()
1682 oldheads = len(cl.heads())
1682 oldheads = len(cl.heads())
1683
1683
1684 tr = self.transaction("\n".join([srctype, urlmod.hidepassword(url)]))
1684 tr = self.transaction("\n".join([srctype, urlmod.hidepassword(url)]))
1685 try:
1685 try:
1686 trp = weakref.proxy(tr)
1686 trp = weakref.proxy(tr)
1687 # pull off the changeset group
1687 # pull off the changeset group
1688 self.ui.status(_("adding changesets\n"))
1688 self.ui.status(_("adding changesets\n"))
1689 clstart = len(cl)
1689 clstart = len(cl)
1690 class prog(object):
1690 class prog(object):
1691 step = _('changesets')
1691 step = _('changesets')
1692 count = 1
1692 count = 1
1693 ui = self.ui
1693 ui = self.ui
1694 total = None
1694 total = None
1695 def __call__(self):
1695 def __call__(self):
1696 self.ui.progress(self.step, self.count, unit=_('chunks'),
1696 self.ui.progress(self.step, self.count, unit=_('chunks'),
1697 total=self.total)
1697 total=self.total)
1698 self.count += 1
1698 self.count += 1
1699 pr = prog()
1699 pr = prog()
1700 source.callback = pr
1700 source.callback = pr
1701
1701
1702 if (cl.addgroup(source, csmap, trp) is None
1702 if (cl.addgroup(source, csmap, trp) is None
1703 and not emptyok):
1703 and not emptyok):
1704 raise util.Abort(_("received changelog group is empty"))
1704 raise util.Abort(_("received changelog group is empty"))
1705 clend = len(cl)
1705 clend = len(cl)
1706 changesets = clend - clstart
1706 changesets = clend - clstart
1707 for c in xrange(clstart, clend):
1707 for c in xrange(clstart, clend):
1708 efiles.update(self[c].files())
1708 efiles.update(self[c].files())
1709 efiles = len(efiles)
1709 efiles = len(efiles)
1710 self.ui.progress(_('changesets'), None)
1710 self.ui.progress(_('changesets'), None)
1711
1711
1712 # pull off the manifest group
1712 # pull off the manifest group
1713 self.ui.status(_("adding manifests\n"))
1713 self.ui.status(_("adding manifests\n"))
1714 pr.step = _('manifests')
1714 pr.step = _('manifests')
1715 pr.count = 1
1715 pr.count = 1
1716 pr.total = changesets # manifests <= changesets
1716 pr.total = changesets # manifests <= changesets
1717 # no need to check for empty manifest group here:
1717 # no need to check for empty manifest group here:
1718 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1718 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1719 # no new manifest will be created and the manifest group will
1719 # no new manifest will be created and the manifest group will
1720 # be empty during the pull
1720 # be empty during the pull
1721 self.manifest.addgroup(source, revmap, trp)
1721 self.manifest.addgroup(source, revmap, trp)
1722 self.ui.progress(_('manifests'), None)
1722 self.ui.progress(_('manifests'), None)
1723
1723
1724 needfiles = {}
1724 needfiles = {}
1725 if self.ui.configbool('server', 'validate', default=False):
1725 if self.ui.configbool('server', 'validate', default=False):
1726 # validate incoming csets have their manifests
1726 # validate incoming csets have their manifests
1727 for cset in xrange(clstart, clend):
1727 for cset in xrange(clstart, clend):
1728 mfest = self.changelog.read(self.changelog.node(cset))[0]
1728 mfest = self.changelog.read(self.changelog.node(cset))[0]
1729 mfest = self.manifest.readdelta(mfest)
1729 mfest = self.manifest.readdelta(mfest)
1730 # store file nodes we must see
1730 # store file nodes we must see
1731 for f, n in mfest.iteritems():
1731 for f, n in mfest.iteritems():
1732 needfiles.setdefault(f, set()).add(n)
1732 needfiles.setdefault(f, set()).add(n)
1733
1733
1734 # process the files
1734 # process the files
1735 self.ui.status(_("adding file changes\n"))
1735 self.ui.status(_("adding file changes\n"))
1736 pr.step = 'files'
1736 pr.step = 'files'
1737 pr.count = 1
1737 pr.count = 1
1738 pr.total = efiles
1738 pr.total = efiles
1739 source.callback = None
1739 source.callback = None
1740
1740
1741 while 1:
1741 while 1:
1742 f = source.chunk()
1742 f = source.chunk()
1743 if not f:
1743 if not f:
1744 break
1744 break
1745 self.ui.debug("adding %s revisions\n" % f)
1745 self.ui.debug("adding %s revisions\n" % f)
1746 pr()
1746 pr()
1747 fl = self.file(f)
1747 fl = self.file(f)
1748 o = len(fl)
1748 o = len(fl)
1749 if fl.addgroup(source, revmap, trp) is None:
1749 if fl.addgroup(source, revmap, trp) is None:
1750 raise util.Abort(_("received file revlog group is empty"))
1750 raise util.Abort(_("received file revlog group is empty"))
1751 revisions += len(fl) - o
1751 revisions += len(fl) - o
1752 files += 1
1752 files += 1
1753 if f in needfiles:
1753 if f in needfiles:
1754 needs = needfiles[f]
1754 needs = needfiles[f]
1755 for new in xrange(o, len(fl)):
1755 for new in xrange(o, len(fl)):
1756 n = fl.node(new)
1756 n = fl.node(new)
1757 if n in needs:
1757 if n in needs:
1758 needs.remove(n)
1758 needs.remove(n)
1759 if not needs:
1759 if not needs:
1760 del needfiles[f]
1760 del needfiles[f]
1761 self.ui.progress(_('files'), None)
1761 self.ui.progress(_('files'), None)
1762
1762
1763 for f, needs in needfiles.iteritems():
1763 for f, needs in needfiles.iteritems():
1764 fl = self.file(f)
1764 fl = self.file(f)
1765 for n in needs:
1765 for n in needs:
1766 try:
1766 try:
1767 fl.rev(n)
1767 fl.rev(n)
1768 except error.LookupError:
1768 except error.LookupError:
1769 raise util.Abort(
1769 raise util.Abort(
1770 _('missing file data for %s:%s - run hg verify') %
1770 _('missing file data for %s:%s - run hg verify') %
1771 (f, hex(n)))
1771 (f, hex(n)))
1772
1772
1773 newheads = len(cl.heads())
1773 newheads = len(cl.heads())
1774 heads = ""
1774 heads = ""
1775 if oldheads and newheads != oldheads:
1775 if oldheads and newheads != oldheads:
1776 heads = _(" (%+d heads)") % (newheads - oldheads)
1776 heads = _(" (%+d heads)") % (newheads - oldheads)
1777
1777
1778 self.ui.status(_("added %d changesets"
1778 self.ui.status(_("added %d changesets"
1779 " with %d changes to %d files%s\n")
1779 " with %d changes to %d files%s\n")
1780 % (changesets, revisions, files, heads))
1780 % (changesets, revisions, files, heads))
1781
1781
1782 if changesets > 0:
1782 if changesets > 0:
1783 p = lambda: cl.writepending() and self.root or ""
1783 p = lambda: cl.writepending() and self.root or ""
1784 self.hook('pretxnchangegroup', throw=True,
1784 self.hook('pretxnchangegroup', throw=True,
1785 node=hex(cl.node(clstart)), source=srctype,
1785 node=hex(cl.node(clstart)), source=srctype,
1786 url=url, pending=p)
1786 url=url, pending=p)
1787
1787
1788 # make changelog see real files again
1788 # make changelog see real files again
1789 cl.finalize(trp)
1789 cl.finalize(trp)
1790
1790
1791 tr.close()
1791 tr.close()
1792 finally:
1792 finally:
1793 tr.release()
1793 tr.release()
1794 if lock:
1794 if lock:
1795 lock.release()
1795 lock.release()
1796
1796
1797 if changesets > 0:
1797 if changesets > 0:
1798 # forcefully update the on-disk branch cache
1798 # forcefully update the on-disk branch cache
1799 self.ui.debug("updating the branch cache\n")
1799 self.ui.debug("updating the branch cache\n")
1800 self.updatebranchcache()
1800 self.updatebranchcache()
1801 self.hook("changegroup", node=hex(cl.node(clstart)),
1801 self.hook("changegroup", node=hex(cl.node(clstart)),
1802 source=srctype, url=url)
1802 source=srctype, url=url)
1803
1803
1804 for i in xrange(clstart, clend):
1804 for i in xrange(clstart, clend):
1805 self.hook("incoming", node=hex(cl.node(i)),
1805 self.hook("incoming", node=hex(cl.node(i)),
1806 source=srctype, url=url)
1806 source=srctype, url=url)
1807
1807
1808 # never return 0 here:
1808 # never return 0 here:
1809 if newheads < oldheads:
1809 if newheads < oldheads:
1810 return newheads - oldheads - 1
1810 return newheads - oldheads - 1
1811 else:
1811 else:
1812 return newheads - oldheads + 1
1812 return newheads - oldheads + 1
1813
1813
1814
1814
1815 def stream_in(self, remote, requirements):
1815 def stream_in(self, remote, requirements):
1816 lock = self.lock()
1816 lock = self.lock()
1817 try:
1817 try:
1818 fp = remote.stream_out()
1818 fp = remote.stream_out()
1819 l = fp.readline()
1819 l = fp.readline()
1820 try:
1820 try:
1821 resp = int(l)
1821 resp = int(l)
1822 except ValueError:
1822 except ValueError:
1823 raise error.ResponseError(
1823 raise error.ResponseError(
1824 _('Unexpected response from remote server:'), l)
1824 _('Unexpected response from remote server:'), l)
1825 if resp == 1:
1825 if resp == 1:
1826 raise util.Abort(_('operation forbidden by server'))
1826 raise util.Abort(_('operation forbidden by server'))
1827 elif resp == 2:
1827 elif resp == 2:
1828 raise util.Abort(_('locking the remote repository failed'))
1828 raise util.Abort(_('locking the remote repository failed'))
1829 elif resp != 0:
1829 elif resp != 0:
1830 raise util.Abort(_('the server sent an unknown error code'))
1830 raise util.Abort(_('the server sent an unknown error code'))
1831 self.ui.status(_('streaming all changes\n'))
1831 self.ui.status(_('streaming all changes\n'))
1832 l = fp.readline()
1832 l = fp.readline()
1833 try:
1833 try:
1834 total_files, total_bytes = map(int, l.split(' ', 1))
1834 total_files, total_bytes = map(int, l.split(' ', 1))
1835 except (ValueError, TypeError):
1835 except (ValueError, TypeError):
1836 raise error.ResponseError(
1836 raise error.ResponseError(
1837 _('Unexpected response from remote server:'), l)
1837 _('Unexpected response from remote server:'), l)
1838 self.ui.status(_('%d files to transfer, %s of data\n') %
1838 self.ui.status(_('%d files to transfer, %s of data\n') %
1839 (total_files, util.bytecount(total_bytes)))
1839 (total_files, util.bytecount(total_bytes)))
1840 start = time.time()
1840 start = time.time()
1841 for i in xrange(total_files):
1841 for i in xrange(total_files):
1842 # XXX doesn't support '\n' or '\r' in filenames
1842 # XXX doesn't support '\n' or '\r' in filenames
1843 l = fp.readline()
1843 l = fp.readline()
1844 try:
1844 try:
1845 name, size = l.split('\0', 1)
1845 name, size = l.split('\0', 1)
1846 size = int(size)
1846 size = int(size)
1847 except (ValueError, TypeError):
1847 except (ValueError, TypeError):
1848 raise error.ResponseError(
1848 raise error.ResponseError(
1849 _('Unexpected response from remote server:'), l)
1849 _('Unexpected response from remote server:'), l)
1850 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1850 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1851 # for backwards compat, name was partially encoded
1851 # for backwards compat, name was partially encoded
1852 ofp = self.sopener(store.decodedir(name), 'w')
1852 ofp = self.sopener(store.decodedir(name), 'w')
1853 for chunk in util.filechunkiter(fp, limit=size):
1853 for chunk in util.filechunkiter(fp, limit=size):
1854 ofp.write(chunk)
1854 ofp.write(chunk)
1855 ofp.close()
1855 ofp.close()
1856 elapsed = time.time() - start
1856 elapsed = time.time() - start
1857 if elapsed <= 0:
1857 if elapsed <= 0:
1858 elapsed = 0.001
1858 elapsed = 0.001
1859 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1859 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1860 (util.bytecount(total_bytes), elapsed,
1860 (util.bytecount(total_bytes), elapsed,
1861 util.bytecount(total_bytes / elapsed)))
1861 util.bytecount(total_bytes / elapsed)))
1862
1862
1863 # new requirements = old non-format requirements + new format-related
1863 # new requirements = old non-format requirements + new format-related
1864 # requirements from the streamed-in repository
1864 # requirements from the streamed-in repository
1865 requirements.update(set(self.requirements) - self.supportedformats)
1865 requirements.update(set(self.requirements) - self.supportedformats)
1866 self._applyrequirements(requirements)
1866 self._applyrequirements(requirements)
1867 self._writerequirements()
1867 self._writerequirements()
1868
1868
1869 self.invalidate()
1869 self.invalidate()
1870 return len(self.heads()) + 1
1870 return len(self.heads()) + 1
1871 finally:
1871 finally:
1872 lock.release()
1872 lock.release()
1873
1873
1874 def clone(self, remote, heads=[], stream=False):
1874 def clone(self, remote, heads=[], stream=False):
1875 '''clone remote repository.
1875 '''clone remote repository.
1876
1876
1877 keyword arguments:
1877 keyword arguments:
1878 heads: list of revs to clone (forces use of pull)
1878 heads: list of revs to clone (forces use of pull)
1879 stream: use streaming clone if possible'''
1879 stream: use streaming clone if possible'''
1880
1880
1881 # now, all clients that can request uncompressed clones can
1881 # now, all clients that can request uncompressed clones can
1882 # read repo formats supported by all servers that can serve
1882 # read repo formats supported by all servers that can serve
1883 # them.
1883 # them.
1884
1884
1885 # if revlog format changes, client will have to check version
1885 # if revlog format changes, client will have to check version
1886 # and format flags on "stream" capability, and use
1886 # and format flags on "stream" capability, and use
1887 # uncompressed only if compatible.
1887 # uncompressed only if compatible.
1888
1888
1889 if stream and not heads:
1889 if stream and not heads:
1890 # 'stream' means remote revlog format is revlogv1 only
1890 # 'stream' means remote revlog format is revlogv1 only
1891 if remote.capable('stream'):
1891 if remote.capable('stream'):
1892 return self.stream_in(remote, set(('revlogv1',)))
1892 return self.stream_in(remote, set(('revlogv1',)))
1893 # otherwise, 'streamreqs' contains the remote revlog format
1893 # otherwise, 'streamreqs' contains the remote revlog format
1894 streamreqs = remote.capable('streamreqs')
1894 streamreqs = remote.capable('streamreqs')
1895 if streamreqs:
1895 if streamreqs:
1896 streamreqs = set(streamreqs.split(','))
1896 streamreqs = set(streamreqs.split(','))
1897 # if we support it, stream in and adjust our requirements
1897 # if we support it, stream in and adjust our requirements
1898 if not streamreqs - self.supportedformats:
1898 if not streamreqs - self.supportedformats:
1899 return self.stream_in(remote, streamreqs)
1899 return self.stream_in(remote, streamreqs)
1900 return self.pull(remote, heads)
1900 return self.pull(remote, heads)
1901
1901
1902 def pushkey(self, namespace, key, old, new):
1902 def pushkey(self, namespace, key, old, new):
1903 return pushkey.push(self, namespace, key, old, new)
1903 return pushkey.push(self, namespace, key, old, new)
1904
1904
1905 def listkeys(self, namespace):
1905 def listkeys(self, namespace):
1906 return pushkey.list(self, namespace)
1906 return pushkey.list(self, namespace)
1907
1907
1908 def debugwireargs(self, one, two, three=None, four=None):
1909 '''used to test argument passing over the wire'''
1910 return "%s %s %s %s" % (one, two, three, four)
1911
1908 # used to avoid circular references so destructors work
1912 # used to avoid circular references so destructors work
1909 def aftertrans(files):
1913 def aftertrans(files):
1910 renamefiles = [tuple(t) for t in files]
1914 renamefiles = [tuple(t) for t in files]
1911 def a():
1915 def a():
1912 for src, dest in renamefiles:
1916 for src, dest in renamefiles:
1913 util.rename(src, dest)
1917 util.rename(src, dest)
1914 return a
1918 return a
1915
1919
1916 def instance(ui, path, create):
1920 def instance(ui, path, create):
1917 return localrepository(ui, util.drop_scheme('file', path), create)
1921 return localrepository(ui, util.drop_scheme('file', path), create)
1918
1922
1919 def islocal(path):
1923 def islocal(path):
1920 return True
1924 return True
@@ -1,353 +1,366 b''
1 # wireproto.py - generic wire protocol support functions
1 # wireproto.py - generic wire protocol support functions
2 #
2 #
3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2010 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 import urllib, tempfile, os, sys
8 import urllib, tempfile, os, sys
9 from i18n import _
9 from i18n import _
10 from node import bin, hex
10 from node import bin, hex
11 import changegroup as changegroupmod
11 import changegroup as changegroupmod
12 import repo, error, encoding, util, store
12 import repo, error, encoding, util, store
13 import pushkey as pushkeymod
13 import pushkey as pushkeymod
14
14
15 # list of nodes encoding / decoding
15 # list of nodes encoding / decoding
16
16
17 def decodelist(l, sep=' '):
17 def decodelist(l, sep=' '):
18 return map(bin, l.split(sep))
18 return map(bin, l.split(sep))
19
19
20 def encodelist(l, sep=' '):
20 def encodelist(l, sep=' '):
21 return sep.join(map(hex, l))
21 return sep.join(map(hex, l))
22
22
23 # client side
23 # client side
24
24
25 class wirerepository(repo.repository):
25 class wirerepository(repo.repository):
26 def lookup(self, key):
26 def lookup(self, key):
27 self.requirecap('lookup', _('look up remote revision'))
27 self.requirecap('lookup', _('look up remote revision'))
28 d = self._call("lookup", key=encoding.fromlocal(key))
28 d = self._call("lookup", key=encoding.fromlocal(key))
29 success, data = d[:-1].split(" ", 1)
29 success, data = d[:-1].split(" ", 1)
30 if int(success):
30 if int(success):
31 return bin(data)
31 return bin(data)
32 self._abort(error.RepoError(data))
32 self._abort(error.RepoError(data))
33
33
34 def heads(self):
34 def heads(self):
35 d = self._call("heads")
35 d = self._call("heads")
36 try:
36 try:
37 return decodelist(d[:-1])
37 return decodelist(d[:-1])
38 except:
38 except:
39 self._abort(error.ResponseError(_("unexpected response:"), d))
39 self._abort(error.ResponseError(_("unexpected response:"), d))
40
40
41 def branchmap(self):
41 def branchmap(self):
42 d = self._call("branchmap")
42 d = self._call("branchmap")
43 try:
43 try:
44 branchmap = {}
44 branchmap = {}
45 for branchpart in d.splitlines():
45 for branchpart in d.splitlines():
46 branchname, branchheads = branchpart.split(' ', 1)
46 branchname, branchheads = branchpart.split(' ', 1)
47 branchname = encoding.tolocal(urllib.unquote(branchname))
47 branchname = encoding.tolocal(urllib.unquote(branchname))
48 branchheads = decodelist(branchheads)
48 branchheads = decodelist(branchheads)
49 branchmap[branchname] = branchheads
49 branchmap[branchname] = branchheads
50 return branchmap
50 return branchmap
51 except TypeError:
51 except TypeError:
52 self._abort(error.ResponseError(_("unexpected response:"), d))
52 self._abort(error.ResponseError(_("unexpected response:"), d))
53
53
54 def branches(self, nodes):
54 def branches(self, nodes):
55 n = encodelist(nodes)
55 n = encodelist(nodes)
56 d = self._call("branches", nodes=n)
56 d = self._call("branches", nodes=n)
57 try:
57 try:
58 br = [tuple(decodelist(b)) for b in d.splitlines()]
58 br = [tuple(decodelist(b)) for b in d.splitlines()]
59 return br
59 return br
60 except:
60 except:
61 self._abort(error.ResponseError(_("unexpected response:"), d))
61 self._abort(error.ResponseError(_("unexpected response:"), d))
62
62
63 def between(self, pairs):
63 def between(self, pairs):
64 batch = 8 # avoid giant requests
64 batch = 8 # avoid giant requests
65 r = []
65 r = []
66 for i in xrange(0, len(pairs), batch):
66 for i in xrange(0, len(pairs), batch):
67 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
67 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
68 d = self._call("between", pairs=n)
68 d = self._call("between", pairs=n)
69 try:
69 try:
70 r.extend(l and decodelist(l) or [] for l in d.splitlines())
70 r.extend(l and decodelist(l) or [] for l in d.splitlines())
71 except:
71 except:
72 self._abort(error.ResponseError(_("unexpected response:"), d))
72 self._abort(error.ResponseError(_("unexpected response:"), d))
73 return r
73 return r
74
74
75 def pushkey(self, namespace, key, old, new):
75 def pushkey(self, namespace, key, old, new):
76 if not self.capable('pushkey'):
76 if not self.capable('pushkey'):
77 return False
77 return False
78 d = self._call("pushkey",
78 d = self._call("pushkey",
79 namespace=encoding.fromlocal(namespace),
79 namespace=encoding.fromlocal(namespace),
80 key=encoding.fromlocal(key),
80 key=encoding.fromlocal(key),
81 old=encoding.fromlocal(old),
81 old=encoding.fromlocal(old),
82 new=encoding.fromlocal(new))
82 new=encoding.fromlocal(new))
83 try:
83 try:
84 d = bool(int(d))
84 d = bool(int(d))
85 except ValueError:
85 except ValueError:
86 raise error.ResponseError(
86 raise error.ResponseError(
87 _('push failed (unexpected response):'), d)
87 _('push failed (unexpected response):'), d)
88 return d
88 return d
89
89
90 def listkeys(self, namespace):
90 def listkeys(self, namespace):
91 if not self.capable('pushkey'):
91 if not self.capable('pushkey'):
92 return {}
92 return {}
93 d = self._call("listkeys", namespace=encoding.fromlocal(namespace))
93 d = self._call("listkeys", namespace=encoding.fromlocal(namespace))
94 r = {}
94 r = {}
95 for l in d.splitlines():
95 for l in d.splitlines():
96 k, v = l.split('\t')
96 k, v = l.split('\t')
97 r[encoding.tolocal(k)] = encoding.tolocal(v)
97 r[encoding.tolocal(k)] = encoding.tolocal(v)
98 return r
98 return r
99
99
100 def stream_out(self):
100 def stream_out(self):
101 return self._callstream('stream_out')
101 return self._callstream('stream_out')
102
102
103 def changegroup(self, nodes, kind):
103 def changegroup(self, nodes, kind):
104 n = encodelist(nodes)
104 n = encodelist(nodes)
105 f = self._callstream("changegroup", roots=n)
105 f = self._callstream("changegroup", roots=n)
106 return changegroupmod.unbundle10(self._decompress(f), 'UN')
106 return changegroupmod.unbundle10(self._decompress(f), 'UN')
107
107
108 def changegroupsubset(self, bases, heads, kind):
108 def changegroupsubset(self, bases, heads, kind):
109 self.requirecap('changegroupsubset', _('look up remote changes'))
109 self.requirecap('changegroupsubset', _('look up remote changes'))
110 bases = encodelist(bases)
110 bases = encodelist(bases)
111 heads = encodelist(heads)
111 heads = encodelist(heads)
112 f = self._callstream("changegroupsubset",
112 f = self._callstream("changegroupsubset",
113 bases=bases, heads=heads)
113 bases=bases, heads=heads)
114 return changegroupmod.unbundle10(self._decompress(f), 'UN')
114 return changegroupmod.unbundle10(self._decompress(f), 'UN')
115
115
116 def unbundle(self, cg, heads, source):
116 def unbundle(self, cg, heads, source):
117 '''Send cg (a readable file-like object representing the
117 '''Send cg (a readable file-like object representing the
118 changegroup to push, typically a chunkbuffer object) to the
118 changegroup to push, typically a chunkbuffer object) to the
119 remote server as a bundle. Return an integer indicating the
119 remote server as a bundle. Return an integer indicating the
120 result of the push (see localrepository.addchangegroup()).'''
120 result of the push (see localrepository.addchangegroup()).'''
121
121
122 ret, output = self._callpush("unbundle", cg, heads=encodelist(heads))
122 ret, output = self._callpush("unbundle", cg, heads=encodelist(heads))
123 if ret == "":
123 if ret == "":
124 raise error.ResponseError(
124 raise error.ResponseError(
125 _('push failed:'), output)
125 _('push failed:'), output)
126 try:
126 try:
127 ret = int(ret)
127 ret = int(ret)
128 except ValueError:
128 except ValueError:
129 raise error.ResponseError(
129 raise error.ResponseError(
130 _('push failed (unexpected response):'), ret)
130 _('push failed (unexpected response):'), ret)
131
131
132 for l in output.splitlines(True):
132 for l in output.splitlines(True):
133 self.ui.status(_('remote: '), l)
133 self.ui.status(_('remote: '), l)
134 return ret
134 return ret
135
135
136 def debugwireargs(self, one, two, three=None, four=None):
137 # don't pass optional arguments left at their default value
138 opts = {}
139 if three is not None:
140 opts['three'] = three
141 if four is not None:
142 opts['four'] = four
143 return self._call('debugwireargs', one=one, two=two, **opts)
144
136 # server side
145 # server side
137
146
138 class streamres(object):
147 class streamres(object):
139 def __init__(self, gen):
148 def __init__(self, gen):
140 self.gen = gen
149 self.gen = gen
141
150
142 class pushres(object):
151 class pushres(object):
143 def __init__(self, res):
152 def __init__(self, res):
144 self.res = res
153 self.res = res
145
154
146 class pusherr(object):
155 class pusherr(object):
147 def __init__(self, res):
156 def __init__(self, res):
148 self.res = res
157 self.res = res
149
158
150 def dispatch(repo, proto, command):
159 def dispatch(repo, proto, command):
151 func, spec = commands[command]
160 func, spec = commands[command]
152 args = proto.getargs(spec)
161 args = proto.getargs(spec)
153 return func(repo, proto, *args)
162 return func(repo, proto, *args)
154
163
155 def between(repo, proto, pairs):
164 def between(repo, proto, pairs):
156 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
165 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
157 r = []
166 r = []
158 for b in repo.between(pairs):
167 for b in repo.between(pairs):
159 r.append(encodelist(b) + "\n")
168 r.append(encodelist(b) + "\n")
160 return "".join(r)
169 return "".join(r)
161
170
162 def branchmap(repo, proto):
171 def branchmap(repo, proto):
163 branchmap = repo.branchmap()
172 branchmap = repo.branchmap()
164 heads = []
173 heads = []
165 for branch, nodes in branchmap.iteritems():
174 for branch, nodes in branchmap.iteritems():
166 branchname = urllib.quote(encoding.fromlocal(branch))
175 branchname = urllib.quote(encoding.fromlocal(branch))
167 branchnodes = encodelist(nodes)
176 branchnodes = encodelist(nodes)
168 heads.append('%s %s' % (branchname, branchnodes))
177 heads.append('%s %s' % (branchname, branchnodes))
169 return '\n'.join(heads)
178 return '\n'.join(heads)
170
179
171 def branches(repo, proto, nodes):
180 def branches(repo, proto, nodes):
172 nodes = decodelist(nodes)
181 nodes = decodelist(nodes)
173 r = []
182 r = []
174 for b in repo.branches(nodes):
183 for b in repo.branches(nodes):
175 r.append(encodelist(b) + "\n")
184 r.append(encodelist(b) + "\n")
176 return "".join(r)
185 return "".join(r)
177
186
178 def capabilities(repo, proto):
187 def capabilities(repo, proto):
179 caps = 'lookup changegroupsubset branchmap pushkey'.split()
188 caps = 'lookup changegroupsubset branchmap pushkey'.split()
180 if _allowstream(repo.ui):
189 if _allowstream(repo.ui):
181 requiredformats = repo.requirements & repo.supportedformats
190 requiredformats = repo.requirements & repo.supportedformats
182 # if our local revlogs are just revlogv1, add 'stream' cap
191 # if our local revlogs are just revlogv1, add 'stream' cap
183 if not requiredformats - set(('revlogv1',)):
192 if not requiredformats - set(('revlogv1',)):
184 caps.append('stream')
193 caps.append('stream')
185 # otherwise, add 'streamreqs' detailing our local revlog format
194 # otherwise, add 'streamreqs' detailing our local revlog format
186 else:
195 else:
187 caps.append('streamreqs=%s' % ','.join(requiredformats))
196 caps.append('streamreqs=%s' % ','.join(requiredformats))
188 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
197 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
189 return ' '.join(caps)
198 return ' '.join(caps)
190
199
191 def changegroup(repo, proto, roots):
200 def changegroup(repo, proto, roots):
192 nodes = decodelist(roots)
201 nodes = decodelist(roots)
193 cg = repo.changegroup(nodes, 'serve')
202 cg = repo.changegroup(nodes, 'serve')
194 return streamres(proto.groupchunks(cg))
203 return streamres(proto.groupchunks(cg))
195
204
196 def changegroupsubset(repo, proto, bases, heads):
205 def changegroupsubset(repo, proto, bases, heads):
197 bases = decodelist(bases)
206 bases = decodelist(bases)
198 heads = decodelist(heads)
207 heads = decodelist(heads)
199 cg = repo.changegroupsubset(bases, heads, 'serve')
208 cg = repo.changegroupsubset(bases, heads, 'serve')
200 return streamres(proto.groupchunks(cg))
209 return streamres(proto.groupchunks(cg))
201
210
211 def debugwireargs(repo, proto, one, two):
212 return repo.debugwireargs(one, two)
213
202 def heads(repo, proto):
214 def heads(repo, proto):
203 h = repo.heads()
215 h = repo.heads()
204 return encodelist(h) + "\n"
216 return encodelist(h) + "\n"
205
217
206 def hello(repo, proto):
218 def hello(repo, proto):
207 '''the hello command returns a set of lines describing various
219 '''the hello command returns a set of lines describing various
208 interesting things about the server, in an RFC822-like format.
220 interesting things about the server, in an RFC822-like format.
209 Currently the only one defined is "capabilities", which
221 Currently the only one defined is "capabilities", which
210 consists of a line in the form:
222 consists of a line in the form:
211
223
212 capabilities: space separated list of tokens
224 capabilities: space separated list of tokens
213 '''
225 '''
214 return "capabilities: %s\n" % (capabilities(repo, proto))
226 return "capabilities: %s\n" % (capabilities(repo, proto))
215
227
216 def listkeys(repo, proto, namespace):
228 def listkeys(repo, proto, namespace):
217 d = pushkeymod.list(repo, encoding.tolocal(namespace)).items()
229 d = pushkeymod.list(repo, encoding.tolocal(namespace)).items()
218 t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
230 t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
219 for k, v in d])
231 for k, v in d])
220 return t
232 return t
221
233
222 def lookup(repo, proto, key):
234 def lookup(repo, proto, key):
223 try:
235 try:
224 r = hex(repo.lookup(encoding.tolocal(key)))
236 r = hex(repo.lookup(encoding.tolocal(key)))
225 success = 1
237 success = 1
226 except Exception, inst:
238 except Exception, inst:
227 r = str(inst)
239 r = str(inst)
228 success = 0
240 success = 0
229 return "%s %s\n" % (success, r)
241 return "%s %s\n" % (success, r)
230
242
231 def pushkey(repo, proto, namespace, key, old, new):
243 def pushkey(repo, proto, namespace, key, old, new):
232 # compatibility with pre-1.8 clients which were accidentally
244 # compatibility with pre-1.8 clients which were accidentally
233 # sending raw binary nodes rather than utf-8-encoded hex
245 # sending raw binary nodes rather than utf-8-encoded hex
234 if len(new) == 20 and new.encode('string-escape') != new:
246 if len(new) == 20 and new.encode('string-escape') != new:
235 # looks like it could be a binary node
247 # looks like it could be a binary node
236 try:
248 try:
237 u = new.decode('utf-8')
249 u = new.decode('utf-8')
238 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
250 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
239 except UnicodeDecodeError:
251 except UnicodeDecodeError:
240 pass # binary, leave unmodified
252 pass # binary, leave unmodified
241 else:
253 else:
242 new = encoding.tolocal(new) # normal path
254 new = encoding.tolocal(new) # normal path
243
255
244 r = pushkeymod.push(repo,
256 r = pushkeymod.push(repo,
245 encoding.tolocal(namespace), encoding.tolocal(key),
257 encoding.tolocal(namespace), encoding.tolocal(key),
246 encoding.tolocal(old), new)
258 encoding.tolocal(old), new)
247 return '%s\n' % int(r)
259 return '%s\n' % int(r)
248
260
249 def _allowstream(ui):
261 def _allowstream(ui):
250 return ui.configbool('server', 'uncompressed', True, untrusted=True)
262 return ui.configbool('server', 'uncompressed', True, untrusted=True)
251
263
252 def stream(repo, proto):
264 def stream(repo, proto):
253 '''If the server supports streaming clone, it advertises the "stream"
265 '''If the server supports streaming clone, it advertises the "stream"
254 capability with a value representing the version and flags of the repo
266 capability with a value representing the version and flags of the repo
255 it is serving. Client checks to see if it understands the format.
267 it is serving. Client checks to see if it understands the format.
256
268
257 The format is simple: the server writes out a line with the amount
269 The format is simple: the server writes out a line with the amount
258 of files, then the total amount of bytes to be transfered (separated
270 of files, then the total amount of bytes to be transfered (separated
259 by a space). Then, for each file, the server first writes the filename
271 by a space). Then, for each file, the server first writes the filename
260 and filesize (separated by the null character), then the file contents.
272 and filesize (separated by the null character), then the file contents.
261 '''
273 '''
262
274
263 if not _allowstream(repo.ui):
275 if not _allowstream(repo.ui):
264 return '1\n'
276 return '1\n'
265
277
266 entries = []
278 entries = []
267 total_bytes = 0
279 total_bytes = 0
268 try:
280 try:
269 # get consistent snapshot of repo, lock during scan
281 # get consistent snapshot of repo, lock during scan
270 lock = repo.lock()
282 lock = repo.lock()
271 try:
283 try:
272 repo.ui.debug('scanning\n')
284 repo.ui.debug('scanning\n')
273 for name, ename, size in repo.store.walk():
285 for name, ename, size in repo.store.walk():
274 entries.append((name, size))
286 entries.append((name, size))
275 total_bytes += size
287 total_bytes += size
276 finally:
288 finally:
277 lock.release()
289 lock.release()
278 except error.LockError:
290 except error.LockError:
279 return '2\n' # error: 2
291 return '2\n' # error: 2
280
292
281 def streamer(repo, entries, total):
293 def streamer(repo, entries, total):
282 '''stream out all metadata files in repository.'''
294 '''stream out all metadata files in repository.'''
283 yield '0\n' # success
295 yield '0\n' # success
284 repo.ui.debug('%d files, %d bytes to transfer\n' %
296 repo.ui.debug('%d files, %d bytes to transfer\n' %
285 (len(entries), total_bytes))
297 (len(entries), total_bytes))
286 yield '%d %d\n' % (len(entries), total_bytes)
298 yield '%d %d\n' % (len(entries), total_bytes)
287 for name, size in entries:
299 for name, size in entries:
288 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
300 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
289 # partially encode name over the wire for backwards compat
301 # partially encode name over the wire for backwards compat
290 yield '%s\0%d\n' % (store.encodedir(name), size)
302 yield '%s\0%d\n' % (store.encodedir(name), size)
291 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
303 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
292 yield chunk
304 yield chunk
293
305
294 return streamres(streamer(repo, entries, total_bytes))
306 return streamres(streamer(repo, entries, total_bytes))
295
307
296 def unbundle(repo, proto, heads):
308 def unbundle(repo, proto, heads):
297 their_heads = decodelist(heads)
309 their_heads = decodelist(heads)
298
310
299 def check_heads():
311 def check_heads():
300 heads = repo.heads()
312 heads = repo.heads()
301 return their_heads == ['force'] or their_heads == heads
313 return their_heads == ['force'] or their_heads == heads
302
314
303 proto.redirect()
315 proto.redirect()
304
316
305 # fail early if possible
317 # fail early if possible
306 if not check_heads():
318 if not check_heads():
307 return pusherr('unsynced changes')
319 return pusherr('unsynced changes')
308
320
309 # write bundle data to temporary file because it can be big
321 # write bundle data to temporary file because it can be big
310 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
322 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
311 fp = os.fdopen(fd, 'wb+')
323 fp = os.fdopen(fd, 'wb+')
312 r = 0
324 r = 0
313 try:
325 try:
314 proto.getfile(fp)
326 proto.getfile(fp)
315 lock = repo.lock()
327 lock = repo.lock()
316 try:
328 try:
317 if not check_heads():
329 if not check_heads():
318 # someone else committed/pushed/unbundled while we
330 # someone else committed/pushed/unbundled while we
319 # were transferring data
331 # were transferring data
320 return pusherr('unsynced changes')
332 return pusherr('unsynced changes')
321
333
322 # push can proceed
334 # push can proceed
323 fp.seek(0)
335 fp.seek(0)
324 gen = changegroupmod.readbundle(fp, None)
336 gen = changegroupmod.readbundle(fp, None)
325
337
326 try:
338 try:
327 r = repo.addchangegroup(gen, 'serve', proto._client(),
339 r = repo.addchangegroup(gen, 'serve', proto._client(),
328 lock=lock)
340 lock=lock)
329 except util.Abort, inst:
341 except util.Abort, inst:
330 sys.stderr.write("abort: %s\n" % inst)
342 sys.stderr.write("abort: %s\n" % inst)
331 finally:
343 finally:
332 lock.release()
344 lock.release()
333 return pushres(r)
345 return pushres(r)
334
346
335 finally:
347 finally:
336 fp.close()
348 fp.close()
337 os.unlink(tempname)
349 os.unlink(tempname)
338
350
339 commands = {
351 commands = {
340 'between': (between, 'pairs'),
352 'between': (between, 'pairs'),
341 'branchmap': (branchmap, ''),
353 'branchmap': (branchmap, ''),
342 'branches': (branches, 'nodes'),
354 'branches': (branches, 'nodes'),
343 'capabilities': (capabilities, ''),
355 'capabilities': (capabilities, ''),
344 'changegroup': (changegroup, 'roots'),
356 'changegroup': (changegroup, 'roots'),
345 'changegroupsubset': (changegroupsubset, 'bases heads'),
357 'changegroupsubset': (changegroupsubset, 'bases heads'),
358 'debugwireargs': (debugwireargs, 'one two'),
346 'heads': (heads, ''),
359 'heads': (heads, ''),
347 'hello': (hello, ''),
360 'hello': (hello, ''),
348 'listkeys': (listkeys, 'namespace'),
361 'listkeys': (listkeys, 'namespace'),
349 'lookup': (lookup, 'key'),
362 'lookup': (lookup, 'key'),
350 'pushkey': (pushkey, 'namespace key old new'),
363 'pushkey': (pushkey, 'namespace key old new'),
351 'stream_out': (stream, ''),
364 'stream_out': (stream, ''),
352 'unbundle': (unbundle, 'heads'),
365 'unbundle': (unbundle, 'heads'),
353 }
366 }
@@ -1,253 +1,255 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 bookmarks
9 bookmarks
10 branch
10 branch
11 branches
11 branches
12 bundle
12 bundle
13 cat
13 cat
14 clone
14 clone
15 commit
15 commit
16 copy
16 copy
17 diff
17 diff
18 export
18 export
19 forget
19 forget
20 grep
20 grep
21 heads
21 heads
22 help
22 help
23 identify
23 identify
24 import
24 import
25 incoming
25 incoming
26 init
26 init
27 locate
27 locate
28 log
28 log
29 manifest
29 manifest
30 merge
30 merge
31 outgoing
31 outgoing
32 parents
32 parents
33 paths
33 paths
34 pull
34 pull
35 push
35 push
36 recover
36 recover
37 remove
37 remove
38 rename
38 rename
39 resolve
39 resolve
40 revert
40 revert
41 rollback
41 rollback
42 root
42 root
43 serve
43 serve
44 showconfig
44 showconfig
45 status
45 status
46 summary
46 summary
47 tag
47 tag
48 tags
48 tags
49 tip
49 tip
50 unbundle
50 unbundle
51 update
51 update
52 verify
52 verify
53 version
53 version
54
54
55 Show all commands that start with "a"
55 Show all commands that start with "a"
56 $ hg debugcomplete a
56 $ hg debugcomplete a
57 add
57 add
58 addremove
58 addremove
59 annotate
59 annotate
60 archive
60 archive
61
61
62 Do not show debug commands if there are other candidates
62 Do not show debug commands if there are other candidates
63 $ hg debugcomplete d
63 $ hg debugcomplete d
64 diff
64 diff
65
65
66 Show debug commands if there are no other candidates
66 Show debug commands if there are no other candidates
67 $ hg debugcomplete debug
67 $ hg debugcomplete debug
68 debugancestor
68 debugancestor
69 debugbuilddag
69 debugbuilddag
70 debugcheckstate
70 debugcheckstate
71 debugcommands
71 debugcommands
72 debugcomplete
72 debugcomplete
73 debugconfig
73 debugconfig
74 debugdag
74 debugdag
75 debugdata
75 debugdata
76 debugdate
76 debugdate
77 debugfsinfo
77 debugfsinfo
78 debugignore
78 debugignore
79 debugindex
79 debugindex
80 debugindexdot
80 debugindexdot
81 debuginstall
81 debuginstall
82 debugpushkey
82 debugpushkey
83 debugrebuildstate
83 debugrebuildstate
84 debugrename
84 debugrename
85 debugrevspec
85 debugrevspec
86 debugsetparents
86 debugsetparents
87 debugstate
87 debugstate
88 debugsub
88 debugsub
89 debugwalk
89 debugwalk
90 debugwireargs
90
91
91 Do not show the alias of a debug command if there are other candidates
92 Do not show the alias of a debug command if there are other candidates
92 (this should hide rawcommit)
93 (this should hide rawcommit)
93 $ hg debugcomplete r
94 $ hg debugcomplete r
94 recover
95 recover
95 remove
96 remove
96 rename
97 rename
97 resolve
98 resolve
98 revert
99 revert
99 rollback
100 rollback
100 root
101 root
101 Show the alias of a debug command if there are no other candidates
102 Show the alias of a debug command if there are no other candidates
102 $ hg debugcomplete rawc
103 $ hg debugcomplete rawc
103
104
104
105
105 Show the global options
106 Show the global options
106 $ hg debugcomplete --options | sort
107 $ hg debugcomplete --options | sort
107 --config
108 --config
108 --cwd
109 --cwd
109 --debug
110 --debug
110 --debugger
111 --debugger
111 --encoding
112 --encoding
112 --encodingmode
113 --encodingmode
113 --help
114 --help
114 --noninteractive
115 --noninteractive
115 --profile
116 --profile
116 --quiet
117 --quiet
117 --repository
118 --repository
118 --time
119 --time
119 --traceback
120 --traceback
120 --verbose
121 --verbose
121 --version
122 --version
122 -R
123 -R
123 -h
124 -h
124 -q
125 -q
125 -v
126 -v
126 -y
127 -y
127
128
128 Show the options for the "serve" command
129 Show the options for the "serve" command
129 $ hg debugcomplete --options serve | sort
130 $ hg debugcomplete --options serve | sort
130 --accesslog
131 --accesslog
131 --address
132 --address
132 --certificate
133 --certificate
133 --config
134 --config
134 --cwd
135 --cwd
135 --daemon
136 --daemon
136 --daemon-pipefds
137 --daemon-pipefds
137 --debug
138 --debug
138 --debugger
139 --debugger
139 --encoding
140 --encoding
140 --encodingmode
141 --encodingmode
141 --errorlog
142 --errorlog
142 --help
143 --help
143 --ipv6
144 --ipv6
144 --name
145 --name
145 --noninteractive
146 --noninteractive
146 --pid-file
147 --pid-file
147 --port
148 --port
148 --prefix
149 --prefix
149 --profile
150 --profile
150 --quiet
151 --quiet
151 --repository
152 --repository
152 --stdio
153 --stdio
153 --style
154 --style
154 --templates
155 --templates
155 --time
156 --time
156 --traceback
157 --traceback
157 --verbose
158 --verbose
158 --version
159 --version
159 --web-conf
160 --web-conf
160 -6
161 -6
161 -A
162 -A
162 -E
163 -E
163 -R
164 -R
164 -a
165 -a
165 -d
166 -d
166 -h
167 -h
167 -n
168 -n
168 -p
169 -p
169 -q
170 -q
170 -t
171 -t
171 -v
172 -v
172 -y
173 -y
173
174
174 Show an error if we use --options with an ambiguous abbreviation
175 Show an error if we use --options with an ambiguous abbreviation
175 $ hg debugcomplete --options s
176 $ hg debugcomplete --options s
176 hg: command 's' is ambiguous:
177 hg: command 's' is ambiguous:
177 serve showconfig status summary
178 serve showconfig status summary
178 [255]
179 [255]
179
180
180 Show all commands + options
181 Show all commands + options
181 $ hg debugcommands
182 $ hg debugcommands
182 add: include, exclude, subrepos, dry-run
183 add: include, exclude, subrepos, dry-run
183 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
184 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
184 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
185 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
185 commit: addremove, close-branch, include, exclude, message, logfile, date, user
186 commit: addremove, close-branch, include, exclude, message, logfile, date, user
186 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
187 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
187 export: output, switch-parent, rev, text, git, nodates
188 export: output, switch-parent, rev, text, git, nodates
188 forget: include, exclude
189 forget: include, exclude
189 init: ssh, remotecmd, insecure
190 init: ssh, remotecmd, insecure
190 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
191 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
191 merge: force, tool, rev, preview
192 merge: force, tool, rev, preview
192 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
193 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
193 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
194 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
194 remove: after, force, include, exclude
195 remove: after, force, include, exclude
195 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
196 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
196 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
197 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
197 summary: remote
198 summary: remote
198 update: clean, check, date, rev
199 update: clean, check, date, rev
199 addremove: similarity, include, exclude, dry-run
200 addremove: similarity, include, exclude, dry-run
200 archive: no-decode, prefix, rev, type, subrepos, include, exclude
201 archive: no-decode, prefix, rev, type, subrepos, include, exclude
201 backout: merge, parent, tool, rev, include, exclude, message, logfile, date, user
202 backout: merge, parent, tool, rev, include, exclude, message, logfile, date, user
202 bisect: reset, good, bad, skip, extend, command, noupdate
203 bisect: reset, good, bad, skip, extend, command, noupdate
203 bookmarks: force, rev, delete, rename
204 bookmarks: force, rev, delete, rename
204 branch: force, clean
205 branch: force, clean
205 branches: active, closed
206 branches: active, closed
206 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
207 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
207 cat: output, rev, decode, include, exclude
208 cat: output, rev, decode, include, exclude
208 copy: after, force, include, exclude, dry-run
209 copy: after, force, include, exclude, dry-run
209 debugancestor:
210 debugancestor:
210 debugbuilddag: mergeable-file, appended-file, overwritten-file, new-file
211 debugbuilddag: mergeable-file, appended-file, overwritten-file, new-file
211 debugcheckstate:
212 debugcheckstate:
212 debugcommands:
213 debugcommands:
213 debugcomplete: options
214 debugcomplete: options
214 debugdag: tags, branches, dots, spaces
215 debugdag: tags, branches, dots, spaces
215 debugdata:
216 debugdata:
216 debugdate: extended
217 debugdate: extended
217 debugfsinfo:
218 debugfsinfo:
218 debugignore:
219 debugignore:
219 debugindex: format
220 debugindex: format
220 debugindexdot:
221 debugindexdot:
221 debuginstall:
222 debuginstall:
222 debugpushkey:
223 debugpushkey:
223 debugrebuildstate: rev
224 debugrebuildstate: rev
224 debugrename: rev
225 debugrename: rev
225 debugrevspec:
226 debugrevspec:
226 debugsetparents:
227 debugsetparents:
227 debugstate: nodates
228 debugstate: nodates
228 debugsub: rev
229 debugsub: rev
229 debugwalk: include, exclude
230 debugwalk: include, exclude
231 debugwireargs: three, four, ssh, remotecmd, insecure
230 grep: print0, all, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
232 grep: print0, all, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
231 heads: rev, topo, active, closed, style, template
233 heads: rev, topo, active, closed, style, template
232 help:
234 help:
233 identify: rev, num, id, branch, tags, bookmarks
235 identify: rev, num, id, branch, tags, bookmarks
234 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
236 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
235 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
237 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
236 locate: rev, print0, fullpath, include, exclude
238 locate: rev, print0, fullpath, include, exclude
237 manifest: rev
239 manifest: rev
238 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
240 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
239 parents: rev, style, template
241 parents: rev, style, template
240 paths:
242 paths:
241 recover:
243 recover:
242 rename: after, force, include, exclude, dry-run
244 rename: after, force, include, exclude, dry-run
243 resolve: all, list, mark, unmark, tool, no-status, include, exclude
245 resolve: all, list, mark, unmark, tool, no-status, include, exclude
244 revert: all, date, rev, no-backup, include, exclude, dry-run
246 revert: all, date, rev, no-backup, include, exclude, dry-run
245 rollback: dry-run
247 rollback: dry-run
246 root:
248 root:
247 showconfig: untrusted
249 showconfig: untrusted
248 tag: force, local, rev, remove, edit, message, date, user
250 tag: force, local, rev, remove, edit, message, date, user
249 tags:
251 tags:
250 tip: patch, git, style, template
252 tip: patch, git, style, template
251 unbundle: update
253 unbundle: update
252 verify:
254 verify:
253 version:
255 version:
General Comments 0
You need to be logged in to leave comments. Login now