##// END OF EJS Templates
subrepo: more isolation, only use ui for hg.peer when there is no repo...
Simon Heimberg -
r17875:92ba3cd5 stable
parent child Browse files
Show More
@@ -1,5956 +1,5956 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
101 ('G', 'graph', None, _("show the revision DAG")),
102 ] + templateopts
102 ] + templateopts
103
103
104 diffopts = [
104 diffopts = [
105 ('a', 'text', None, _('treat all files as text')),
105 ('a', 'text', None, _('treat all files as text')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
107 ('', 'nodates', None, _('omit dates from diff headers'))
107 ('', 'nodates', None, _('omit dates from diff headers'))
108 ]
108 ]
109
109
110 diffwsopts = [
110 diffwsopts = [
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ]
117 ]
118
118
119 diffopts2 = [
119 diffopts2 = [
120 ('p', 'show-function', None, _('show which function each change is in')),
120 ('p', 'show-function', None, _('show which function each change is in')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ] + diffwsopts + [
122 ] + diffwsopts + [
123 ('U', 'unified', '',
123 ('U', 'unified', '',
124 _('number of lines of context to show'), _('NUM')),
124 _('number of lines of context to show'), _('NUM')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ]
126 ]
127
127
128 mergetoolopts = [
128 mergetoolopts = [
129 ('t', 'tool', '', _('specify merge tool')),
129 ('t', 'tool', '', _('specify merge tool')),
130 ]
130 ]
131
131
132 similarityopts = [
132 similarityopts = [
133 ('s', 'similarity', '',
133 ('s', 'similarity', '',
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 ]
135 ]
136
136
137 subrepoopts = [
137 subrepoopts = [
138 ('S', 'subrepos', None,
138 ('S', 'subrepos', None,
139 _('recurse into subrepositories'))
139 _('recurse into subrepositories'))
140 ]
140 ]
141
141
142 # Commands start here, listed alphabetically
142 # Commands start here, listed alphabetically
143
143
144 @command('^add',
144 @command('^add',
145 walkopts + subrepoopts + dryrunopts,
145 walkopts + subrepoopts + dryrunopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def add(ui, repo, *pats, **opts):
147 def add(ui, repo, *pats, **opts):
148 """add the specified files on the next commit
148 """add the specified files on the next commit
149
149
150 Schedule files to be version controlled and added to the
150 Schedule files to be version controlled and added to the
151 repository.
151 repository.
152
152
153 The files will be added to the repository at the next commit. To
153 The files will be added to the repository at the next commit. To
154 undo an add before that, see :hg:`forget`.
154 undo an add before that, see :hg:`forget`.
155
155
156 If no names are given, add all files to the repository.
156 If no names are given, add all files to the repository.
157
157
158 .. container:: verbose
158 .. container:: verbose
159
159
160 An example showing how new (unknown) files are added
160 An example showing how new (unknown) files are added
161 automatically by :hg:`add`::
161 automatically by :hg:`add`::
162
162
163 $ ls
163 $ ls
164 foo.c
164 foo.c
165 $ hg status
165 $ hg status
166 ? foo.c
166 ? foo.c
167 $ hg add
167 $ hg add
168 adding foo.c
168 adding foo.c
169 $ hg status
169 $ hg status
170 A foo.c
170 A foo.c
171
171
172 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
173 """
173 """
174
174
175 m = scmutil.match(repo[None], pats, opts)
175 m = scmutil.match(repo[None], pats, opts)
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 opts.get('subrepos'), prefix="", explicitonly=False)
177 opts.get('subrepos'), prefix="", explicitonly=False)
178 return rejected and 1 or 0
178 return rejected and 1 or 0
179
179
180 @command('addremove',
180 @command('addremove',
181 similarityopts + walkopts + dryrunopts,
181 similarityopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'))
182 _('[OPTION]... [FILE]...'))
183 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
184 """add all new files, delete all missing files
185
185
186 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
187 repository.
187 repository.
188
188
189 New files are ignored if they match any of the patterns in
189 New files are ignored if they match any of the patterns in
190 ``.hgignore``. As with add, these changes take effect at the next
190 ``.hgignore``. As with add, these changes take effect at the next
191 commit.
191 commit.
192
192
193 Use the -s/--similarity option to detect renamed files. This
193 Use the -s/--similarity option to detect renamed files. This
194 option takes a percentage between 0 (disabled) and 100 (files must
194 option takes a percentage between 0 (disabled) and 100 (files must
195 be identical) as its parameter. With a parameter greater than 0,
195 be identical) as its parameter. With a parameter greater than 0,
196 this compares every removed file with every added file and records
196 this compares every removed file with every added file and records
197 those similar enough as renames. Detecting renamed files this way
197 those similar enough as renames. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed. If
199 used to check which files were identified as moved or renamed. If
200 not specified, -s/--similarity defaults to 100 and only renames of
200 not specified, -s/--similarity defaults to 100 and only renames of
201 identical files are detected.
201 identical files are detected.
202
202
203 Returns 0 if all files are successfully added.
203 Returns 0 if all files are successfully added.
204 """
204 """
205 try:
205 try:
206 sim = float(opts.get('similarity') or 100)
206 sim = float(opts.get('similarity') or 100)
207 except ValueError:
207 except ValueError:
208 raise util.Abort(_('similarity must be a number'))
208 raise util.Abort(_('similarity must be a number'))
209 if sim < 0 or sim > 100:
209 if sim < 0 or sim > 100:
210 raise util.Abort(_('similarity must be between 0 and 100'))
210 raise util.Abort(_('similarity must be between 0 and 100'))
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212
212
213 @command('^annotate|blame',
213 @command('^annotate|blame',
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 ('', 'follow', None,
215 ('', 'follow', None,
216 _('follow copies/renames and list the filename (DEPRECATED)')),
216 _('follow copies/renames and list the filename (DEPRECATED)')),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('a', 'text', None, _('treat all files as text')),
218 ('a', 'text', None, _('treat all files as text')),
219 ('u', 'user', None, _('list the author (long with -v)')),
219 ('u', 'user', None, _('list the author (long with -v)')),
220 ('f', 'file', None, _('list the filename')),
220 ('f', 'file', None, _('list the filename')),
221 ('d', 'date', None, _('list the date (short with -q)')),
221 ('d', 'date', None, _('list the date (short with -q)')),
222 ('n', 'number', None, _('list the revision number (default)')),
222 ('n', 'number', None, _('list the revision number (default)')),
223 ('c', 'changeset', None, _('list the changeset')),
223 ('c', 'changeset', None, _('list the changeset')),
224 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ] + diffwsopts + walkopts,
225 ] + diffwsopts + walkopts,
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 def annotate(ui, repo, *pats, **opts):
227 def annotate(ui, repo, *pats, **opts):
228 """show changeset information by line for each file
228 """show changeset information by line for each file
229
229
230 List changes in files, showing the revision id responsible for
230 List changes in files, showing the revision id responsible for
231 each line
231 each line
232
232
233 This command is useful for discovering when a change was made and
233 This command is useful for discovering when a change was made and
234 by whom.
234 by whom.
235
235
236 Without the -a/--text option, annotate will avoid processing files
236 Without the -a/--text option, annotate will avoid processing files
237 it detects as binary. With -a, annotate will annotate the file
237 it detects as binary. With -a, annotate will annotate the file
238 anyway, although the results will probably be neither useful
238 anyway, although the results will probably be neither useful
239 nor desirable.
239 nor desirable.
240
240
241 Returns 0 on success.
241 Returns 0 on success.
242 """
242 """
243 if opts.get('follow'):
243 if opts.get('follow'):
244 # --follow is deprecated and now just an alias for -f/--file
244 # --follow is deprecated and now just an alias for -f/--file
245 # to mimic the behavior of Mercurial before version 1.5
245 # to mimic the behavior of Mercurial before version 1.5
246 opts['file'] = True
246 opts['file'] = True
247
247
248 datefunc = ui.quiet and util.shortdate or util.datestr
248 datefunc = ui.quiet and util.shortdate or util.datestr
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250
250
251 if not pats:
251 if not pats:
252 raise util.Abort(_('at least one filename or pattern is required'))
252 raise util.Abort(_('at least one filename or pattern is required'))
253
253
254 hexfn = ui.debugflag and hex or short
254 hexfn = ui.debugflag and hex or short
255
255
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 ('number', ' ', lambda x: str(x[0].rev())),
257 ('number', ' ', lambda x: str(x[0].rev())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('date', ' ', getdate),
259 ('date', ' ', getdate),
260 ('file', ' ', lambda x: x[0].path()),
260 ('file', ' ', lambda x: x[0].path()),
261 ('line_number', ':', lambda x: str(x[1])),
261 ('line_number', ':', lambda x: str(x[1])),
262 ]
262 ]
263
263
264 if (not opts.get('user') and not opts.get('changeset')
264 if (not opts.get('user') and not opts.get('changeset')
265 and not opts.get('date') and not opts.get('file')):
265 and not opts.get('date') and not opts.get('file')):
266 opts['number'] = True
266 opts['number'] = True
267
267
268 linenumber = opts.get('line_number') is not None
268 linenumber = opts.get('line_number') is not None
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
271
271
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274
274
275 def bad(x, y):
275 def bad(x, y):
276 raise util.Abort("%s: %s" % (x, y))
276 raise util.Abort("%s: %s" % (x, y))
277
277
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 m = scmutil.match(ctx, pats, opts)
279 m = scmutil.match(ctx, pats, opts)
280 m.bad = bad
280 m.bad = bad
281 follow = not opts.get('no_follow')
281 follow = not opts.get('no_follow')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
283 for abs in ctx.walk(m):
283 for abs in ctx.walk(m):
284 fctx = ctx[abs]
284 fctx = ctx[abs]
285 if not opts.get('text') and util.binary(fctx.data()):
285 if not opts.get('text') and util.binary(fctx.data()):
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 continue
287 continue
288
288
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 diffopts=diffopts)
290 diffopts=diffopts)
291 pieces = []
291 pieces = []
292
292
293 for f, sep in funcmap:
293 for f, sep in funcmap:
294 l = [f(n) for n, dummy in lines]
294 l = [f(n) for n, dummy in lines]
295 if l:
295 if l:
296 sized = [(x, encoding.colwidth(x)) for x in l]
296 sized = [(x, encoding.colwidth(x)) for x in l]
297 ml = max([w for x, w in sized])
297 ml = max([w for x, w in sized])
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 for x, w in sized])
299 for x, w in sized])
300
300
301 if pieces:
301 if pieces:
302 for p, l in zip(zip(*pieces), lines):
302 for p, l in zip(zip(*pieces), lines):
303 ui.write("%s: %s" % ("".join(p), l[1]))
303 ui.write("%s: %s" % ("".join(p), l[1]))
304
304
305 if lines and not lines[-1][1].endswith('\n'):
305 if lines and not lines[-1][1].endswith('\n'):
306 ui.write('\n')
306 ui.write('\n')
307
307
308 @command('archive',
308 @command('archive',
309 [('', 'no-decode', None, _('do not pass files through decoders')),
309 [('', 'no-decode', None, _('do not pass files through decoders')),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 _('PREFIX')),
311 _('PREFIX')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ] + subrepoopts + walkopts,
314 ] + subrepoopts + walkopts,
315 _('[OPTION]... DEST'))
315 _('[OPTION]... DEST'))
316 def archive(ui, repo, dest, **opts):
316 def archive(ui, repo, dest, **opts):
317 '''create an unversioned archive of a repository revision
317 '''create an unversioned archive of a repository revision
318
318
319 By default, the revision used is the parent of the working
319 By default, the revision used is the parent of the working
320 directory; use -r/--rev to specify a different revision.
320 directory; use -r/--rev to specify a different revision.
321
321
322 The archive type is automatically detected based on file
322 The archive type is automatically detected based on file
323 extension (or override using -t/--type).
323 extension (or override using -t/--type).
324
324
325 .. container:: verbose
325 .. container:: verbose
326
326
327 Examples:
327 Examples:
328
328
329 - create a zip file containing the 1.0 release::
329 - create a zip file containing the 1.0 release::
330
330
331 hg archive -r 1.0 project-1.0.zip
331 hg archive -r 1.0 project-1.0.zip
332
332
333 - create a tarball excluding .hg files::
333 - create a tarball excluding .hg files::
334
334
335 hg archive project.tar.gz -X ".hg*"
335 hg archive project.tar.gz -X ".hg*"
336
336
337 Valid types are:
337 Valid types are:
338
338
339 :``files``: a directory full of files (default)
339 :``files``: a directory full of files (default)
340 :``tar``: tar archive, uncompressed
340 :``tar``: tar archive, uncompressed
341 :``tbz2``: tar archive, compressed using bzip2
341 :``tbz2``: tar archive, compressed using bzip2
342 :``tgz``: tar archive, compressed using gzip
342 :``tgz``: tar archive, compressed using gzip
343 :``uzip``: zip archive, uncompressed
343 :``uzip``: zip archive, uncompressed
344 :``zip``: zip archive, compressed using deflate
344 :``zip``: zip archive, compressed using deflate
345
345
346 The exact name of the destination archive or directory is given
346 The exact name of the destination archive or directory is given
347 using a format string; see :hg:`help export` for details.
347 using a format string; see :hg:`help export` for details.
348
348
349 Each member added to an archive file has a directory prefix
349 Each member added to an archive file has a directory prefix
350 prepended. Use -p/--prefix to specify a format string for the
350 prepended. Use -p/--prefix to specify a format string for the
351 prefix. The default is the basename of the archive, with suffixes
351 prefix. The default is the basename of the archive, with suffixes
352 removed.
352 removed.
353
353
354 Returns 0 on success.
354 Returns 0 on success.
355 '''
355 '''
356
356
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 if not ctx:
358 if not ctx:
359 raise util.Abort(_('no working directory: please specify a revision'))
359 raise util.Abort(_('no working directory: please specify a revision'))
360 node = ctx.node()
360 node = ctx.node()
361 dest = cmdutil.makefilename(repo, dest, node)
361 dest = cmdutil.makefilename(repo, dest, node)
362 if os.path.realpath(dest) == repo.root:
362 if os.path.realpath(dest) == repo.root:
363 raise util.Abort(_('repository root cannot be destination'))
363 raise util.Abort(_('repository root cannot be destination'))
364
364
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 prefix = opts.get('prefix')
366 prefix = opts.get('prefix')
367
367
368 if dest == '-':
368 if dest == '-':
369 if kind == 'files':
369 if kind == 'files':
370 raise util.Abort(_('cannot archive plain files to stdout'))
370 raise util.Abort(_('cannot archive plain files to stdout'))
371 dest = cmdutil.makefileobj(repo, dest)
371 dest = cmdutil.makefileobj(repo, dest)
372 if not prefix:
372 if not prefix:
373 prefix = os.path.basename(repo.root) + '-%h'
373 prefix = os.path.basename(repo.root) + '-%h'
374
374
375 prefix = cmdutil.makefilename(repo, prefix, node)
375 prefix = cmdutil.makefilename(repo, prefix, node)
376 matchfn = scmutil.match(ctx, [], opts)
376 matchfn = scmutil.match(ctx, [], opts)
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 matchfn, prefix, subrepos=opts.get('subrepos'))
378 matchfn, prefix, subrepos=opts.get('subrepos'))
379
379
380 @command('backout',
380 @command('backout',
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 ('', 'parent', '',
382 ('', 'parent', '',
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 _('[OPTION]... [-r] REV'))
386 _('[OPTION]... [-r] REV'))
387 def backout(ui, repo, node=None, rev=None, **opts):
387 def backout(ui, repo, node=None, rev=None, **opts):
388 '''reverse effect of earlier changeset
388 '''reverse effect of earlier changeset
389
389
390 Prepare a new changeset with the effect of REV undone in the
390 Prepare a new changeset with the effect of REV undone in the
391 current working directory.
391 current working directory.
392
392
393 If REV is the parent of the working directory, then this new changeset
393 If REV is the parent of the working directory, then this new changeset
394 is committed automatically. Otherwise, hg needs to merge the
394 is committed automatically. Otherwise, hg needs to merge the
395 changes and the merged result is left uncommitted.
395 changes and the merged result is left uncommitted.
396
396
397 .. note::
397 .. note::
398 backout cannot be used to fix either an unwanted or
398 backout cannot be used to fix either an unwanted or
399 incorrect merge.
399 incorrect merge.
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 By default, the pending changeset will have one parent,
403 By default, the pending changeset will have one parent,
404 maintaining a linear history. With --merge, the pending
404 maintaining a linear history. With --merge, the pending
405 changeset will instead have two parents: the old parent of the
405 changeset will instead have two parents: the old parent of the
406 working directory and a new child of REV that simply undoes REV.
406 working directory and a new child of REV that simply undoes REV.
407
407
408 Before version 1.7, the behavior without --merge was equivalent
408 Before version 1.7, the behavior without --merge was equivalent
409 to specifying --merge followed by :hg:`update --clean .` to
409 to specifying --merge followed by :hg:`update --clean .` to
410 cancel the merge and leave the child of REV as a head to be
410 cancel the merge and leave the child of REV as a head to be
411 merged separately.
411 merged separately.
412
412
413 See :hg:`help dates` for a list of formats valid for -d/--date.
413 See :hg:`help dates` for a list of formats valid for -d/--date.
414
414
415 Returns 0 on success.
415 Returns 0 on success.
416 '''
416 '''
417 if rev and node:
417 if rev and node:
418 raise util.Abort(_("please specify just one revision"))
418 raise util.Abort(_("please specify just one revision"))
419
419
420 if not rev:
420 if not rev:
421 rev = node
421 rev = node
422
422
423 if not rev:
423 if not rev:
424 raise util.Abort(_("please specify a revision to backout"))
424 raise util.Abort(_("please specify a revision to backout"))
425
425
426 date = opts.get('date')
426 date = opts.get('date')
427 if date:
427 if date:
428 opts['date'] = util.parsedate(date)
428 opts['date'] = util.parsedate(date)
429
429
430 cmdutil.bailifchanged(repo)
430 cmdutil.bailifchanged(repo)
431 node = scmutil.revsingle(repo, rev).node()
431 node = scmutil.revsingle(repo, rev).node()
432
432
433 op1, op2 = repo.dirstate.parents()
433 op1, op2 = repo.dirstate.parents()
434 a = repo.changelog.ancestor(op1, node)
434 a = repo.changelog.ancestor(op1, node)
435 if a != node:
435 if a != node:
436 raise util.Abort(_('cannot backout change on a different branch'))
436 raise util.Abort(_('cannot backout change on a different branch'))
437
437
438 p1, p2 = repo.changelog.parents(node)
438 p1, p2 = repo.changelog.parents(node)
439 if p1 == nullid:
439 if p1 == nullid:
440 raise util.Abort(_('cannot backout a change with no parents'))
440 raise util.Abort(_('cannot backout a change with no parents'))
441 if p2 != nullid:
441 if p2 != nullid:
442 if not opts.get('parent'):
442 if not opts.get('parent'):
443 raise util.Abort(_('cannot backout a merge changeset'))
443 raise util.Abort(_('cannot backout a merge changeset'))
444 p = repo.lookup(opts['parent'])
444 p = repo.lookup(opts['parent'])
445 if p not in (p1, p2):
445 if p not in (p1, p2):
446 raise util.Abort(_('%s is not a parent of %s') %
446 raise util.Abort(_('%s is not a parent of %s') %
447 (short(p), short(node)))
447 (short(p), short(node)))
448 parent = p
448 parent = p
449 else:
449 else:
450 if opts.get('parent'):
450 if opts.get('parent'):
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 parent = p1
452 parent = p1
453
453
454 # the backout should appear on the same branch
454 # the backout should appear on the same branch
455 wlock = repo.wlock()
455 wlock = repo.wlock()
456 try:
456 try:
457 branch = repo.dirstate.branch()
457 branch = repo.dirstate.branch()
458 hg.clean(repo, node, show_stats=False)
458 hg.clean(repo, node, show_stats=False)
459 repo.dirstate.setbranch(branch)
459 repo.dirstate.setbranch(branch)
460 revert_opts = opts.copy()
460 revert_opts = opts.copy()
461 revert_opts['date'] = None
461 revert_opts['date'] = None
462 revert_opts['all'] = True
462 revert_opts['all'] = True
463 revert_opts['rev'] = hex(parent)
463 revert_opts['rev'] = hex(parent)
464 revert_opts['no_backup'] = None
464 revert_opts['no_backup'] = None
465 revert(ui, repo, **revert_opts)
465 revert(ui, repo, **revert_opts)
466 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
467 try:
467 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
469 return hg.update(repo, op1)
470 finally:
470 finally:
471 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
472
472
473 commit_opts = opts.copy()
473 commit_opts = opts.copy()
474 commit_opts['addremove'] = False
474 commit_opts['addremove'] = False
475 if not commit_opts['message'] and not commit_opts['logfile']:
475 if not commit_opts['message'] and not commit_opts['logfile']:
476 # we don't translate commit messages
476 # we don't translate commit messages
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['force_editor'] = True
478 commit_opts['force_editor'] = True
479 commit(ui, repo, **commit_opts)
479 commit(ui, repo, **commit_opts)
480 def nice(node):
480 def nice(node):
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 ui.status(_('changeset %s backs out changeset %s\n') %
482 ui.status(_('changeset %s backs out changeset %s\n') %
483 (nice(repo.changelog.tip()), nice(node)))
483 (nice(repo.changelog.tip()), nice(node)))
484 if opts.get('merge') and op1 != node:
484 if opts.get('merge') and op1 != node:
485 hg.clean(repo, op1, show_stats=False)
485 hg.clean(repo, op1, show_stats=False)
486 ui.status(_('merging with changeset %s\n')
486 ui.status(_('merging with changeset %s\n')
487 % nice(repo.changelog.tip()))
487 % nice(repo.changelog.tip()))
488 try:
488 try:
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 return hg.merge(repo, hex(repo.changelog.tip()))
490 return hg.merge(repo, hex(repo.changelog.tip()))
491 finally:
491 finally:
492 ui.setconfig('ui', 'forcemerge', '')
492 ui.setconfig('ui', 'forcemerge', '')
493 finally:
493 finally:
494 wlock.release()
494 wlock.release()
495 return 0
495 return 0
496
496
497 @command('bisect',
497 @command('bisect',
498 [('r', 'reset', False, _('reset bisect state')),
498 [('r', 'reset', False, _('reset bisect state')),
499 ('g', 'good', False, _('mark changeset good')),
499 ('g', 'good', False, _('mark changeset good')),
500 ('b', 'bad', False, _('mark changeset bad')),
500 ('b', 'bad', False, _('mark changeset bad')),
501 ('s', 'skip', False, _('skip testing changeset')),
501 ('s', 'skip', False, _('skip testing changeset')),
502 ('e', 'extend', False, _('extend the bisect range')),
502 ('e', 'extend', False, _('extend the bisect range')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('U', 'noupdate', False, _('do not update to target'))],
504 ('U', 'noupdate', False, _('do not update to target'))],
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 def bisect(ui, repo, rev=None, extra=None, command=None,
506 def bisect(ui, repo, rev=None, extra=None, command=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
508 noupdate=None):
508 noupdate=None):
509 """subdivision search of changesets
509 """subdivision search of changesets
510
510
511 This command helps to find changesets which introduce problems. To
511 This command helps to find changesets which introduce problems. To
512 use, mark the earliest changeset you know exhibits the problem as
512 use, mark the earliest changeset you know exhibits the problem as
513 bad, then mark the latest changeset which is free from the problem
513 bad, then mark the latest changeset which is free from the problem
514 as good. Bisect will update your working directory to a revision
514 as good. Bisect will update your working directory to a revision
515 for testing (unless the -U/--noupdate option is specified). Once
515 for testing (unless the -U/--noupdate option is specified). Once
516 you have performed tests, mark the working directory as good or
516 you have performed tests, mark the working directory as good or
517 bad, and bisect will either update to another candidate changeset
517 bad, and bisect will either update to another candidate changeset
518 or announce that it has found the bad revision.
518 or announce that it has found the bad revision.
519
519
520 As a shortcut, you can also use the revision argument to mark a
520 As a shortcut, you can also use the revision argument to mark a
521 revision as good or bad without checking it out first.
521 revision as good or bad without checking it out first.
522
522
523 If you supply a command, it will be used for automatic bisection.
523 If you supply a command, it will be used for automatic bisection.
524 The environment variable HG_NODE will contain the ID of the
524 The environment variable HG_NODE will contain the ID of the
525 changeset being tested. The exit status of the command will be
525 changeset being tested. The exit status of the command will be
526 used to mark revisions as good or bad: status 0 means good, 125
526 used to mark revisions as good or bad: status 0 means good, 125
527 means to skip the revision, 127 (command not found) will abort the
527 means to skip the revision, 127 (command not found) will abort the
528 bisection, and any other non-zero exit status means the revision
528 bisection, and any other non-zero exit status means the revision
529 is bad.
529 is bad.
530
530
531 .. container:: verbose
531 .. container:: verbose
532
532
533 Some examples:
533 Some examples:
534
534
535 - start a bisection with known bad revision 12, and good revision 34::
535 - start a bisection with known bad revision 12, and good revision 34::
536
536
537 hg bisect --bad 34
537 hg bisect --bad 34
538 hg bisect --good 12
538 hg bisect --good 12
539
539
540 - advance the current bisection by marking current revision as good or
540 - advance the current bisection by marking current revision as good or
541 bad::
541 bad::
542
542
543 hg bisect --good
543 hg bisect --good
544 hg bisect --bad
544 hg bisect --bad
545
545
546 - mark the current revision, or a known revision, to be skipped (e.g. if
546 - mark the current revision, or a known revision, to be skipped (e.g. if
547 that revision is not usable because of another issue)::
547 that revision is not usable because of another issue)::
548
548
549 hg bisect --skip
549 hg bisect --skip
550 hg bisect --skip 23
550 hg bisect --skip 23
551
551
552 - forget the current bisection::
552 - forget the current bisection::
553
553
554 hg bisect --reset
554 hg bisect --reset
555
555
556 - use 'make && make tests' to automatically find the first broken
556 - use 'make && make tests' to automatically find the first broken
557 revision::
557 revision::
558
558
559 hg bisect --reset
559 hg bisect --reset
560 hg bisect --bad 34
560 hg bisect --bad 34
561 hg bisect --good 12
561 hg bisect --good 12
562 hg bisect --command 'make && make tests'
562 hg bisect --command 'make && make tests'
563
563
564 - see all changesets whose states are already known in the current
564 - see all changesets whose states are already known in the current
565 bisection::
565 bisection::
566
566
567 hg log -r "bisect(pruned)"
567 hg log -r "bisect(pruned)"
568
568
569 - see the changeset currently being bisected (especially useful
569 - see the changeset currently being bisected (especially useful
570 if running with -U/--noupdate)::
570 if running with -U/--noupdate)::
571
571
572 hg log -r "bisect(current)"
572 hg log -r "bisect(current)"
573
573
574 - see all changesets that took part in the current bisection::
574 - see all changesets that took part in the current bisection::
575
575
576 hg log -r "bisect(range)"
576 hg log -r "bisect(range)"
577
577
578 - with the graphlog extension, you can even get a nice graph::
578 - with the graphlog extension, you can even get a nice graph::
579
579
580 hg log --graph -r "bisect(range)"
580 hg log --graph -r "bisect(range)"
581
581
582 See :hg:`help revsets` for more about the `bisect()` keyword.
582 See :hg:`help revsets` for more about the `bisect()` keyword.
583
583
584 Returns 0 on success.
584 Returns 0 on success.
585 """
585 """
586 def extendbisectrange(nodes, good):
586 def extendbisectrange(nodes, good):
587 # bisect is incomplete when it ends on a merge node and
587 # bisect is incomplete when it ends on a merge node and
588 # one of the parent was not checked.
588 # one of the parent was not checked.
589 parents = repo[nodes[0]].parents()
589 parents = repo[nodes[0]].parents()
590 if len(parents) > 1:
590 if len(parents) > 1:
591 side = good and state['bad'] or state['good']
591 side = good and state['bad'] or state['good']
592 num = len(set(i.node() for i in parents) & set(side))
592 num = len(set(i.node() for i in parents) & set(side))
593 if num == 1:
593 if num == 1:
594 return parents[0].ancestor(parents[1])
594 return parents[0].ancestor(parents[1])
595 return None
595 return None
596
596
597 def print_result(nodes, good):
597 def print_result(nodes, good):
598 displayer = cmdutil.show_changeset(ui, repo, {})
598 displayer = cmdutil.show_changeset(ui, repo, {})
599 if len(nodes) == 1:
599 if len(nodes) == 1:
600 # narrowed it down to a single revision
600 # narrowed it down to a single revision
601 if good:
601 if good:
602 ui.write(_("The first good revision is:\n"))
602 ui.write(_("The first good revision is:\n"))
603 else:
603 else:
604 ui.write(_("The first bad revision is:\n"))
604 ui.write(_("The first bad revision is:\n"))
605 displayer.show(repo[nodes[0]])
605 displayer.show(repo[nodes[0]])
606 extendnode = extendbisectrange(nodes, good)
606 extendnode = extendbisectrange(nodes, good)
607 if extendnode is not None:
607 if extendnode is not None:
608 ui.write(_('Not all ancestors of this changeset have been'
608 ui.write(_('Not all ancestors of this changeset have been'
609 ' checked.\nUse bisect --extend to continue the '
609 ' checked.\nUse bisect --extend to continue the '
610 'bisection from\nthe common ancestor, %s.\n')
610 'bisection from\nthe common ancestor, %s.\n')
611 % extendnode)
611 % extendnode)
612 else:
612 else:
613 # multiple possible revisions
613 # multiple possible revisions
614 if good:
614 if good:
615 ui.write(_("Due to skipped revisions, the first "
615 ui.write(_("Due to skipped revisions, the first "
616 "good revision could be any of:\n"))
616 "good revision could be any of:\n"))
617 else:
617 else:
618 ui.write(_("Due to skipped revisions, the first "
618 ui.write(_("Due to skipped revisions, the first "
619 "bad revision could be any of:\n"))
619 "bad revision could be any of:\n"))
620 for n in nodes:
620 for n in nodes:
621 displayer.show(repo[n])
621 displayer.show(repo[n])
622 displayer.close()
622 displayer.close()
623
623
624 def check_state(state, interactive=True):
624 def check_state(state, interactive=True):
625 if not state['good'] or not state['bad']:
625 if not state['good'] or not state['bad']:
626 if (good or bad or skip or reset) and interactive:
626 if (good or bad or skip or reset) and interactive:
627 return
627 return
628 if not state['good']:
628 if not state['good']:
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
630 else:
630 else:
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
632 return True
632 return True
633
633
634 # backward compatibility
634 # backward compatibility
635 if rev in "good bad reset init".split():
635 if rev in "good bad reset init".split():
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
637 cmd, rev, extra = rev, extra, None
637 cmd, rev, extra = rev, extra, None
638 if cmd == "good":
638 if cmd == "good":
639 good = True
639 good = True
640 elif cmd == "bad":
640 elif cmd == "bad":
641 bad = True
641 bad = True
642 else:
642 else:
643 reset = True
643 reset = True
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
645 raise util.Abort(_('incompatible arguments'))
645 raise util.Abort(_('incompatible arguments'))
646
646
647 if reset:
647 if reset:
648 p = repo.join("bisect.state")
648 p = repo.join("bisect.state")
649 if os.path.exists(p):
649 if os.path.exists(p):
650 os.unlink(p)
650 os.unlink(p)
651 return
651 return
652
652
653 state = hbisect.load_state(repo)
653 state = hbisect.load_state(repo)
654
654
655 if command:
655 if command:
656 changesets = 1
656 changesets = 1
657 try:
657 try:
658 node = state['current'][0]
658 node = state['current'][0]
659 except LookupError:
659 except LookupError:
660 if noupdate:
660 if noupdate:
661 raise util.Abort(_('current bisect revision is unknown - '
661 raise util.Abort(_('current bisect revision is unknown - '
662 'start a new bisect to fix'))
662 'start a new bisect to fix'))
663 node, p2 = repo.dirstate.parents()
663 node, p2 = repo.dirstate.parents()
664 if p2 != nullid:
664 if p2 != nullid:
665 raise util.Abort(_('current bisect revision is a merge'))
665 raise util.Abort(_('current bisect revision is a merge'))
666 try:
666 try:
667 while changesets:
667 while changesets:
668 # update state
668 # update state
669 state['current'] = [node]
669 state['current'] = [node]
670 hbisect.save_state(repo, state)
670 hbisect.save_state(repo, state)
671 status = util.system(command,
671 status = util.system(command,
672 environ={'HG_NODE': hex(node)},
672 environ={'HG_NODE': hex(node)},
673 out=ui.fout)
673 out=ui.fout)
674 if status == 125:
674 if status == 125:
675 transition = "skip"
675 transition = "skip"
676 elif status == 0:
676 elif status == 0:
677 transition = "good"
677 transition = "good"
678 # status < 0 means process was killed
678 # status < 0 means process was killed
679 elif status == 127:
679 elif status == 127:
680 raise util.Abort(_("failed to execute %s") % command)
680 raise util.Abort(_("failed to execute %s") % command)
681 elif status < 0:
681 elif status < 0:
682 raise util.Abort(_("%s killed") % command)
682 raise util.Abort(_("%s killed") % command)
683 else:
683 else:
684 transition = "bad"
684 transition = "bad"
685 ctx = scmutil.revsingle(repo, rev, node)
685 ctx = scmutil.revsingle(repo, rev, node)
686 rev = None # clear for future iterations
686 rev = None # clear for future iterations
687 state[transition].append(ctx.node())
687 state[transition].append(ctx.node())
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
689 check_state(state, interactive=False)
689 check_state(state, interactive=False)
690 # bisect
690 # bisect
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
692 # update to next check
692 # update to next check
693 node = nodes[0]
693 node = nodes[0]
694 if not noupdate:
694 if not noupdate:
695 cmdutil.bailifchanged(repo)
695 cmdutil.bailifchanged(repo)
696 hg.clean(repo, node, show_stats=False)
696 hg.clean(repo, node, show_stats=False)
697 finally:
697 finally:
698 state['current'] = [node]
698 state['current'] = [node]
699 hbisect.save_state(repo, state)
699 hbisect.save_state(repo, state)
700 print_result(nodes, good)
700 print_result(nodes, good)
701 return
701 return
702
702
703 # update state
703 # update state
704
704
705 if rev:
705 if rev:
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
707 else:
707 else:
708 nodes = [repo.lookup('.')]
708 nodes = [repo.lookup('.')]
709
709
710 if good or bad or skip:
710 if good or bad or skip:
711 if good:
711 if good:
712 state['good'] += nodes
712 state['good'] += nodes
713 elif bad:
713 elif bad:
714 state['bad'] += nodes
714 state['bad'] += nodes
715 elif skip:
715 elif skip:
716 state['skip'] += nodes
716 state['skip'] += nodes
717 hbisect.save_state(repo, state)
717 hbisect.save_state(repo, state)
718
718
719 if not check_state(state):
719 if not check_state(state):
720 return
720 return
721
721
722 # actually bisect
722 # actually bisect
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
724 if extend:
724 if extend:
725 if not changesets:
725 if not changesets:
726 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
727 if extendnode is not None:
727 if extendnode is not None:
728 ui.write(_("Extending search to changeset %d:%s\n"
728 ui.write(_("Extending search to changeset %d:%s\n"
729 % (extendnode.rev(), extendnode)))
729 % (extendnode.rev(), extendnode)))
730 state['current'] = [extendnode.node()]
730 state['current'] = [extendnode.node()]
731 hbisect.save_state(repo, state)
731 hbisect.save_state(repo, state)
732 if noupdate:
732 if noupdate:
733 return
733 return
734 cmdutil.bailifchanged(repo)
734 cmdutil.bailifchanged(repo)
735 return hg.clean(repo, extendnode.node())
735 return hg.clean(repo, extendnode.node())
736 raise util.Abort(_("nothing to extend"))
736 raise util.Abort(_("nothing to extend"))
737
737
738 if changesets == 0:
738 if changesets == 0:
739 print_result(nodes, good)
739 print_result(nodes, good)
740 else:
740 else:
741 assert len(nodes) == 1 # only a single node can be tested next
741 assert len(nodes) == 1 # only a single node can be tested next
742 node = nodes[0]
742 node = nodes[0]
743 # compute the approximate number of remaining tests
743 # compute the approximate number of remaining tests
744 tests, size = 0, 2
744 tests, size = 0, 2
745 while size <= changesets:
745 while size <= changesets:
746 tests, size = tests + 1, size * 2
746 tests, size = tests + 1, size * 2
747 rev = repo.changelog.rev(node)
747 rev = repo.changelog.rev(node)
748 ui.write(_("Testing changeset %d:%s "
748 ui.write(_("Testing changeset %d:%s "
749 "(%d changesets remaining, ~%d tests)\n")
749 "(%d changesets remaining, ~%d tests)\n")
750 % (rev, short(node), changesets, tests))
750 % (rev, short(node), changesets, tests))
751 state['current'] = [node]
751 state['current'] = [node]
752 hbisect.save_state(repo, state)
752 hbisect.save_state(repo, state)
753 if not noupdate:
753 if not noupdate:
754 cmdutil.bailifchanged(repo)
754 cmdutil.bailifchanged(repo)
755 return hg.clean(repo, node)
755 return hg.clean(repo, node)
756
756
757 @command('bookmarks',
757 @command('bookmarks',
758 [('f', 'force', False, _('force')),
758 [('f', 'force', False, _('force')),
759 ('r', 'rev', '', _('revision'), _('REV')),
759 ('r', 'rev', '', _('revision'), _('REV')),
760 ('d', 'delete', False, _('delete a given bookmark')),
760 ('d', 'delete', False, _('delete a given bookmark')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
765 rename=None, inactive=False):
765 rename=None, inactive=False):
766 '''track a line of development with movable markers
766 '''track a line of development with movable markers
767
767
768 Bookmarks are pointers to certain commits that move when committing.
768 Bookmarks are pointers to certain commits that move when committing.
769 Bookmarks are local. They can be renamed, copied and deleted. It is
769 Bookmarks are local. They can be renamed, copied and deleted. It is
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
771 :hg:`update NAME` to update to a given bookmark.
771 :hg:`update NAME` to update to a given bookmark.
772
772
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
774 directory's parent revision with the given name. If you specify
774 directory's parent revision with the given name. If you specify
775 a revision using -r REV (where REV may be an existing bookmark),
775 a revision using -r REV (where REV may be an existing bookmark),
776 the bookmark is assigned to that revision.
776 the bookmark is assigned to that revision.
777
777
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
779 push` and :hg:`help pull`). This requires both the local and remote
779 push` and :hg:`help pull`). This requires both the local and remote
780 repositories to support bookmarks. For versions prior to 1.8, this means
780 repositories to support bookmarks. For versions prior to 1.8, this means
781 the bookmarks extension must be enabled.
781 the bookmarks extension must be enabled.
782
782
783 With -i/--inactive, the new bookmark will not be made the active
783 With -i/--inactive, the new bookmark will not be made the active
784 bookmark. If -r/--rev is given, the new bookmark will not be made
784 bookmark. If -r/--rev is given, the new bookmark will not be made
785 active even if -i/--inactive is not given. If no NAME is given, the
785 active even if -i/--inactive is not given. If no NAME is given, the
786 current active bookmark will be marked inactive.
786 current active bookmark will be marked inactive.
787 '''
787 '''
788 hexfn = ui.debugflag and hex or short
788 hexfn = ui.debugflag and hex or short
789 marks = repo._bookmarks
789 marks = repo._bookmarks
790 cur = repo.changectx('.').node()
790 cur = repo.changectx('.').node()
791
791
792 def checkformat(mark):
792 def checkformat(mark):
793 mark = mark.strip()
793 mark = mark.strip()
794 if not mark:
794 if not mark:
795 raise util.Abort(_("bookmark names cannot consist entirely of "
795 raise util.Abort(_("bookmark names cannot consist entirely of "
796 "whitespace"))
796 "whitespace"))
797 scmutil.checknewlabel(repo, mark, 'bookmark')
797 scmutil.checknewlabel(repo, mark, 'bookmark')
798 return mark
798 return mark
799
799
800 def checkconflict(repo, mark, force=False):
800 def checkconflict(repo, mark, force=False):
801 if mark in marks and not force:
801 if mark in marks and not force:
802 raise util.Abort(_("bookmark '%s' already exists "
802 raise util.Abort(_("bookmark '%s' already exists "
803 "(use -f to force)") % mark)
803 "(use -f to force)") % mark)
804 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
804 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
805 and not force):
805 and not force):
806 raise util.Abort(
806 raise util.Abort(
807 _("a bookmark cannot have the name of an existing branch"))
807 _("a bookmark cannot have the name of an existing branch"))
808
808
809 if delete and rename:
809 if delete and rename:
810 raise util.Abort(_("--delete and --rename are incompatible"))
810 raise util.Abort(_("--delete and --rename are incompatible"))
811 if delete and rev:
811 if delete and rev:
812 raise util.Abort(_("--rev is incompatible with --delete"))
812 raise util.Abort(_("--rev is incompatible with --delete"))
813 if rename and rev:
813 if rename and rev:
814 raise util.Abort(_("--rev is incompatible with --rename"))
814 raise util.Abort(_("--rev is incompatible with --rename"))
815 if mark is None and (delete or rev):
815 if mark is None and (delete or rev):
816 raise util.Abort(_("bookmark name required"))
816 raise util.Abort(_("bookmark name required"))
817
817
818 if delete:
818 if delete:
819 if mark not in marks:
819 if mark not in marks:
820 raise util.Abort(_("bookmark '%s' does not exist") % mark)
820 raise util.Abort(_("bookmark '%s' does not exist") % mark)
821 if mark == repo._bookmarkcurrent:
821 if mark == repo._bookmarkcurrent:
822 bookmarks.setcurrent(repo, None)
822 bookmarks.setcurrent(repo, None)
823 del marks[mark]
823 del marks[mark]
824 bookmarks.write(repo)
824 bookmarks.write(repo)
825
825
826 elif rename:
826 elif rename:
827 if mark is None:
827 if mark is None:
828 raise util.Abort(_("new bookmark name required"))
828 raise util.Abort(_("new bookmark name required"))
829 mark = checkformat(mark)
829 mark = checkformat(mark)
830 if rename not in marks:
830 if rename not in marks:
831 raise util.Abort(_("bookmark '%s' does not exist") % rename)
831 raise util.Abort(_("bookmark '%s' does not exist") % rename)
832 checkconflict(repo, mark, force)
832 checkconflict(repo, mark, force)
833 marks[mark] = marks[rename]
833 marks[mark] = marks[rename]
834 if repo._bookmarkcurrent == rename and not inactive:
834 if repo._bookmarkcurrent == rename and not inactive:
835 bookmarks.setcurrent(repo, mark)
835 bookmarks.setcurrent(repo, mark)
836 del marks[rename]
836 del marks[rename]
837 bookmarks.write(repo)
837 bookmarks.write(repo)
838
838
839 elif mark is not None:
839 elif mark is not None:
840 mark = checkformat(mark)
840 mark = checkformat(mark)
841 if inactive and mark == repo._bookmarkcurrent:
841 if inactive and mark == repo._bookmarkcurrent:
842 bookmarks.setcurrent(repo, None)
842 bookmarks.setcurrent(repo, None)
843 return
843 return
844 checkconflict(repo, mark, force)
844 checkconflict(repo, mark, force)
845 if rev:
845 if rev:
846 marks[mark] = scmutil.revsingle(repo, rev).node()
846 marks[mark] = scmutil.revsingle(repo, rev).node()
847 else:
847 else:
848 marks[mark] = cur
848 marks[mark] = cur
849 if not inactive and cur == marks[mark]:
849 if not inactive and cur == marks[mark]:
850 bookmarks.setcurrent(repo, mark)
850 bookmarks.setcurrent(repo, mark)
851 bookmarks.write(repo)
851 bookmarks.write(repo)
852
852
853 # Same message whether trying to deactivate the current bookmark (-i
853 # Same message whether trying to deactivate the current bookmark (-i
854 # with no NAME) or listing bookmarks
854 # with no NAME) or listing bookmarks
855 elif len(marks) == 0:
855 elif len(marks) == 0:
856 ui.status(_("no bookmarks set\n"))
856 ui.status(_("no bookmarks set\n"))
857
857
858 elif inactive:
858 elif inactive:
859 if not repo._bookmarkcurrent:
859 if not repo._bookmarkcurrent:
860 ui.status(_("no active bookmark\n"))
860 ui.status(_("no active bookmark\n"))
861 else:
861 else:
862 bookmarks.setcurrent(repo, None)
862 bookmarks.setcurrent(repo, None)
863
863
864 else: # show bookmarks
864 else: # show bookmarks
865 for bmark, n in sorted(marks.iteritems()):
865 for bmark, n in sorted(marks.iteritems()):
866 current = repo._bookmarkcurrent
866 current = repo._bookmarkcurrent
867 if bmark == current and n == cur:
867 if bmark == current and n == cur:
868 prefix, label = '*', 'bookmarks.current'
868 prefix, label = '*', 'bookmarks.current'
869 else:
869 else:
870 prefix, label = ' ', ''
870 prefix, label = ' ', ''
871
871
872 if ui.quiet:
872 if ui.quiet:
873 ui.write("%s\n" % bmark, label=label)
873 ui.write("%s\n" % bmark, label=label)
874 else:
874 else:
875 ui.write(" %s %-25s %d:%s\n" % (
875 ui.write(" %s %-25s %d:%s\n" % (
876 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
876 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
877 label=label)
877 label=label)
878
878
879 @command('branch',
879 @command('branch',
880 [('f', 'force', None,
880 [('f', 'force', None,
881 _('set branch name even if it shadows an existing branch')),
881 _('set branch name even if it shadows an existing branch')),
882 ('C', 'clean', None, _('reset branch name to parent branch name'))],
882 ('C', 'clean', None, _('reset branch name to parent branch name'))],
883 _('[-fC] [NAME]'))
883 _('[-fC] [NAME]'))
884 def branch(ui, repo, label=None, **opts):
884 def branch(ui, repo, label=None, **opts):
885 """set or show the current branch name
885 """set or show the current branch name
886
886
887 .. note::
887 .. note::
888 Branch names are permanent and global. Use :hg:`bookmark` to create a
888 Branch names are permanent and global. Use :hg:`bookmark` to create a
889 light-weight bookmark instead. See :hg:`help glossary` for more
889 light-weight bookmark instead. See :hg:`help glossary` for more
890 information about named branches and bookmarks.
890 information about named branches and bookmarks.
891
891
892 With no argument, show the current branch name. With one argument,
892 With no argument, show the current branch name. With one argument,
893 set the working directory branch name (the branch will not exist
893 set the working directory branch name (the branch will not exist
894 in the repository until the next commit). Standard practice
894 in the repository until the next commit). Standard practice
895 recommends that primary development take place on the 'default'
895 recommends that primary development take place on the 'default'
896 branch.
896 branch.
897
897
898 Unless -f/--force is specified, branch will not let you set a
898 Unless -f/--force is specified, branch will not let you set a
899 branch name that already exists, even if it's inactive.
899 branch name that already exists, even if it's inactive.
900
900
901 Use -C/--clean to reset the working directory branch to that of
901 Use -C/--clean to reset the working directory branch to that of
902 the parent of the working directory, negating a previous branch
902 the parent of the working directory, negating a previous branch
903 change.
903 change.
904
904
905 Use the command :hg:`update` to switch to an existing branch. Use
905 Use the command :hg:`update` to switch to an existing branch. Use
906 :hg:`commit --close-branch` to mark this branch as closed.
906 :hg:`commit --close-branch` to mark this branch as closed.
907
907
908 Returns 0 on success.
908 Returns 0 on success.
909 """
909 """
910 if not opts.get('clean') and not label:
910 if not opts.get('clean') and not label:
911 ui.write("%s\n" % repo.dirstate.branch())
911 ui.write("%s\n" % repo.dirstate.branch())
912 return
912 return
913
913
914 wlock = repo.wlock()
914 wlock = repo.wlock()
915 try:
915 try:
916 if opts.get('clean'):
916 if opts.get('clean'):
917 label = repo[None].p1().branch()
917 label = repo[None].p1().branch()
918 repo.dirstate.setbranch(label)
918 repo.dirstate.setbranch(label)
919 ui.status(_('reset working directory to branch %s\n') % label)
919 ui.status(_('reset working directory to branch %s\n') % label)
920 elif label:
920 elif label:
921 if not opts.get('force') and label in repo.branchmap():
921 if not opts.get('force') and label in repo.branchmap():
922 if label not in [p.branch() for p in repo.parents()]:
922 if label not in [p.branch() for p in repo.parents()]:
923 raise util.Abort(_('a branch of the same name already'
923 raise util.Abort(_('a branch of the same name already'
924 ' exists'),
924 ' exists'),
925 # i18n: "it" refers to an existing branch
925 # i18n: "it" refers to an existing branch
926 hint=_("use 'hg update' to switch to it"))
926 hint=_("use 'hg update' to switch to it"))
927 repo.dirstate.setbranch(label)
927 repo.dirstate.setbranch(label)
928 ui.status(_('marked working directory as branch %s\n') % label)
928 ui.status(_('marked working directory as branch %s\n') % label)
929 ui.status(_('(branches are permanent and global, '
929 ui.status(_('(branches are permanent and global, '
930 'did you want a bookmark?)\n'))
930 'did you want a bookmark?)\n'))
931 finally:
931 finally:
932 wlock.release()
932 wlock.release()
933
933
934 @command('branches',
934 @command('branches',
935 [('a', 'active', False, _('show only branches that have unmerged heads')),
935 [('a', 'active', False, _('show only branches that have unmerged heads')),
936 ('c', 'closed', False, _('show normal and closed branches'))],
936 ('c', 'closed', False, _('show normal and closed branches'))],
937 _('[-ac]'))
937 _('[-ac]'))
938 def branches(ui, repo, active=False, closed=False):
938 def branches(ui, repo, active=False, closed=False):
939 """list repository named branches
939 """list repository named branches
940
940
941 List the repository's named branches, indicating which ones are
941 List the repository's named branches, indicating which ones are
942 inactive. If -c/--closed is specified, also list branches which have
942 inactive. If -c/--closed is specified, also list branches which have
943 been marked closed (see :hg:`commit --close-branch`).
943 been marked closed (see :hg:`commit --close-branch`).
944
944
945 If -a/--active is specified, only show active branches. A branch
945 If -a/--active is specified, only show active branches. A branch
946 is considered active if it contains repository heads.
946 is considered active if it contains repository heads.
947
947
948 Use the command :hg:`update` to switch to an existing branch.
948 Use the command :hg:`update` to switch to an existing branch.
949
949
950 Returns 0.
950 Returns 0.
951 """
951 """
952
952
953 hexfunc = ui.debugflag and hex or short
953 hexfunc = ui.debugflag and hex or short
954
954
955 activebranches = set([repo[n].branch() for n in repo.heads()])
955 activebranches = set([repo[n].branch() for n in repo.heads()])
956 branches = []
956 branches = []
957 for tag, heads in repo.branchmap().iteritems():
957 for tag, heads in repo.branchmap().iteritems():
958 for h in reversed(heads):
958 for h in reversed(heads):
959 ctx = repo[h]
959 ctx = repo[h]
960 isopen = not ctx.closesbranch()
960 isopen = not ctx.closesbranch()
961 if isopen:
961 if isopen:
962 tip = ctx
962 tip = ctx
963 break
963 break
964 else:
964 else:
965 tip = repo[heads[-1]]
965 tip = repo[heads[-1]]
966 isactive = tag in activebranches and isopen
966 isactive = tag in activebranches and isopen
967 branches.append((tip, isactive, isopen))
967 branches.append((tip, isactive, isopen))
968 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
968 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
969 reverse=True)
969 reverse=True)
970
970
971 for ctx, isactive, isopen in branches:
971 for ctx, isactive, isopen in branches:
972 if (not active) or isactive:
972 if (not active) or isactive:
973 if isactive:
973 if isactive:
974 label = 'branches.active'
974 label = 'branches.active'
975 notice = ''
975 notice = ''
976 elif not isopen:
976 elif not isopen:
977 if not closed:
977 if not closed:
978 continue
978 continue
979 label = 'branches.closed'
979 label = 'branches.closed'
980 notice = _(' (closed)')
980 notice = _(' (closed)')
981 else:
981 else:
982 label = 'branches.inactive'
982 label = 'branches.inactive'
983 notice = _(' (inactive)')
983 notice = _(' (inactive)')
984 if ctx.branch() == repo.dirstate.branch():
984 if ctx.branch() == repo.dirstate.branch():
985 label = 'branches.current'
985 label = 'branches.current'
986 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
986 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
987 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
987 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
988 'log.changeset changeset.%s' % ctx.phasestr())
988 'log.changeset changeset.%s' % ctx.phasestr())
989 tag = ui.label(ctx.branch(), label)
989 tag = ui.label(ctx.branch(), label)
990 if ui.quiet:
990 if ui.quiet:
991 ui.write("%s\n" % tag)
991 ui.write("%s\n" % tag)
992 else:
992 else:
993 ui.write("%s %s%s\n" % (tag, rev, notice))
993 ui.write("%s %s%s\n" % (tag, rev, notice))
994
994
995 @command('bundle',
995 @command('bundle',
996 [('f', 'force', None, _('run even when the destination is unrelated')),
996 [('f', 'force', None, _('run even when the destination is unrelated')),
997 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
997 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
998 _('REV')),
998 _('REV')),
999 ('b', 'branch', [], _('a specific branch you would like to bundle'),
999 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1000 _('BRANCH')),
1000 _('BRANCH')),
1001 ('', 'base', [],
1001 ('', 'base', [],
1002 _('a base changeset assumed to be available at the destination'),
1002 _('a base changeset assumed to be available at the destination'),
1003 _('REV')),
1003 _('REV')),
1004 ('a', 'all', None, _('bundle all changesets in the repository')),
1004 ('a', 'all', None, _('bundle all changesets in the repository')),
1005 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1005 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1006 ] + remoteopts,
1006 ] + remoteopts,
1007 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1007 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1008 def bundle(ui, repo, fname, dest=None, **opts):
1008 def bundle(ui, repo, fname, dest=None, **opts):
1009 """create a changegroup file
1009 """create a changegroup file
1010
1010
1011 Generate a compressed changegroup file collecting changesets not
1011 Generate a compressed changegroup file collecting changesets not
1012 known to be in another repository.
1012 known to be in another repository.
1013
1013
1014 If you omit the destination repository, then hg assumes the
1014 If you omit the destination repository, then hg assumes the
1015 destination will have all the nodes you specify with --base
1015 destination will have all the nodes you specify with --base
1016 parameters. To create a bundle containing all changesets, use
1016 parameters. To create a bundle containing all changesets, use
1017 -a/--all (or --base null).
1017 -a/--all (or --base null).
1018
1018
1019 You can change compression method with the -t/--type option.
1019 You can change compression method with the -t/--type option.
1020 The available compression methods are: none, bzip2, and
1020 The available compression methods are: none, bzip2, and
1021 gzip (by default, bundles are compressed using bzip2).
1021 gzip (by default, bundles are compressed using bzip2).
1022
1022
1023 The bundle file can then be transferred using conventional means
1023 The bundle file can then be transferred using conventional means
1024 and applied to another repository with the unbundle or pull
1024 and applied to another repository with the unbundle or pull
1025 command. This is useful when direct push and pull are not
1025 command. This is useful when direct push and pull are not
1026 available or when exporting an entire repository is undesirable.
1026 available or when exporting an entire repository is undesirable.
1027
1027
1028 Applying bundles preserves all changeset contents including
1028 Applying bundles preserves all changeset contents including
1029 permissions, copy/rename information, and revision history.
1029 permissions, copy/rename information, and revision history.
1030
1030
1031 Returns 0 on success, 1 if no changes found.
1031 Returns 0 on success, 1 if no changes found.
1032 """
1032 """
1033 revs = None
1033 revs = None
1034 if 'rev' in opts:
1034 if 'rev' in opts:
1035 revs = scmutil.revrange(repo, opts['rev'])
1035 revs = scmutil.revrange(repo, opts['rev'])
1036
1036
1037 bundletype = opts.get('type', 'bzip2').lower()
1037 bundletype = opts.get('type', 'bzip2').lower()
1038 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1038 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1039 bundletype = btypes.get(bundletype)
1039 bundletype = btypes.get(bundletype)
1040 if bundletype not in changegroup.bundletypes:
1040 if bundletype not in changegroup.bundletypes:
1041 raise util.Abort(_('unknown bundle type specified with --type'))
1041 raise util.Abort(_('unknown bundle type specified with --type'))
1042
1042
1043 if opts.get('all'):
1043 if opts.get('all'):
1044 base = ['null']
1044 base = ['null']
1045 else:
1045 else:
1046 base = scmutil.revrange(repo, opts.get('base'))
1046 base = scmutil.revrange(repo, opts.get('base'))
1047 if base:
1047 if base:
1048 if dest:
1048 if dest:
1049 raise util.Abort(_("--base is incompatible with specifying "
1049 raise util.Abort(_("--base is incompatible with specifying "
1050 "a destination"))
1050 "a destination"))
1051 common = [repo.lookup(rev) for rev in base]
1051 common = [repo.lookup(rev) for rev in base]
1052 heads = revs and map(repo.lookup, revs) or revs
1052 heads = revs and map(repo.lookup, revs) or revs
1053 cg = repo.getbundle('bundle', heads=heads, common=common)
1053 cg = repo.getbundle('bundle', heads=heads, common=common)
1054 outgoing = None
1054 outgoing = None
1055 else:
1055 else:
1056 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1056 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1057 dest, branches = hg.parseurl(dest, opts.get('branch'))
1057 dest, branches = hg.parseurl(dest, opts.get('branch'))
1058 other = hg.peer(repo, opts, dest)
1058 other = hg.peer(repo, opts, dest)
1059 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1059 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1060 heads = revs and map(repo.lookup, revs) or revs
1060 heads = revs and map(repo.lookup, revs) or revs
1061 outgoing = discovery.findcommonoutgoing(repo, other,
1061 outgoing = discovery.findcommonoutgoing(repo, other,
1062 onlyheads=heads,
1062 onlyheads=heads,
1063 force=opts.get('force'),
1063 force=opts.get('force'),
1064 portable=True)
1064 portable=True)
1065 cg = repo.getlocalbundle('bundle', outgoing)
1065 cg = repo.getlocalbundle('bundle', outgoing)
1066 if not cg:
1066 if not cg:
1067 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1067 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1068 return 1
1068 return 1
1069
1069
1070 changegroup.writebundle(cg, fname, bundletype)
1070 changegroup.writebundle(cg, fname, bundletype)
1071
1071
1072 @command('cat',
1072 @command('cat',
1073 [('o', 'output', '',
1073 [('o', 'output', '',
1074 _('print output to file with formatted name'), _('FORMAT')),
1074 _('print output to file with formatted name'), _('FORMAT')),
1075 ('r', 'rev', '', _('print the given revision'), _('REV')),
1075 ('r', 'rev', '', _('print the given revision'), _('REV')),
1076 ('', 'decode', None, _('apply any matching decode filter')),
1076 ('', 'decode', None, _('apply any matching decode filter')),
1077 ] + walkopts,
1077 ] + walkopts,
1078 _('[OPTION]... FILE...'))
1078 _('[OPTION]... FILE...'))
1079 def cat(ui, repo, file1, *pats, **opts):
1079 def cat(ui, repo, file1, *pats, **opts):
1080 """output the current or given revision of files
1080 """output the current or given revision of files
1081
1081
1082 Print the specified files as they were at the given revision. If
1082 Print the specified files as they were at the given revision. If
1083 no revision is given, the parent of the working directory is used,
1083 no revision is given, the parent of the working directory is used,
1084 or tip if no revision is checked out.
1084 or tip if no revision is checked out.
1085
1085
1086 Output may be to a file, in which case the name of the file is
1086 Output may be to a file, in which case the name of the file is
1087 given using a format string. The formatting rules are the same as
1087 given using a format string. The formatting rules are the same as
1088 for the export command, with the following additions:
1088 for the export command, with the following additions:
1089
1089
1090 :``%s``: basename of file being printed
1090 :``%s``: basename of file being printed
1091 :``%d``: dirname of file being printed, or '.' if in repository root
1091 :``%d``: dirname of file being printed, or '.' if in repository root
1092 :``%p``: root-relative path name of file being printed
1092 :``%p``: root-relative path name of file being printed
1093
1093
1094 Returns 0 on success.
1094 Returns 0 on success.
1095 """
1095 """
1096 ctx = scmutil.revsingle(repo, opts.get('rev'))
1096 ctx = scmutil.revsingle(repo, opts.get('rev'))
1097 err = 1
1097 err = 1
1098 m = scmutil.match(ctx, (file1,) + pats, opts)
1098 m = scmutil.match(ctx, (file1,) + pats, opts)
1099 for abs in ctx.walk(m):
1099 for abs in ctx.walk(m):
1100 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1100 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1101 pathname=abs)
1101 pathname=abs)
1102 data = ctx[abs].data()
1102 data = ctx[abs].data()
1103 if opts.get('decode'):
1103 if opts.get('decode'):
1104 data = repo.wwritedata(abs, data)
1104 data = repo.wwritedata(abs, data)
1105 fp.write(data)
1105 fp.write(data)
1106 fp.close()
1106 fp.close()
1107 err = 0
1107 err = 0
1108 return err
1108 return err
1109
1109
1110 @command('^clone',
1110 @command('^clone',
1111 [('U', 'noupdate', None,
1111 [('U', 'noupdate', None,
1112 _('the clone will include an empty working copy (only a repository)')),
1112 _('the clone will include an empty working copy (only a repository)')),
1113 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1113 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1114 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1114 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1115 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1115 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1116 ('', 'pull', None, _('use pull protocol to copy metadata')),
1116 ('', 'pull', None, _('use pull protocol to copy metadata')),
1117 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1117 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1118 ] + remoteopts,
1118 ] + remoteopts,
1119 _('[OPTION]... SOURCE [DEST]'))
1119 _('[OPTION]... SOURCE [DEST]'))
1120 def clone(ui, source, dest=None, **opts):
1120 def clone(ui, source, dest=None, **opts):
1121 """make a copy of an existing repository
1121 """make a copy of an existing repository
1122
1122
1123 Create a copy of an existing repository in a new directory.
1123 Create a copy of an existing repository in a new directory.
1124
1124
1125 If no destination directory name is specified, it defaults to the
1125 If no destination directory name is specified, it defaults to the
1126 basename of the source.
1126 basename of the source.
1127
1127
1128 The location of the source is added to the new repository's
1128 The location of the source is added to the new repository's
1129 ``.hg/hgrc`` file, as the default to be used for future pulls.
1129 ``.hg/hgrc`` file, as the default to be used for future pulls.
1130
1130
1131 Only local paths and ``ssh://`` URLs are supported as
1131 Only local paths and ``ssh://`` URLs are supported as
1132 destinations. For ``ssh://`` destinations, no working directory or
1132 destinations. For ``ssh://`` destinations, no working directory or
1133 ``.hg/hgrc`` will be created on the remote side.
1133 ``.hg/hgrc`` will be created on the remote side.
1134
1134
1135 To pull only a subset of changesets, specify one or more revisions
1135 To pull only a subset of changesets, specify one or more revisions
1136 identifiers with -r/--rev or branches with -b/--branch. The
1136 identifiers with -r/--rev or branches with -b/--branch. The
1137 resulting clone will contain only the specified changesets and
1137 resulting clone will contain only the specified changesets and
1138 their ancestors. These options (or 'clone src#rev dest') imply
1138 their ancestors. These options (or 'clone src#rev dest') imply
1139 --pull, even for local source repositories. Note that specifying a
1139 --pull, even for local source repositories. Note that specifying a
1140 tag will include the tagged changeset but not the changeset
1140 tag will include the tagged changeset but not the changeset
1141 containing the tag.
1141 containing the tag.
1142
1142
1143 To check out a particular version, use -u/--update, or
1143 To check out a particular version, use -u/--update, or
1144 -U/--noupdate to create a clone with no working directory.
1144 -U/--noupdate to create a clone with no working directory.
1145
1145
1146 .. container:: verbose
1146 .. container:: verbose
1147
1147
1148 For efficiency, hardlinks are used for cloning whenever the
1148 For efficiency, hardlinks are used for cloning whenever the
1149 source and destination are on the same filesystem (note this
1149 source and destination are on the same filesystem (note this
1150 applies only to the repository data, not to the working
1150 applies only to the repository data, not to the working
1151 directory). Some filesystems, such as AFS, implement hardlinking
1151 directory). Some filesystems, such as AFS, implement hardlinking
1152 incorrectly, but do not report errors. In these cases, use the
1152 incorrectly, but do not report errors. In these cases, use the
1153 --pull option to avoid hardlinking.
1153 --pull option to avoid hardlinking.
1154
1154
1155 In some cases, you can clone repositories and the working
1155 In some cases, you can clone repositories and the working
1156 directory using full hardlinks with ::
1156 directory using full hardlinks with ::
1157
1157
1158 $ cp -al REPO REPOCLONE
1158 $ cp -al REPO REPOCLONE
1159
1159
1160 This is the fastest way to clone, but it is not always safe. The
1160 This is the fastest way to clone, but it is not always safe. The
1161 operation is not atomic (making sure REPO is not modified during
1161 operation is not atomic (making sure REPO is not modified during
1162 the operation is up to you) and you have to make sure your
1162 the operation is up to you) and you have to make sure your
1163 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1163 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1164 so). Also, this is not compatible with certain extensions that
1164 so). Also, this is not compatible with certain extensions that
1165 place their metadata under the .hg directory, such as mq.
1165 place their metadata under the .hg directory, such as mq.
1166
1166
1167 Mercurial will update the working directory to the first applicable
1167 Mercurial will update the working directory to the first applicable
1168 revision from this list:
1168 revision from this list:
1169
1169
1170 a) null if -U or the source repository has no changesets
1170 a) null if -U or the source repository has no changesets
1171 b) if -u . and the source repository is local, the first parent of
1171 b) if -u . and the source repository is local, the first parent of
1172 the source repository's working directory
1172 the source repository's working directory
1173 c) the changeset specified with -u (if a branch name, this means the
1173 c) the changeset specified with -u (if a branch name, this means the
1174 latest head of that branch)
1174 latest head of that branch)
1175 d) the changeset specified with -r
1175 d) the changeset specified with -r
1176 e) the tipmost head specified with -b
1176 e) the tipmost head specified with -b
1177 f) the tipmost head specified with the url#branch source syntax
1177 f) the tipmost head specified with the url#branch source syntax
1178 g) the tipmost head of the default branch
1178 g) the tipmost head of the default branch
1179 h) tip
1179 h) tip
1180
1180
1181 Examples:
1181 Examples:
1182
1182
1183 - clone a remote repository to a new directory named hg/::
1183 - clone a remote repository to a new directory named hg/::
1184
1184
1185 hg clone http://selenic.com/hg
1185 hg clone http://selenic.com/hg
1186
1186
1187 - create a lightweight local clone::
1187 - create a lightweight local clone::
1188
1188
1189 hg clone project/ project-feature/
1189 hg clone project/ project-feature/
1190
1190
1191 - clone from an absolute path on an ssh server (note double-slash)::
1191 - clone from an absolute path on an ssh server (note double-slash)::
1192
1192
1193 hg clone ssh://user@server//home/projects/alpha/
1193 hg clone ssh://user@server//home/projects/alpha/
1194
1194
1195 - do a high-speed clone over a LAN while checking out a
1195 - do a high-speed clone over a LAN while checking out a
1196 specified version::
1196 specified version::
1197
1197
1198 hg clone --uncompressed http://server/repo -u 1.5
1198 hg clone --uncompressed http://server/repo -u 1.5
1199
1199
1200 - create a repository without changesets after a particular revision::
1200 - create a repository without changesets after a particular revision::
1201
1201
1202 hg clone -r 04e544 experimental/ good/
1202 hg clone -r 04e544 experimental/ good/
1203
1203
1204 - clone (and track) a particular named branch::
1204 - clone (and track) a particular named branch::
1205
1205
1206 hg clone http://selenic.com/hg#stable
1206 hg clone http://selenic.com/hg#stable
1207
1207
1208 See :hg:`help urls` for details on specifying URLs.
1208 See :hg:`help urls` for details on specifying URLs.
1209
1209
1210 Returns 0 on success.
1210 Returns 0 on success.
1211 """
1211 """
1212 if opts.get('noupdate') and opts.get('updaterev'):
1212 if opts.get('noupdate') and opts.get('updaterev'):
1213 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1213 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1214
1214
1215 r = hg.clone(ui, opts, source, dest,
1215 r = hg.clone(ui, opts, source, dest,
1216 pull=opts.get('pull'),
1216 pull=opts.get('pull'),
1217 stream=opts.get('uncompressed'),
1217 stream=opts.get('uncompressed'),
1218 rev=opts.get('rev'),
1218 rev=opts.get('rev'),
1219 update=opts.get('updaterev') or not opts.get('noupdate'),
1219 update=opts.get('updaterev') or not opts.get('noupdate'),
1220 branch=opts.get('branch'))
1220 branch=opts.get('branch'))
1221
1221
1222 return r is None
1222 return r is None
1223
1223
1224 @command('^commit|ci',
1224 @command('^commit|ci',
1225 [('A', 'addremove', None,
1225 [('A', 'addremove', None,
1226 _('mark new/missing files as added/removed before committing')),
1226 _('mark new/missing files as added/removed before committing')),
1227 ('', 'close-branch', None,
1227 ('', 'close-branch', None,
1228 _('mark a branch as closed, hiding it from the branch list')),
1228 _('mark a branch as closed, hiding it from the branch list')),
1229 ('', 'amend', None, _('amend the parent of the working dir')),
1229 ('', 'amend', None, _('amend the parent of the working dir')),
1230 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1230 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1231 _('[OPTION]... [FILE]...'))
1231 _('[OPTION]... [FILE]...'))
1232 def commit(ui, repo, *pats, **opts):
1232 def commit(ui, repo, *pats, **opts):
1233 """commit the specified files or all outstanding changes
1233 """commit the specified files or all outstanding changes
1234
1234
1235 Commit changes to the given files into the repository. Unlike a
1235 Commit changes to the given files into the repository. Unlike a
1236 centralized SCM, this operation is a local operation. See
1236 centralized SCM, this operation is a local operation. See
1237 :hg:`push` for a way to actively distribute your changes.
1237 :hg:`push` for a way to actively distribute your changes.
1238
1238
1239 If a list of files is omitted, all changes reported by :hg:`status`
1239 If a list of files is omitted, all changes reported by :hg:`status`
1240 will be committed.
1240 will be committed.
1241
1241
1242 If you are committing the result of a merge, do not provide any
1242 If you are committing the result of a merge, do not provide any
1243 filenames or -I/-X filters.
1243 filenames or -I/-X filters.
1244
1244
1245 If no commit message is specified, Mercurial starts your
1245 If no commit message is specified, Mercurial starts your
1246 configured editor where you can enter a message. In case your
1246 configured editor where you can enter a message. In case your
1247 commit fails, you will find a backup of your message in
1247 commit fails, you will find a backup of your message in
1248 ``.hg/last-message.txt``.
1248 ``.hg/last-message.txt``.
1249
1249
1250 The --amend flag can be used to amend the parent of the
1250 The --amend flag can be used to amend the parent of the
1251 working directory with a new commit that contains the changes
1251 working directory with a new commit that contains the changes
1252 in the parent in addition to those currently reported by :hg:`status`,
1252 in the parent in addition to those currently reported by :hg:`status`,
1253 if there are any. The old commit is stored in a backup bundle in
1253 if there are any. The old commit is stored in a backup bundle in
1254 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1254 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1255 on how to restore it).
1255 on how to restore it).
1256
1256
1257 Message, user and date are taken from the amended commit unless
1257 Message, user and date are taken from the amended commit unless
1258 specified. When a message isn't specified on the command line,
1258 specified. When a message isn't specified on the command line,
1259 the editor will open with the message of the amended commit.
1259 the editor will open with the message of the amended commit.
1260
1260
1261 It is not possible to amend public changesets (see :hg:`help phases`)
1261 It is not possible to amend public changesets (see :hg:`help phases`)
1262 or changesets that have children.
1262 or changesets that have children.
1263
1263
1264 See :hg:`help dates` for a list of formats valid for -d/--date.
1264 See :hg:`help dates` for a list of formats valid for -d/--date.
1265
1265
1266 Returns 0 on success, 1 if nothing changed.
1266 Returns 0 on success, 1 if nothing changed.
1267 """
1267 """
1268 if opts.get('subrepos'):
1268 if opts.get('subrepos'):
1269 # Let --subrepos on the command line override config setting.
1269 # Let --subrepos on the command line override config setting.
1270 ui.setconfig('ui', 'commitsubrepos', True)
1270 ui.setconfig('ui', 'commitsubrepos', True)
1271
1271
1272 extra = {}
1272 extra = {}
1273 if opts.get('close_branch'):
1273 if opts.get('close_branch'):
1274 if repo['.'].node() not in repo.branchheads():
1274 if repo['.'].node() not in repo.branchheads():
1275 # The topo heads set is included in the branch heads set of the
1275 # The topo heads set is included in the branch heads set of the
1276 # current branch, so it's sufficient to test branchheads
1276 # current branch, so it's sufficient to test branchheads
1277 raise util.Abort(_('can only close branch heads'))
1277 raise util.Abort(_('can only close branch heads'))
1278 extra['close'] = 1
1278 extra['close'] = 1
1279
1279
1280 branch = repo[None].branch()
1280 branch = repo[None].branch()
1281 bheads = repo.branchheads(branch)
1281 bheads = repo.branchheads(branch)
1282
1282
1283 if opts.get('amend'):
1283 if opts.get('amend'):
1284 if ui.configbool('ui', 'commitsubrepos'):
1284 if ui.configbool('ui', 'commitsubrepos'):
1285 raise util.Abort(_('cannot amend recursively'))
1285 raise util.Abort(_('cannot amend recursively'))
1286
1286
1287 old = repo['.']
1287 old = repo['.']
1288 if old.phase() == phases.public:
1288 if old.phase() == phases.public:
1289 raise util.Abort(_('cannot amend public changesets'))
1289 raise util.Abort(_('cannot amend public changesets'))
1290 if len(old.parents()) > 1:
1290 if len(old.parents()) > 1:
1291 raise util.Abort(_('cannot amend merge changesets'))
1291 raise util.Abort(_('cannot amend merge changesets'))
1292 if len(repo[None].parents()) > 1:
1292 if len(repo[None].parents()) > 1:
1293 raise util.Abort(_('cannot amend while merging'))
1293 raise util.Abort(_('cannot amend while merging'))
1294 if old.children():
1294 if old.children():
1295 raise util.Abort(_('cannot amend changeset with children'))
1295 raise util.Abort(_('cannot amend changeset with children'))
1296
1296
1297 e = cmdutil.commiteditor
1297 e = cmdutil.commiteditor
1298 if opts.get('force_editor'):
1298 if opts.get('force_editor'):
1299 e = cmdutil.commitforceeditor
1299 e = cmdutil.commitforceeditor
1300
1300
1301 def commitfunc(ui, repo, message, match, opts):
1301 def commitfunc(ui, repo, message, match, opts):
1302 editor = e
1302 editor = e
1303 # message contains text from -m or -l, if it's empty,
1303 # message contains text from -m or -l, if it's empty,
1304 # open the editor with the old message
1304 # open the editor with the old message
1305 if not message:
1305 if not message:
1306 message = old.description()
1306 message = old.description()
1307 editor = cmdutil.commitforceeditor
1307 editor = cmdutil.commitforceeditor
1308 return repo.commit(message,
1308 return repo.commit(message,
1309 opts.get('user') or old.user(),
1309 opts.get('user') or old.user(),
1310 opts.get('date') or old.date(),
1310 opts.get('date') or old.date(),
1311 match,
1311 match,
1312 editor=editor,
1312 editor=editor,
1313 extra=extra)
1313 extra=extra)
1314
1314
1315 current = repo._bookmarkcurrent
1315 current = repo._bookmarkcurrent
1316 marks = old.bookmarks()
1316 marks = old.bookmarks()
1317 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1317 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1318 if node == old.node():
1318 if node == old.node():
1319 ui.status(_("nothing changed\n"))
1319 ui.status(_("nothing changed\n"))
1320 return 1
1320 return 1
1321 elif marks:
1321 elif marks:
1322 ui.debug('moving bookmarks %r from %s to %s\n' %
1322 ui.debug('moving bookmarks %r from %s to %s\n' %
1323 (marks, old.hex(), hex(node)))
1323 (marks, old.hex(), hex(node)))
1324 for bm in marks:
1324 for bm in marks:
1325 repo._bookmarks[bm] = node
1325 repo._bookmarks[bm] = node
1326 if bm == current:
1326 if bm == current:
1327 bookmarks.setcurrent(repo, bm)
1327 bookmarks.setcurrent(repo, bm)
1328 bookmarks.write(repo)
1328 bookmarks.write(repo)
1329 else:
1329 else:
1330 e = cmdutil.commiteditor
1330 e = cmdutil.commiteditor
1331 if opts.get('force_editor'):
1331 if opts.get('force_editor'):
1332 e = cmdutil.commitforceeditor
1332 e = cmdutil.commitforceeditor
1333
1333
1334 def commitfunc(ui, repo, message, match, opts):
1334 def commitfunc(ui, repo, message, match, opts):
1335 return repo.commit(message, opts.get('user'), opts.get('date'),
1335 return repo.commit(message, opts.get('user'), opts.get('date'),
1336 match, editor=e, extra=extra)
1336 match, editor=e, extra=extra)
1337
1337
1338 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1338 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1339
1339
1340 if not node:
1340 if not node:
1341 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1341 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1342 if stat[3]:
1342 if stat[3]:
1343 ui.status(_("nothing changed (%d missing files, see "
1343 ui.status(_("nothing changed (%d missing files, see "
1344 "'hg status')\n") % len(stat[3]))
1344 "'hg status')\n") % len(stat[3]))
1345 else:
1345 else:
1346 ui.status(_("nothing changed\n"))
1346 ui.status(_("nothing changed\n"))
1347 return 1
1347 return 1
1348
1348
1349 ctx = repo[node]
1349 ctx = repo[node]
1350 parents = ctx.parents()
1350 parents = ctx.parents()
1351
1351
1352 if (not opts.get('amend') and bheads and node not in bheads and not
1352 if (not opts.get('amend') and bheads and node not in bheads and not
1353 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1353 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1354 ui.status(_('created new head\n'))
1354 ui.status(_('created new head\n'))
1355 # The message is not printed for initial roots. For the other
1355 # The message is not printed for initial roots. For the other
1356 # changesets, it is printed in the following situations:
1356 # changesets, it is printed in the following situations:
1357 #
1357 #
1358 # Par column: for the 2 parents with ...
1358 # Par column: for the 2 parents with ...
1359 # N: null or no parent
1359 # N: null or no parent
1360 # B: parent is on another named branch
1360 # B: parent is on another named branch
1361 # C: parent is a regular non head changeset
1361 # C: parent is a regular non head changeset
1362 # H: parent was a branch head of the current branch
1362 # H: parent was a branch head of the current branch
1363 # Msg column: whether we print "created new head" message
1363 # Msg column: whether we print "created new head" message
1364 # In the following, it is assumed that there already exists some
1364 # In the following, it is assumed that there already exists some
1365 # initial branch heads of the current branch, otherwise nothing is
1365 # initial branch heads of the current branch, otherwise nothing is
1366 # printed anyway.
1366 # printed anyway.
1367 #
1367 #
1368 # Par Msg Comment
1368 # Par Msg Comment
1369 # N N y additional topo root
1369 # N N y additional topo root
1370 #
1370 #
1371 # B N y additional branch root
1371 # B N y additional branch root
1372 # C N y additional topo head
1372 # C N y additional topo head
1373 # H N n usual case
1373 # H N n usual case
1374 #
1374 #
1375 # B B y weird additional branch root
1375 # B B y weird additional branch root
1376 # C B y branch merge
1376 # C B y branch merge
1377 # H B n merge with named branch
1377 # H B n merge with named branch
1378 #
1378 #
1379 # C C y additional head from merge
1379 # C C y additional head from merge
1380 # C H n merge with a head
1380 # C H n merge with a head
1381 #
1381 #
1382 # H H n head merge: head count decreases
1382 # H H n head merge: head count decreases
1383
1383
1384 if not opts.get('close_branch'):
1384 if not opts.get('close_branch'):
1385 for r in parents:
1385 for r in parents:
1386 if r.closesbranch() and r.branch() == branch:
1386 if r.closesbranch() and r.branch() == branch:
1387 ui.status(_('reopening closed branch head %d\n') % r)
1387 ui.status(_('reopening closed branch head %d\n') % r)
1388
1388
1389 if ui.debugflag:
1389 if ui.debugflag:
1390 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1390 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1391 elif ui.verbose:
1391 elif ui.verbose:
1392 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1392 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1393
1393
1394 @command('copy|cp',
1394 @command('copy|cp',
1395 [('A', 'after', None, _('record a copy that has already occurred')),
1395 [('A', 'after', None, _('record a copy that has already occurred')),
1396 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1396 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1397 ] + walkopts + dryrunopts,
1397 ] + walkopts + dryrunopts,
1398 _('[OPTION]... [SOURCE]... DEST'))
1398 _('[OPTION]... [SOURCE]... DEST'))
1399 def copy(ui, repo, *pats, **opts):
1399 def copy(ui, repo, *pats, **opts):
1400 """mark files as copied for the next commit
1400 """mark files as copied for the next commit
1401
1401
1402 Mark dest as having copies of source files. If dest is a
1402 Mark dest as having copies of source files. If dest is a
1403 directory, copies are put in that directory. If dest is a file,
1403 directory, copies are put in that directory. If dest is a file,
1404 the source must be a single file.
1404 the source must be a single file.
1405
1405
1406 By default, this command copies the contents of files as they
1406 By default, this command copies the contents of files as they
1407 exist in the working directory. If invoked with -A/--after, the
1407 exist in the working directory. If invoked with -A/--after, the
1408 operation is recorded, but no copying is performed.
1408 operation is recorded, but no copying is performed.
1409
1409
1410 This command takes effect with the next commit. To undo a copy
1410 This command takes effect with the next commit. To undo a copy
1411 before that, see :hg:`revert`.
1411 before that, see :hg:`revert`.
1412
1412
1413 Returns 0 on success, 1 if errors are encountered.
1413 Returns 0 on success, 1 if errors are encountered.
1414 """
1414 """
1415 wlock = repo.wlock(False)
1415 wlock = repo.wlock(False)
1416 try:
1416 try:
1417 return cmdutil.copy(ui, repo, pats, opts)
1417 return cmdutil.copy(ui, repo, pats, opts)
1418 finally:
1418 finally:
1419 wlock.release()
1419 wlock.release()
1420
1420
1421 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1421 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1422 def debugancestor(ui, repo, *args):
1422 def debugancestor(ui, repo, *args):
1423 """find the ancestor revision of two revisions in a given index"""
1423 """find the ancestor revision of two revisions in a given index"""
1424 if len(args) == 3:
1424 if len(args) == 3:
1425 index, rev1, rev2 = args
1425 index, rev1, rev2 = args
1426 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1426 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1427 lookup = r.lookup
1427 lookup = r.lookup
1428 elif len(args) == 2:
1428 elif len(args) == 2:
1429 if not repo:
1429 if not repo:
1430 raise util.Abort(_("there is no Mercurial repository here "
1430 raise util.Abort(_("there is no Mercurial repository here "
1431 "(.hg not found)"))
1431 "(.hg not found)"))
1432 rev1, rev2 = args
1432 rev1, rev2 = args
1433 r = repo.changelog
1433 r = repo.changelog
1434 lookup = repo.lookup
1434 lookup = repo.lookup
1435 else:
1435 else:
1436 raise util.Abort(_('either two or three arguments required'))
1436 raise util.Abort(_('either two or three arguments required'))
1437 a = r.ancestor(lookup(rev1), lookup(rev2))
1437 a = r.ancestor(lookup(rev1), lookup(rev2))
1438 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1438 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1439
1439
1440 @command('debugbuilddag',
1440 @command('debugbuilddag',
1441 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1441 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1442 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1442 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1443 ('n', 'new-file', None, _('add new file at each rev'))],
1443 ('n', 'new-file', None, _('add new file at each rev'))],
1444 _('[OPTION]... [TEXT]'))
1444 _('[OPTION]... [TEXT]'))
1445 def debugbuilddag(ui, repo, text=None,
1445 def debugbuilddag(ui, repo, text=None,
1446 mergeable_file=False,
1446 mergeable_file=False,
1447 overwritten_file=False,
1447 overwritten_file=False,
1448 new_file=False):
1448 new_file=False):
1449 """builds a repo with a given DAG from scratch in the current empty repo
1449 """builds a repo with a given DAG from scratch in the current empty repo
1450
1450
1451 The description of the DAG is read from stdin if not given on the
1451 The description of the DAG is read from stdin if not given on the
1452 command line.
1452 command line.
1453
1453
1454 Elements:
1454 Elements:
1455
1455
1456 - "+n" is a linear run of n nodes based on the current default parent
1456 - "+n" is a linear run of n nodes based on the current default parent
1457 - "." is a single node based on the current default parent
1457 - "." is a single node based on the current default parent
1458 - "$" resets the default parent to null (implied at the start);
1458 - "$" resets the default parent to null (implied at the start);
1459 otherwise the default parent is always the last node created
1459 otherwise the default parent is always the last node created
1460 - "<p" sets the default parent to the backref p
1460 - "<p" sets the default parent to the backref p
1461 - "*p" is a fork at parent p, which is a backref
1461 - "*p" is a fork at parent p, which is a backref
1462 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1462 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1463 - "/p2" is a merge of the preceding node and p2
1463 - "/p2" is a merge of the preceding node and p2
1464 - ":tag" defines a local tag for the preceding node
1464 - ":tag" defines a local tag for the preceding node
1465 - "@branch" sets the named branch for subsequent nodes
1465 - "@branch" sets the named branch for subsequent nodes
1466 - "#...\\n" is a comment up to the end of the line
1466 - "#...\\n" is a comment up to the end of the line
1467
1467
1468 Whitespace between the above elements is ignored.
1468 Whitespace between the above elements is ignored.
1469
1469
1470 A backref is either
1470 A backref is either
1471
1471
1472 - a number n, which references the node curr-n, where curr is the current
1472 - a number n, which references the node curr-n, where curr is the current
1473 node, or
1473 node, or
1474 - the name of a local tag you placed earlier using ":tag", or
1474 - the name of a local tag you placed earlier using ":tag", or
1475 - empty to denote the default parent.
1475 - empty to denote the default parent.
1476
1476
1477 All string valued-elements are either strictly alphanumeric, or must
1477 All string valued-elements are either strictly alphanumeric, or must
1478 be enclosed in double quotes ("..."), with "\\" as escape character.
1478 be enclosed in double quotes ("..."), with "\\" as escape character.
1479 """
1479 """
1480
1480
1481 if text is None:
1481 if text is None:
1482 ui.status(_("reading DAG from stdin\n"))
1482 ui.status(_("reading DAG from stdin\n"))
1483 text = ui.fin.read()
1483 text = ui.fin.read()
1484
1484
1485 cl = repo.changelog
1485 cl = repo.changelog
1486 if len(cl) > 0:
1486 if len(cl) > 0:
1487 raise util.Abort(_('repository is not empty'))
1487 raise util.Abort(_('repository is not empty'))
1488
1488
1489 # determine number of revs in DAG
1489 # determine number of revs in DAG
1490 total = 0
1490 total = 0
1491 for type, data in dagparser.parsedag(text):
1491 for type, data in dagparser.parsedag(text):
1492 if type == 'n':
1492 if type == 'n':
1493 total += 1
1493 total += 1
1494
1494
1495 if mergeable_file:
1495 if mergeable_file:
1496 linesperrev = 2
1496 linesperrev = 2
1497 # make a file with k lines per rev
1497 # make a file with k lines per rev
1498 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1498 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1499 initialmergedlines.append("")
1499 initialmergedlines.append("")
1500
1500
1501 tags = []
1501 tags = []
1502
1502
1503 lock = tr = None
1503 lock = tr = None
1504 try:
1504 try:
1505 lock = repo.lock()
1505 lock = repo.lock()
1506 tr = repo.transaction("builddag")
1506 tr = repo.transaction("builddag")
1507
1507
1508 at = -1
1508 at = -1
1509 atbranch = 'default'
1509 atbranch = 'default'
1510 nodeids = []
1510 nodeids = []
1511 id = 0
1511 id = 0
1512 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1512 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1513 for type, data in dagparser.parsedag(text):
1513 for type, data in dagparser.parsedag(text):
1514 if type == 'n':
1514 if type == 'n':
1515 ui.note('node %s\n' % str(data))
1515 ui.note('node %s\n' % str(data))
1516 id, ps = data
1516 id, ps = data
1517
1517
1518 files = []
1518 files = []
1519 fctxs = {}
1519 fctxs = {}
1520
1520
1521 p2 = None
1521 p2 = None
1522 if mergeable_file:
1522 if mergeable_file:
1523 fn = "mf"
1523 fn = "mf"
1524 p1 = repo[ps[0]]
1524 p1 = repo[ps[0]]
1525 if len(ps) > 1:
1525 if len(ps) > 1:
1526 p2 = repo[ps[1]]
1526 p2 = repo[ps[1]]
1527 pa = p1.ancestor(p2)
1527 pa = p1.ancestor(p2)
1528 base, local, other = [x[fn].data() for x in pa, p1, p2]
1528 base, local, other = [x[fn].data() for x in pa, p1, p2]
1529 m3 = simplemerge.Merge3Text(base, local, other)
1529 m3 = simplemerge.Merge3Text(base, local, other)
1530 ml = [l.strip() for l in m3.merge_lines()]
1530 ml = [l.strip() for l in m3.merge_lines()]
1531 ml.append("")
1531 ml.append("")
1532 elif at > 0:
1532 elif at > 0:
1533 ml = p1[fn].data().split("\n")
1533 ml = p1[fn].data().split("\n")
1534 else:
1534 else:
1535 ml = initialmergedlines
1535 ml = initialmergedlines
1536 ml[id * linesperrev] += " r%i" % id
1536 ml[id * linesperrev] += " r%i" % id
1537 mergedtext = "\n".join(ml)
1537 mergedtext = "\n".join(ml)
1538 files.append(fn)
1538 files.append(fn)
1539 fctxs[fn] = context.memfilectx(fn, mergedtext)
1539 fctxs[fn] = context.memfilectx(fn, mergedtext)
1540
1540
1541 if overwritten_file:
1541 if overwritten_file:
1542 fn = "of"
1542 fn = "of"
1543 files.append(fn)
1543 files.append(fn)
1544 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1544 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1545
1545
1546 if new_file:
1546 if new_file:
1547 fn = "nf%i" % id
1547 fn = "nf%i" % id
1548 files.append(fn)
1548 files.append(fn)
1549 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1549 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1550 if len(ps) > 1:
1550 if len(ps) > 1:
1551 if not p2:
1551 if not p2:
1552 p2 = repo[ps[1]]
1552 p2 = repo[ps[1]]
1553 for fn in p2:
1553 for fn in p2:
1554 if fn.startswith("nf"):
1554 if fn.startswith("nf"):
1555 files.append(fn)
1555 files.append(fn)
1556 fctxs[fn] = p2[fn]
1556 fctxs[fn] = p2[fn]
1557
1557
1558 def fctxfn(repo, cx, path):
1558 def fctxfn(repo, cx, path):
1559 return fctxs.get(path)
1559 return fctxs.get(path)
1560
1560
1561 if len(ps) == 0 or ps[0] < 0:
1561 if len(ps) == 0 or ps[0] < 0:
1562 pars = [None, None]
1562 pars = [None, None]
1563 elif len(ps) == 1:
1563 elif len(ps) == 1:
1564 pars = [nodeids[ps[0]], None]
1564 pars = [nodeids[ps[0]], None]
1565 else:
1565 else:
1566 pars = [nodeids[p] for p in ps]
1566 pars = [nodeids[p] for p in ps]
1567 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1567 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1568 date=(id, 0),
1568 date=(id, 0),
1569 user="debugbuilddag",
1569 user="debugbuilddag",
1570 extra={'branch': atbranch})
1570 extra={'branch': atbranch})
1571 nodeid = repo.commitctx(cx)
1571 nodeid = repo.commitctx(cx)
1572 nodeids.append(nodeid)
1572 nodeids.append(nodeid)
1573 at = id
1573 at = id
1574 elif type == 'l':
1574 elif type == 'l':
1575 id, name = data
1575 id, name = data
1576 ui.note('tag %s\n' % name)
1576 ui.note('tag %s\n' % name)
1577 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1577 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1578 elif type == 'a':
1578 elif type == 'a':
1579 ui.note('branch %s\n' % data)
1579 ui.note('branch %s\n' % data)
1580 atbranch = data
1580 atbranch = data
1581 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1581 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1582 tr.close()
1582 tr.close()
1583
1583
1584 if tags:
1584 if tags:
1585 repo.opener.write("localtags", "".join(tags))
1585 repo.opener.write("localtags", "".join(tags))
1586 finally:
1586 finally:
1587 ui.progress(_('building'), None)
1587 ui.progress(_('building'), None)
1588 release(tr, lock)
1588 release(tr, lock)
1589
1589
1590 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1590 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1591 def debugbundle(ui, bundlepath, all=None, **opts):
1591 def debugbundle(ui, bundlepath, all=None, **opts):
1592 """lists the contents of a bundle"""
1592 """lists the contents of a bundle"""
1593 f = url.open(ui, bundlepath)
1593 f = url.open(ui, bundlepath)
1594 try:
1594 try:
1595 gen = changegroup.readbundle(f, bundlepath)
1595 gen = changegroup.readbundle(f, bundlepath)
1596 if all:
1596 if all:
1597 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1597 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1598
1598
1599 def showchunks(named):
1599 def showchunks(named):
1600 ui.write("\n%s\n" % named)
1600 ui.write("\n%s\n" % named)
1601 chain = None
1601 chain = None
1602 while True:
1602 while True:
1603 chunkdata = gen.deltachunk(chain)
1603 chunkdata = gen.deltachunk(chain)
1604 if not chunkdata:
1604 if not chunkdata:
1605 break
1605 break
1606 node = chunkdata['node']
1606 node = chunkdata['node']
1607 p1 = chunkdata['p1']
1607 p1 = chunkdata['p1']
1608 p2 = chunkdata['p2']
1608 p2 = chunkdata['p2']
1609 cs = chunkdata['cs']
1609 cs = chunkdata['cs']
1610 deltabase = chunkdata['deltabase']
1610 deltabase = chunkdata['deltabase']
1611 delta = chunkdata['delta']
1611 delta = chunkdata['delta']
1612 ui.write("%s %s %s %s %s %s\n" %
1612 ui.write("%s %s %s %s %s %s\n" %
1613 (hex(node), hex(p1), hex(p2),
1613 (hex(node), hex(p1), hex(p2),
1614 hex(cs), hex(deltabase), len(delta)))
1614 hex(cs), hex(deltabase), len(delta)))
1615 chain = node
1615 chain = node
1616
1616
1617 chunkdata = gen.changelogheader()
1617 chunkdata = gen.changelogheader()
1618 showchunks("changelog")
1618 showchunks("changelog")
1619 chunkdata = gen.manifestheader()
1619 chunkdata = gen.manifestheader()
1620 showchunks("manifest")
1620 showchunks("manifest")
1621 while True:
1621 while True:
1622 chunkdata = gen.filelogheader()
1622 chunkdata = gen.filelogheader()
1623 if not chunkdata:
1623 if not chunkdata:
1624 break
1624 break
1625 fname = chunkdata['filename']
1625 fname = chunkdata['filename']
1626 showchunks(fname)
1626 showchunks(fname)
1627 else:
1627 else:
1628 chunkdata = gen.changelogheader()
1628 chunkdata = gen.changelogheader()
1629 chain = None
1629 chain = None
1630 while True:
1630 while True:
1631 chunkdata = gen.deltachunk(chain)
1631 chunkdata = gen.deltachunk(chain)
1632 if not chunkdata:
1632 if not chunkdata:
1633 break
1633 break
1634 node = chunkdata['node']
1634 node = chunkdata['node']
1635 ui.write("%s\n" % hex(node))
1635 ui.write("%s\n" % hex(node))
1636 chain = node
1636 chain = node
1637 finally:
1637 finally:
1638 f.close()
1638 f.close()
1639
1639
1640 @command('debugcheckstate', [], '')
1640 @command('debugcheckstate', [], '')
1641 def debugcheckstate(ui, repo):
1641 def debugcheckstate(ui, repo):
1642 """validate the correctness of the current dirstate"""
1642 """validate the correctness of the current dirstate"""
1643 parent1, parent2 = repo.dirstate.parents()
1643 parent1, parent2 = repo.dirstate.parents()
1644 m1 = repo[parent1].manifest()
1644 m1 = repo[parent1].manifest()
1645 m2 = repo[parent2].manifest()
1645 m2 = repo[parent2].manifest()
1646 errors = 0
1646 errors = 0
1647 for f in repo.dirstate:
1647 for f in repo.dirstate:
1648 state = repo.dirstate[f]
1648 state = repo.dirstate[f]
1649 if state in "nr" and f not in m1:
1649 if state in "nr" and f not in m1:
1650 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1650 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1651 errors += 1
1651 errors += 1
1652 if state in "a" and f in m1:
1652 if state in "a" and f in m1:
1653 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1653 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1654 errors += 1
1654 errors += 1
1655 if state in "m" and f not in m1 and f not in m2:
1655 if state in "m" and f not in m1 and f not in m2:
1656 ui.warn(_("%s in state %s, but not in either manifest\n") %
1656 ui.warn(_("%s in state %s, but not in either manifest\n") %
1657 (f, state))
1657 (f, state))
1658 errors += 1
1658 errors += 1
1659 for f in m1:
1659 for f in m1:
1660 state = repo.dirstate[f]
1660 state = repo.dirstate[f]
1661 if state not in "nrm":
1661 if state not in "nrm":
1662 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1662 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1663 errors += 1
1663 errors += 1
1664 if errors:
1664 if errors:
1665 error = _(".hg/dirstate inconsistent with current parent's manifest")
1665 error = _(".hg/dirstate inconsistent with current parent's manifest")
1666 raise util.Abort(error)
1666 raise util.Abort(error)
1667
1667
1668 @command('debugcommands', [], _('[COMMAND]'))
1668 @command('debugcommands', [], _('[COMMAND]'))
1669 def debugcommands(ui, cmd='', *args):
1669 def debugcommands(ui, cmd='', *args):
1670 """list all available commands and options"""
1670 """list all available commands and options"""
1671 for cmd, vals in sorted(table.iteritems()):
1671 for cmd, vals in sorted(table.iteritems()):
1672 cmd = cmd.split('|')[0].strip('^')
1672 cmd = cmd.split('|')[0].strip('^')
1673 opts = ', '.join([i[1] for i in vals[1]])
1673 opts = ', '.join([i[1] for i in vals[1]])
1674 ui.write('%s: %s\n' % (cmd, opts))
1674 ui.write('%s: %s\n' % (cmd, opts))
1675
1675
1676 @command('debugcomplete',
1676 @command('debugcomplete',
1677 [('o', 'options', None, _('show the command options'))],
1677 [('o', 'options', None, _('show the command options'))],
1678 _('[-o] CMD'))
1678 _('[-o] CMD'))
1679 def debugcomplete(ui, cmd='', **opts):
1679 def debugcomplete(ui, cmd='', **opts):
1680 """returns the completion list associated with the given command"""
1680 """returns the completion list associated with the given command"""
1681
1681
1682 if opts.get('options'):
1682 if opts.get('options'):
1683 options = []
1683 options = []
1684 otables = [globalopts]
1684 otables = [globalopts]
1685 if cmd:
1685 if cmd:
1686 aliases, entry = cmdutil.findcmd(cmd, table, False)
1686 aliases, entry = cmdutil.findcmd(cmd, table, False)
1687 otables.append(entry[1])
1687 otables.append(entry[1])
1688 for t in otables:
1688 for t in otables:
1689 for o in t:
1689 for o in t:
1690 if "(DEPRECATED)" in o[3]:
1690 if "(DEPRECATED)" in o[3]:
1691 continue
1691 continue
1692 if o[0]:
1692 if o[0]:
1693 options.append('-%s' % o[0])
1693 options.append('-%s' % o[0])
1694 options.append('--%s' % o[1])
1694 options.append('--%s' % o[1])
1695 ui.write("%s\n" % "\n".join(options))
1695 ui.write("%s\n" % "\n".join(options))
1696 return
1696 return
1697
1697
1698 cmdlist = cmdutil.findpossible(cmd, table)
1698 cmdlist = cmdutil.findpossible(cmd, table)
1699 if ui.verbose:
1699 if ui.verbose:
1700 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1700 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1701 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1701 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1702
1702
1703 @command('debugdag',
1703 @command('debugdag',
1704 [('t', 'tags', None, _('use tags as labels')),
1704 [('t', 'tags', None, _('use tags as labels')),
1705 ('b', 'branches', None, _('annotate with branch names')),
1705 ('b', 'branches', None, _('annotate with branch names')),
1706 ('', 'dots', None, _('use dots for runs')),
1706 ('', 'dots', None, _('use dots for runs')),
1707 ('s', 'spaces', None, _('separate elements by spaces'))],
1707 ('s', 'spaces', None, _('separate elements by spaces'))],
1708 _('[OPTION]... [FILE [REV]...]'))
1708 _('[OPTION]... [FILE [REV]...]'))
1709 def debugdag(ui, repo, file_=None, *revs, **opts):
1709 def debugdag(ui, repo, file_=None, *revs, **opts):
1710 """format the changelog or an index DAG as a concise textual description
1710 """format the changelog or an index DAG as a concise textual description
1711
1711
1712 If you pass a revlog index, the revlog's DAG is emitted. If you list
1712 If you pass a revlog index, the revlog's DAG is emitted. If you list
1713 revision numbers, they get labeled in the output as rN.
1713 revision numbers, they get labeled in the output as rN.
1714
1714
1715 Otherwise, the changelog DAG of the current repo is emitted.
1715 Otherwise, the changelog DAG of the current repo is emitted.
1716 """
1716 """
1717 spaces = opts.get('spaces')
1717 spaces = opts.get('spaces')
1718 dots = opts.get('dots')
1718 dots = opts.get('dots')
1719 if file_:
1719 if file_:
1720 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1720 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1721 revs = set((int(r) for r in revs))
1721 revs = set((int(r) for r in revs))
1722 def events():
1722 def events():
1723 for r in rlog:
1723 for r in rlog:
1724 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1724 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1725 if p != -1)))
1725 if p != -1)))
1726 if r in revs:
1726 if r in revs:
1727 yield 'l', (r, "r%i" % r)
1727 yield 'l', (r, "r%i" % r)
1728 elif repo:
1728 elif repo:
1729 cl = repo.changelog
1729 cl = repo.changelog
1730 tags = opts.get('tags')
1730 tags = opts.get('tags')
1731 branches = opts.get('branches')
1731 branches = opts.get('branches')
1732 if tags:
1732 if tags:
1733 labels = {}
1733 labels = {}
1734 for l, n in repo.tags().items():
1734 for l, n in repo.tags().items():
1735 labels.setdefault(cl.rev(n), []).append(l)
1735 labels.setdefault(cl.rev(n), []).append(l)
1736 def events():
1736 def events():
1737 b = "default"
1737 b = "default"
1738 for r in cl:
1738 for r in cl:
1739 if branches:
1739 if branches:
1740 newb = cl.read(cl.node(r))[5]['branch']
1740 newb = cl.read(cl.node(r))[5]['branch']
1741 if newb != b:
1741 if newb != b:
1742 yield 'a', newb
1742 yield 'a', newb
1743 b = newb
1743 b = newb
1744 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1744 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1745 if p != -1)))
1745 if p != -1)))
1746 if tags:
1746 if tags:
1747 ls = labels.get(r)
1747 ls = labels.get(r)
1748 if ls:
1748 if ls:
1749 for l in ls:
1749 for l in ls:
1750 yield 'l', (r, l)
1750 yield 'l', (r, l)
1751 else:
1751 else:
1752 raise util.Abort(_('need repo for changelog dag'))
1752 raise util.Abort(_('need repo for changelog dag'))
1753
1753
1754 for line in dagparser.dagtextlines(events(),
1754 for line in dagparser.dagtextlines(events(),
1755 addspaces=spaces,
1755 addspaces=spaces,
1756 wraplabels=True,
1756 wraplabels=True,
1757 wrapannotations=True,
1757 wrapannotations=True,
1758 wrapnonlinear=dots,
1758 wrapnonlinear=dots,
1759 usedots=dots,
1759 usedots=dots,
1760 maxlinewidth=70):
1760 maxlinewidth=70):
1761 ui.write(line)
1761 ui.write(line)
1762 ui.write("\n")
1762 ui.write("\n")
1763
1763
1764 @command('debugdata',
1764 @command('debugdata',
1765 [('c', 'changelog', False, _('open changelog')),
1765 [('c', 'changelog', False, _('open changelog')),
1766 ('m', 'manifest', False, _('open manifest'))],
1766 ('m', 'manifest', False, _('open manifest'))],
1767 _('-c|-m|FILE REV'))
1767 _('-c|-m|FILE REV'))
1768 def debugdata(ui, repo, file_, rev = None, **opts):
1768 def debugdata(ui, repo, file_, rev = None, **opts):
1769 """dump the contents of a data file revision"""
1769 """dump the contents of a data file revision"""
1770 if opts.get('changelog') or opts.get('manifest'):
1770 if opts.get('changelog') or opts.get('manifest'):
1771 file_, rev = None, file_
1771 file_, rev = None, file_
1772 elif rev is None:
1772 elif rev is None:
1773 raise error.CommandError('debugdata', _('invalid arguments'))
1773 raise error.CommandError('debugdata', _('invalid arguments'))
1774 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1774 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1775 try:
1775 try:
1776 ui.write(r.revision(r.lookup(rev)))
1776 ui.write(r.revision(r.lookup(rev)))
1777 except KeyError:
1777 except KeyError:
1778 raise util.Abort(_('invalid revision identifier %s') % rev)
1778 raise util.Abort(_('invalid revision identifier %s') % rev)
1779
1779
1780 @command('debugdate',
1780 @command('debugdate',
1781 [('e', 'extended', None, _('try extended date formats'))],
1781 [('e', 'extended', None, _('try extended date formats'))],
1782 _('[-e] DATE [RANGE]'))
1782 _('[-e] DATE [RANGE]'))
1783 def debugdate(ui, date, range=None, **opts):
1783 def debugdate(ui, date, range=None, **opts):
1784 """parse and display a date"""
1784 """parse and display a date"""
1785 if opts["extended"]:
1785 if opts["extended"]:
1786 d = util.parsedate(date, util.extendeddateformats)
1786 d = util.parsedate(date, util.extendeddateformats)
1787 else:
1787 else:
1788 d = util.parsedate(date)
1788 d = util.parsedate(date)
1789 ui.write("internal: %s %s\n" % d)
1789 ui.write("internal: %s %s\n" % d)
1790 ui.write("standard: %s\n" % util.datestr(d))
1790 ui.write("standard: %s\n" % util.datestr(d))
1791 if range:
1791 if range:
1792 m = util.matchdate(range)
1792 m = util.matchdate(range)
1793 ui.write("match: %s\n" % m(d[0]))
1793 ui.write("match: %s\n" % m(d[0]))
1794
1794
1795 @command('debugdiscovery',
1795 @command('debugdiscovery',
1796 [('', 'old', None, _('use old-style discovery')),
1796 [('', 'old', None, _('use old-style discovery')),
1797 ('', 'nonheads', None,
1797 ('', 'nonheads', None,
1798 _('use old-style discovery with non-heads included')),
1798 _('use old-style discovery with non-heads included')),
1799 ] + remoteopts,
1799 ] + remoteopts,
1800 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1800 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1801 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1801 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1802 """runs the changeset discovery protocol in isolation"""
1802 """runs the changeset discovery protocol in isolation"""
1803 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1803 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1804 opts.get('branch'))
1804 opts.get('branch'))
1805 remote = hg.peer(repo, opts, remoteurl)
1805 remote = hg.peer(repo, opts, remoteurl)
1806 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1806 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1807
1807
1808 # make sure tests are repeatable
1808 # make sure tests are repeatable
1809 random.seed(12323)
1809 random.seed(12323)
1810
1810
1811 def doit(localheads, remoteheads, remote=remote):
1811 def doit(localheads, remoteheads, remote=remote):
1812 if opts.get('old'):
1812 if opts.get('old'):
1813 if localheads:
1813 if localheads:
1814 raise util.Abort('cannot use localheads with old style '
1814 raise util.Abort('cannot use localheads with old style '
1815 'discovery')
1815 'discovery')
1816 if not util.safehasattr(remote, 'branches'):
1816 if not util.safehasattr(remote, 'branches'):
1817 # enable in-client legacy support
1817 # enable in-client legacy support
1818 remote = localrepo.locallegacypeer(remote.local())
1818 remote = localrepo.locallegacypeer(remote.local())
1819 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1819 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1820 force=True)
1820 force=True)
1821 common = set(common)
1821 common = set(common)
1822 if not opts.get('nonheads'):
1822 if not opts.get('nonheads'):
1823 ui.write("unpruned common: %s\n" % " ".join([short(n)
1823 ui.write("unpruned common: %s\n" % " ".join([short(n)
1824 for n in common]))
1824 for n in common]))
1825 dag = dagutil.revlogdag(repo.changelog)
1825 dag = dagutil.revlogdag(repo.changelog)
1826 all = dag.ancestorset(dag.internalizeall(common))
1826 all = dag.ancestorset(dag.internalizeall(common))
1827 common = dag.externalizeall(dag.headsetofconnecteds(all))
1827 common = dag.externalizeall(dag.headsetofconnecteds(all))
1828 else:
1828 else:
1829 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1829 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1830 common = set(common)
1830 common = set(common)
1831 rheads = set(hds)
1831 rheads = set(hds)
1832 lheads = set(repo.heads())
1832 lheads = set(repo.heads())
1833 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1833 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1834 if lheads <= common:
1834 if lheads <= common:
1835 ui.write("local is subset\n")
1835 ui.write("local is subset\n")
1836 elif rheads <= common:
1836 elif rheads <= common:
1837 ui.write("remote is subset\n")
1837 ui.write("remote is subset\n")
1838
1838
1839 serverlogs = opts.get('serverlog')
1839 serverlogs = opts.get('serverlog')
1840 if serverlogs:
1840 if serverlogs:
1841 for filename in serverlogs:
1841 for filename in serverlogs:
1842 logfile = open(filename, 'r')
1842 logfile = open(filename, 'r')
1843 try:
1843 try:
1844 line = logfile.readline()
1844 line = logfile.readline()
1845 while line:
1845 while line:
1846 parts = line.strip().split(';')
1846 parts = line.strip().split(';')
1847 op = parts[1]
1847 op = parts[1]
1848 if op == 'cg':
1848 if op == 'cg':
1849 pass
1849 pass
1850 elif op == 'cgss':
1850 elif op == 'cgss':
1851 doit(parts[2].split(' '), parts[3].split(' '))
1851 doit(parts[2].split(' '), parts[3].split(' '))
1852 elif op == 'unb':
1852 elif op == 'unb':
1853 doit(parts[3].split(' '), parts[2].split(' '))
1853 doit(parts[3].split(' '), parts[2].split(' '))
1854 line = logfile.readline()
1854 line = logfile.readline()
1855 finally:
1855 finally:
1856 logfile.close()
1856 logfile.close()
1857
1857
1858 else:
1858 else:
1859 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1859 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1860 opts.get('remote_head'))
1860 opts.get('remote_head'))
1861 localrevs = opts.get('local_head')
1861 localrevs = opts.get('local_head')
1862 doit(localrevs, remoterevs)
1862 doit(localrevs, remoterevs)
1863
1863
1864 @command('debugfileset',
1864 @command('debugfileset',
1865 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1865 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1866 _('[-r REV] FILESPEC'))
1866 _('[-r REV] FILESPEC'))
1867 def debugfileset(ui, repo, expr, **opts):
1867 def debugfileset(ui, repo, expr, **opts):
1868 '''parse and apply a fileset specification'''
1868 '''parse and apply a fileset specification'''
1869 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1869 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1870 if ui.verbose:
1870 if ui.verbose:
1871 tree = fileset.parse(expr)[0]
1871 tree = fileset.parse(expr)[0]
1872 ui.note(tree, "\n")
1872 ui.note(tree, "\n")
1873
1873
1874 for f in fileset.getfileset(ctx, expr):
1874 for f in fileset.getfileset(ctx, expr):
1875 ui.write("%s\n" % f)
1875 ui.write("%s\n" % f)
1876
1876
1877 @command('debugfsinfo', [], _('[PATH]'))
1877 @command('debugfsinfo', [], _('[PATH]'))
1878 def debugfsinfo(ui, path = "."):
1878 def debugfsinfo(ui, path = "."):
1879 """show information detected about current filesystem"""
1879 """show information detected about current filesystem"""
1880 util.writefile('.debugfsinfo', '')
1880 util.writefile('.debugfsinfo', '')
1881 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1881 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1882 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1882 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1883 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1883 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1884 and 'yes' or 'no'))
1884 and 'yes' or 'no'))
1885 os.unlink('.debugfsinfo')
1885 os.unlink('.debugfsinfo')
1886
1886
1887 @command('debuggetbundle',
1887 @command('debuggetbundle',
1888 [('H', 'head', [], _('id of head node'), _('ID')),
1888 [('H', 'head', [], _('id of head node'), _('ID')),
1889 ('C', 'common', [], _('id of common node'), _('ID')),
1889 ('C', 'common', [], _('id of common node'), _('ID')),
1890 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1890 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1891 _('REPO FILE [-H|-C ID]...'))
1891 _('REPO FILE [-H|-C ID]...'))
1892 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1892 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1893 """retrieves a bundle from a repo
1893 """retrieves a bundle from a repo
1894
1894
1895 Every ID must be a full-length hex node id string. Saves the bundle to the
1895 Every ID must be a full-length hex node id string. Saves the bundle to the
1896 given file.
1896 given file.
1897 """
1897 """
1898 repo = hg.peer(ui, opts, repopath)
1898 repo = hg.peer(ui, opts, repopath)
1899 if not repo.capable('getbundle'):
1899 if not repo.capable('getbundle'):
1900 raise util.Abort("getbundle() not supported by target repository")
1900 raise util.Abort("getbundle() not supported by target repository")
1901 args = {}
1901 args = {}
1902 if common:
1902 if common:
1903 args['common'] = [bin(s) for s in common]
1903 args['common'] = [bin(s) for s in common]
1904 if head:
1904 if head:
1905 args['heads'] = [bin(s) for s in head]
1905 args['heads'] = [bin(s) for s in head]
1906 bundle = repo.getbundle('debug', **args)
1906 bundle = repo.getbundle('debug', **args)
1907
1907
1908 bundletype = opts.get('type', 'bzip2').lower()
1908 bundletype = opts.get('type', 'bzip2').lower()
1909 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1909 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1910 bundletype = btypes.get(bundletype)
1910 bundletype = btypes.get(bundletype)
1911 if bundletype not in changegroup.bundletypes:
1911 if bundletype not in changegroup.bundletypes:
1912 raise util.Abort(_('unknown bundle type specified with --type'))
1912 raise util.Abort(_('unknown bundle type specified with --type'))
1913 changegroup.writebundle(bundle, bundlepath, bundletype)
1913 changegroup.writebundle(bundle, bundlepath, bundletype)
1914
1914
1915 @command('debugignore', [], '')
1915 @command('debugignore', [], '')
1916 def debugignore(ui, repo, *values, **opts):
1916 def debugignore(ui, repo, *values, **opts):
1917 """display the combined ignore pattern"""
1917 """display the combined ignore pattern"""
1918 ignore = repo.dirstate._ignore
1918 ignore = repo.dirstate._ignore
1919 includepat = getattr(ignore, 'includepat', None)
1919 includepat = getattr(ignore, 'includepat', None)
1920 if includepat is not None:
1920 if includepat is not None:
1921 ui.write("%s\n" % includepat)
1921 ui.write("%s\n" % includepat)
1922 else:
1922 else:
1923 raise util.Abort(_("no ignore patterns found"))
1923 raise util.Abort(_("no ignore patterns found"))
1924
1924
1925 @command('debugindex',
1925 @command('debugindex',
1926 [('c', 'changelog', False, _('open changelog')),
1926 [('c', 'changelog', False, _('open changelog')),
1927 ('m', 'manifest', False, _('open manifest')),
1927 ('m', 'manifest', False, _('open manifest')),
1928 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1928 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1929 _('[-f FORMAT] -c|-m|FILE'))
1929 _('[-f FORMAT] -c|-m|FILE'))
1930 def debugindex(ui, repo, file_ = None, **opts):
1930 def debugindex(ui, repo, file_ = None, **opts):
1931 """dump the contents of an index file"""
1931 """dump the contents of an index file"""
1932 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1932 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1933 format = opts.get('format', 0)
1933 format = opts.get('format', 0)
1934 if format not in (0, 1):
1934 if format not in (0, 1):
1935 raise util.Abort(_("unknown format %d") % format)
1935 raise util.Abort(_("unknown format %d") % format)
1936
1936
1937 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1937 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1938 if generaldelta:
1938 if generaldelta:
1939 basehdr = ' delta'
1939 basehdr = ' delta'
1940 else:
1940 else:
1941 basehdr = ' base'
1941 basehdr = ' base'
1942
1942
1943 if format == 0:
1943 if format == 0:
1944 ui.write(" rev offset length " + basehdr + " linkrev"
1944 ui.write(" rev offset length " + basehdr + " linkrev"
1945 " nodeid p1 p2\n")
1945 " nodeid p1 p2\n")
1946 elif format == 1:
1946 elif format == 1:
1947 ui.write(" rev flag offset length"
1947 ui.write(" rev flag offset length"
1948 " size " + basehdr + " link p1 p2"
1948 " size " + basehdr + " link p1 p2"
1949 " nodeid\n")
1949 " nodeid\n")
1950
1950
1951 for i in r:
1951 for i in r:
1952 node = r.node(i)
1952 node = r.node(i)
1953 if generaldelta:
1953 if generaldelta:
1954 base = r.deltaparent(i)
1954 base = r.deltaparent(i)
1955 else:
1955 else:
1956 base = r.chainbase(i)
1956 base = r.chainbase(i)
1957 if format == 0:
1957 if format == 0:
1958 try:
1958 try:
1959 pp = r.parents(node)
1959 pp = r.parents(node)
1960 except Exception:
1960 except Exception:
1961 pp = [nullid, nullid]
1961 pp = [nullid, nullid]
1962 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1962 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1963 i, r.start(i), r.length(i), base, r.linkrev(i),
1963 i, r.start(i), r.length(i), base, r.linkrev(i),
1964 short(node), short(pp[0]), short(pp[1])))
1964 short(node), short(pp[0]), short(pp[1])))
1965 elif format == 1:
1965 elif format == 1:
1966 pr = r.parentrevs(i)
1966 pr = r.parentrevs(i)
1967 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1967 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1968 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1968 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1969 base, r.linkrev(i), pr[0], pr[1], short(node)))
1969 base, r.linkrev(i), pr[0], pr[1], short(node)))
1970
1970
1971 @command('debugindexdot', [], _('FILE'))
1971 @command('debugindexdot', [], _('FILE'))
1972 def debugindexdot(ui, repo, file_):
1972 def debugindexdot(ui, repo, file_):
1973 """dump an index DAG as a graphviz dot file"""
1973 """dump an index DAG as a graphviz dot file"""
1974 r = None
1974 r = None
1975 if repo:
1975 if repo:
1976 filelog = repo.file(file_)
1976 filelog = repo.file(file_)
1977 if len(filelog):
1977 if len(filelog):
1978 r = filelog
1978 r = filelog
1979 if not r:
1979 if not r:
1980 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1980 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1981 ui.write("digraph G {\n")
1981 ui.write("digraph G {\n")
1982 for i in r:
1982 for i in r:
1983 node = r.node(i)
1983 node = r.node(i)
1984 pp = r.parents(node)
1984 pp = r.parents(node)
1985 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1985 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1986 if pp[1] != nullid:
1986 if pp[1] != nullid:
1987 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1987 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1988 ui.write("}\n")
1988 ui.write("}\n")
1989
1989
1990 @command('debuginstall', [], '')
1990 @command('debuginstall', [], '')
1991 def debuginstall(ui):
1991 def debuginstall(ui):
1992 '''test Mercurial installation
1992 '''test Mercurial installation
1993
1993
1994 Returns 0 on success.
1994 Returns 0 on success.
1995 '''
1995 '''
1996
1996
1997 def writetemp(contents):
1997 def writetemp(contents):
1998 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1998 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1999 f = os.fdopen(fd, "wb")
1999 f = os.fdopen(fd, "wb")
2000 f.write(contents)
2000 f.write(contents)
2001 f.close()
2001 f.close()
2002 return name
2002 return name
2003
2003
2004 problems = 0
2004 problems = 0
2005
2005
2006 # encoding
2006 # encoding
2007 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2007 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2008 try:
2008 try:
2009 encoding.fromlocal("test")
2009 encoding.fromlocal("test")
2010 except util.Abort, inst:
2010 except util.Abort, inst:
2011 ui.write(" %s\n" % inst)
2011 ui.write(" %s\n" % inst)
2012 ui.write(_(" (check that your locale is properly set)\n"))
2012 ui.write(_(" (check that your locale is properly set)\n"))
2013 problems += 1
2013 problems += 1
2014
2014
2015 # Python lib
2015 # Python lib
2016 ui.status(_("checking Python lib (%s)...\n")
2016 ui.status(_("checking Python lib (%s)...\n")
2017 % os.path.dirname(os.__file__))
2017 % os.path.dirname(os.__file__))
2018
2018
2019 # compiled modules
2019 # compiled modules
2020 ui.status(_("checking installed modules (%s)...\n")
2020 ui.status(_("checking installed modules (%s)...\n")
2021 % os.path.dirname(__file__))
2021 % os.path.dirname(__file__))
2022 try:
2022 try:
2023 import bdiff, mpatch, base85, osutil
2023 import bdiff, mpatch, base85, osutil
2024 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2024 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2025 except Exception, inst:
2025 except Exception, inst:
2026 ui.write(" %s\n" % inst)
2026 ui.write(" %s\n" % inst)
2027 ui.write(_(" One or more extensions could not be found"))
2027 ui.write(_(" One or more extensions could not be found"))
2028 ui.write(_(" (check that you compiled the extensions)\n"))
2028 ui.write(_(" (check that you compiled the extensions)\n"))
2029 problems += 1
2029 problems += 1
2030
2030
2031 # templates
2031 # templates
2032 import templater
2032 import templater
2033 p = templater.templatepath()
2033 p = templater.templatepath()
2034 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2034 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2035 try:
2035 try:
2036 templater.templater(templater.templatepath("map-cmdline.default"))
2036 templater.templater(templater.templatepath("map-cmdline.default"))
2037 except Exception, inst:
2037 except Exception, inst:
2038 ui.write(" %s\n" % inst)
2038 ui.write(" %s\n" % inst)
2039 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2039 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2040 problems += 1
2040 problems += 1
2041
2041
2042 # editor
2042 # editor
2043 ui.status(_("checking commit editor...\n"))
2043 ui.status(_("checking commit editor...\n"))
2044 editor = ui.geteditor()
2044 editor = ui.geteditor()
2045 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2045 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2046 if not cmdpath:
2046 if not cmdpath:
2047 if editor == 'vi':
2047 if editor == 'vi':
2048 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2048 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2049 ui.write(_(" (specify a commit editor in your configuration"
2049 ui.write(_(" (specify a commit editor in your configuration"
2050 " file)\n"))
2050 " file)\n"))
2051 else:
2051 else:
2052 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2052 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2053 ui.write(_(" (specify a commit editor in your configuration"
2053 ui.write(_(" (specify a commit editor in your configuration"
2054 " file)\n"))
2054 " file)\n"))
2055 problems += 1
2055 problems += 1
2056
2056
2057 # check username
2057 # check username
2058 ui.status(_("checking username...\n"))
2058 ui.status(_("checking username...\n"))
2059 try:
2059 try:
2060 ui.username()
2060 ui.username()
2061 except util.Abort, e:
2061 except util.Abort, e:
2062 ui.write(" %s\n" % e)
2062 ui.write(" %s\n" % e)
2063 ui.write(_(" (specify a username in your configuration file)\n"))
2063 ui.write(_(" (specify a username in your configuration file)\n"))
2064 problems += 1
2064 problems += 1
2065
2065
2066 if not problems:
2066 if not problems:
2067 ui.status(_("no problems detected\n"))
2067 ui.status(_("no problems detected\n"))
2068 else:
2068 else:
2069 ui.write(_("%s problems detected,"
2069 ui.write(_("%s problems detected,"
2070 " please check your install!\n") % problems)
2070 " please check your install!\n") % problems)
2071
2071
2072 return problems
2072 return problems
2073
2073
2074 @command('debugknown', [], _('REPO ID...'))
2074 @command('debugknown', [], _('REPO ID...'))
2075 def debugknown(ui, repopath, *ids, **opts):
2075 def debugknown(ui, repopath, *ids, **opts):
2076 """test whether node ids are known to a repo
2076 """test whether node ids are known to a repo
2077
2077
2078 Every ID must be a full-length hex node id string. Returns a list of 0s
2078 Every ID must be a full-length hex node id string. Returns a list of 0s
2079 and 1s indicating unknown/known.
2079 and 1s indicating unknown/known.
2080 """
2080 """
2081 repo = hg.peer(ui, opts, repopath)
2081 repo = hg.peer(ui, opts, repopath)
2082 if not repo.capable('known'):
2082 if not repo.capable('known'):
2083 raise util.Abort("known() not supported by target repository")
2083 raise util.Abort("known() not supported by target repository")
2084 flags = repo.known([bin(s) for s in ids])
2084 flags = repo.known([bin(s) for s in ids])
2085 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2085 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2086
2086
2087 @command('debugobsolete',
2087 @command('debugobsolete',
2088 [('', 'flags', 0, _('markers flag')),
2088 [('', 'flags', 0, _('markers flag')),
2089 ] + commitopts2,
2089 ] + commitopts2,
2090 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2090 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2091 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2091 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2092 """create arbitrary obsolete marker"""
2092 """create arbitrary obsolete marker"""
2093 def parsenodeid(s):
2093 def parsenodeid(s):
2094 try:
2094 try:
2095 # We do not use revsingle/revrange functions here to accept
2095 # We do not use revsingle/revrange functions here to accept
2096 # arbitrary node identifiers, possibly not present in the
2096 # arbitrary node identifiers, possibly not present in the
2097 # local repository.
2097 # local repository.
2098 n = bin(s)
2098 n = bin(s)
2099 if len(n) != len(nullid):
2099 if len(n) != len(nullid):
2100 raise TypeError()
2100 raise TypeError()
2101 return n
2101 return n
2102 except TypeError:
2102 except TypeError:
2103 raise util.Abort('changeset references must be full hexadecimal '
2103 raise util.Abort('changeset references must be full hexadecimal '
2104 'node identifiers')
2104 'node identifiers')
2105
2105
2106 if precursor is not None:
2106 if precursor is not None:
2107 metadata = {}
2107 metadata = {}
2108 if 'date' in opts:
2108 if 'date' in opts:
2109 metadata['date'] = opts['date']
2109 metadata['date'] = opts['date']
2110 metadata['user'] = opts['user'] or ui.username()
2110 metadata['user'] = opts['user'] or ui.username()
2111 succs = tuple(parsenodeid(succ) for succ in successors)
2111 succs = tuple(parsenodeid(succ) for succ in successors)
2112 l = repo.lock()
2112 l = repo.lock()
2113 try:
2113 try:
2114 tr = repo.transaction('debugobsolete')
2114 tr = repo.transaction('debugobsolete')
2115 try:
2115 try:
2116 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2116 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2117 opts['flags'], metadata)
2117 opts['flags'], metadata)
2118 tr.close()
2118 tr.close()
2119 finally:
2119 finally:
2120 tr.release()
2120 tr.release()
2121 finally:
2121 finally:
2122 l.release()
2122 l.release()
2123 else:
2123 else:
2124 for m in obsolete.allmarkers(repo):
2124 for m in obsolete.allmarkers(repo):
2125 ui.write(hex(m.precnode()))
2125 ui.write(hex(m.precnode()))
2126 for repl in m.succnodes():
2126 for repl in m.succnodes():
2127 ui.write(' ')
2127 ui.write(' ')
2128 ui.write(hex(repl))
2128 ui.write(hex(repl))
2129 ui.write(' %X ' % m._data[2])
2129 ui.write(' %X ' % m._data[2])
2130 ui.write(m.metadata())
2130 ui.write(m.metadata())
2131 ui.write('\n')
2131 ui.write('\n')
2132
2132
2133 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2133 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2134 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2134 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2135 '''access the pushkey key/value protocol
2135 '''access the pushkey key/value protocol
2136
2136
2137 With two args, list the keys in the given namespace.
2137 With two args, list the keys in the given namespace.
2138
2138
2139 With five args, set a key to new if it currently is set to old.
2139 With five args, set a key to new if it currently is set to old.
2140 Reports success or failure.
2140 Reports success or failure.
2141 '''
2141 '''
2142
2142
2143 target = hg.peer(ui, {}, repopath)
2143 target = hg.peer(ui, {}, repopath)
2144 if keyinfo:
2144 if keyinfo:
2145 key, old, new = keyinfo
2145 key, old, new = keyinfo
2146 r = target.pushkey(namespace, key, old, new)
2146 r = target.pushkey(namespace, key, old, new)
2147 ui.status(str(r) + '\n')
2147 ui.status(str(r) + '\n')
2148 return not r
2148 return not r
2149 else:
2149 else:
2150 for k, v in target.listkeys(namespace).iteritems():
2150 for k, v in target.listkeys(namespace).iteritems():
2151 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2151 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2152 v.encode('string-escape')))
2152 v.encode('string-escape')))
2153
2153
2154 @command('debugpvec', [], _('A B'))
2154 @command('debugpvec', [], _('A B'))
2155 def debugpvec(ui, repo, a, b=None):
2155 def debugpvec(ui, repo, a, b=None):
2156 ca = scmutil.revsingle(repo, a)
2156 ca = scmutil.revsingle(repo, a)
2157 cb = scmutil.revsingle(repo, b)
2157 cb = scmutil.revsingle(repo, b)
2158 pa = pvec.ctxpvec(ca)
2158 pa = pvec.ctxpvec(ca)
2159 pb = pvec.ctxpvec(cb)
2159 pb = pvec.ctxpvec(cb)
2160 if pa == pb:
2160 if pa == pb:
2161 rel = "="
2161 rel = "="
2162 elif pa > pb:
2162 elif pa > pb:
2163 rel = ">"
2163 rel = ">"
2164 elif pa < pb:
2164 elif pa < pb:
2165 rel = "<"
2165 rel = "<"
2166 elif pa | pb:
2166 elif pa | pb:
2167 rel = "|"
2167 rel = "|"
2168 ui.write(_("a: %s\n") % pa)
2168 ui.write(_("a: %s\n") % pa)
2169 ui.write(_("b: %s\n") % pb)
2169 ui.write(_("b: %s\n") % pb)
2170 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2170 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2171 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2171 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2172 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2172 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2173 pa.distance(pb), rel))
2173 pa.distance(pb), rel))
2174
2174
2175 @command('debugrebuildstate',
2175 @command('debugrebuildstate',
2176 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2176 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2177 _('[-r REV] [REV]'))
2177 _('[-r REV] [REV]'))
2178 def debugrebuildstate(ui, repo, rev="tip"):
2178 def debugrebuildstate(ui, repo, rev="tip"):
2179 """rebuild the dirstate as it would look like for the given revision"""
2179 """rebuild the dirstate as it would look like for the given revision"""
2180 ctx = scmutil.revsingle(repo, rev)
2180 ctx = scmutil.revsingle(repo, rev)
2181 wlock = repo.wlock()
2181 wlock = repo.wlock()
2182 try:
2182 try:
2183 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2183 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2184 finally:
2184 finally:
2185 wlock.release()
2185 wlock.release()
2186
2186
2187 @command('debugrename',
2187 @command('debugrename',
2188 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2188 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2189 _('[-r REV] FILE'))
2189 _('[-r REV] FILE'))
2190 def debugrename(ui, repo, file1, *pats, **opts):
2190 def debugrename(ui, repo, file1, *pats, **opts):
2191 """dump rename information"""
2191 """dump rename information"""
2192
2192
2193 ctx = scmutil.revsingle(repo, opts.get('rev'))
2193 ctx = scmutil.revsingle(repo, opts.get('rev'))
2194 m = scmutil.match(ctx, (file1,) + pats, opts)
2194 m = scmutil.match(ctx, (file1,) + pats, opts)
2195 for abs in ctx.walk(m):
2195 for abs in ctx.walk(m):
2196 fctx = ctx[abs]
2196 fctx = ctx[abs]
2197 o = fctx.filelog().renamed(fctx.filenode())
2197 o = fctx.filelog().renamed(fctx.filenode())
2198 rel = m.rel(abs)
2198 rel = m.rel(abs)
2199 if o:
2199 if o:
2200 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2200 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2201 else:
2201 else:
2202 ui.write(_("%s not renamed\n") % rel)
2202 ui.write(_("%s not renamed\n") % rel)
2203
2203
2204 @command('debugrevlog',
2204 @command('debugrevlog',
2205 [('c', 'changelog', False, _('open changelog')),
2205 [('c', 'changelog', False, _('open changelog')),
2206 ('m', 'manifest', False, _('open manifest')),
2206 ('m', 'manifest', False, _('open manifest')),
2207 ('d', 'dump', False, _('dump index data'))],
2207 ('d', 'dump', False, _('dump index data'))],
2208 _('-c|-m|FILE'))
2208 _('-c|-m|FILE'))
2209 def debugrevlog(ui, repo, file_ = None, **opts):
2209 def debugrevlog(ui, repo, file_ = None, **opts):
2210 """show data and statistics about a revlog"""
2210 """show data and statistics about a revlog"""
2211 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2211 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2212
2212
2213 if opts.get("dump"):
2213 if opts.get("dump"):
2214 numrevs = len(r)
2214 numrevs = len(r)
2215 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2215 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2216 " rawsize totalsize compression heads\n")
2216 " rawsize totalsize compression heads\n")
2217 ts = 0
2217 ts = 0
2218 heads = set()
2218 heads = set()
2219 for rev in xrange(numrevs):
2219 for rev in xrange(numrevs):
2220 dbase = r.deltaparent(rev)
2220 dbase = r.deltaparent(rev)
2221 if dbase == -1:
2221 if dbase == -1:
2222 dbase = rev
2222 dbase = rev
2223 cbase = r.chainbase(rev)
2223 cbase = r.chainbase(rev)
2224 p1, p2 = r.parentrevs(rev)
2224 p1, p2 = r.parentrevs(rev)
2225 rs = r.rawsize(rev)
2225 rs = r.rawsize(rev)
2226 ts = ts + rs
2226 ts = ts + rs
2227 heads -= set(r.parentrevs(rev))
2227 heads -= set(r.parentrevs(rev))
2228 heads.add(rev)
2228 heads.add(rev)
2229 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2229 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2230 (rev, p1, p2, r.start(rev), r.end(rev),
2230 (rev, p1, p2, r.start(rev), r.end(rev),
2231 r.start(dbase), r.start(cbase),
2231 r.start(dbase), r.start(cbase),
2232 r.start(p1), r.start(p2),
2232 r.start(p1), r.start(p2),
2233 rs, ts, ts / r.end(rev), len(heads)))
2233 rs, ts, ts / r.end(rev), len(heads)))
2234 return 0
2234 return 0
2235
2235
2236 v = r.version
2236 v = r.version
2237 format = v & 0xFFFF
2237 format = v & 0xFFFF
2238 flags = []
2238 flags = []
2239 gdelta = False
2239 gdelta = False
2240 if v & revlog.REVLOGNGINLINEDATA:
2240 if v & revlog.REVLOGNGINLINEDATA:
2241 flags.append('inline')
2241 flags.append('inline')
2242 if v & revlog.REVLOGGENERALDELTA:
2242 if v & revlog.REVLOGGENERALDELTA:
2243 gdelta = True
2243 gdelta = True
2244 flags.append('generaldelta')
2244 flags.append('generaldelta')
2245 if not flags:
2245 if not flags:
2246 flags = ['(none)']
2246 flags = ['(none)']
2247
2247
2248 nummerges = 0
2248 nummerges = 0
2249 numfull = 0
2249 numfull = 0
2250 numprev = 0
2250 numprev = 0
2251 nump1 = 0
2251 nump1 = 0
2252 nump2 = 0
2252 nump2 = 0
2253 numother = 0
2253 numother = 0
2254 nump1prev = 0
2254 nump1prev = 0
2255 nump2prev = 0
2255 nump2prev = 0
2256 chainlengths = []
2256 chainlengths = []
2257
2257
2258 datasize = [None, 0, 0L]
2258 datasize = [None, 0, 0L]
2259 fullsize = [None, 0, 0L]
2259 fullsize = [None, 0, 0L]
2260 deltasize = [None, 0, 0L]
2260 deltasize = [None, 0, 0L]
2261
2261
2262 def addsize(size, l):
2262 def addsize(size, l):
2263 if l[0] is None or size < l[0]:
2263 if l[0] is None or size < l[0]:
2264 l[0] = size
2264 l[0] = size
2265 if size > l[1]:
2265 if size > l[1]:
2266 l[1] = size
2266 l[1] = size
2267 l[2] += size
2267 l[2] += size
2268
2268
2269 numrevs = len(r)
2269 numrevs = len(r)
2270 for rev in xrange(numrevs):
2270 for rev in xrange(numrevs):
2271 p1, p2 = r.parentrevs(rev)
2271 p1, p2 = r.parentrevs(rev)
2272 delta = r.deltaparent(rev)
2272 delta = r.deltaparent(rev)
2273 if format > 0:
2273 if format > 0:
2274 addsize(r.rawsize(rev), datasize)
2274 addsize(r.rawsize(rev), datasize)
2275 if p2 != nullrev:
2275 if p2 != nullrev:
2276 nummerges += 1
2276 nummerges += 1
2277 size = r.length(rev)
2277 size = r.length(rev)
2278 if delta == nullrev:
2278 if delta == nullrev:
2279 chainlengths.append(0)
2279 chainlengths.append(0)
2280 numfull += 1
2280 numfull += 1
2281 addsize(size, fullsize)
2281 addsize(size, fullsize)
2282 else:
2282 else:
2283 chainlengths.append(chainlengths[delta] + 1)
2283 chainlengths.append(chainlengths[delta] + 1)
2284 addsize(size, deltasize)
2284 addsize(size, deltasize)
2285 if delta == rev - 1:
2285 if delta == rev - 1:
2286 numprev += 1
2286 numprev += 1
2287 if delta == p1:
2287 if delta == p1:
2288 nump1prev += 1
2288 nump1prev += 1
2289 elif delta == p2:
2289 elif delta == p2:
2290 nump2prev += 1
2290 nump2prev += 1
2291 elif delta == p1:
2291 elif delta == p1:
2292 nump1 += 1
2292 nump1 += 1
2293 elif delta == p2:
2293 elif delta == p2:
2294 nump2 += 1
2294 nump2 += 1
2295 elif delta != nullrev:
2295 elif delta != nullrev:
2296 numother += 1
2296 numother += 1
2297
2297
2298 # Adjust size min value for empty cases
2298 # Adjust size min value for empty cases
2299 for size in (datasize, fullsize, deltasize):
2299 for size in (datasize, fullsize, deltasize):
2300 if size[0] is None:
2300 if size[0] is None:
2301 size[0] = 0
2301 size[0] = 0
2302
2302
2303 numdeltas = numrevs - numfull
2303 numdeltas = numrevs - numfull
2304 numoprev = numprev - nump1prev - nump2prev
2304 numoprev = numprev - nump1prev - nump2prev
2305 totalrawsize = datasize[2]
2305 totalrawsize = datasize[2]
2306 datasize[2] /= numrevs
2306 datasize[2] /= numrevs
2307 fulltotal = fullsize[2]
2307 fulltotal = fullsize[2]
2308 fullsize[2] /= numfull
2308 fullsize[2] /= numfull
2309 deltatotal = deltasize[2]
2309 deltatotal = deltasize[2]
2310 if numrevs - numfull > 0:
2310 if numrevs - numfull > 0:
2311 deltasize[2] /= numrevs - numfull
2311 deltasize[2] /= numrevs - numfull
2312 totalsize = fulltotal + deltatotal
2312 totalsize = fulltotal + deltatotal
2313 avgchainlen = sum(chainlengths) / numrevs
2313 avgchainlen = sum(chainlengths) / numrevs
2314 compratio = totalrawsize / totalsize
2314 compratio = totalrawsize / totalsize
2315
2315
2316 basedfmtstr = '%%%dd\n'
2316 basedfmtstr = '%%%dd\n'
2317 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2317 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2318
2318
2319 def dfmtstr(max):
2319 def dfmtstr(max):
2320 return basedfmtstr % len(str(max))
2320 return basedfmtstr % len(str(max))
2321 def pcfmtstr(max, padding=0):
2321 def pcfmtstr(max, padding=0):
2322 return basepcfmtstr % (len(str(max)), ' ' * padding)
2322 return basepcfmtstr % (len(str(max)), ' ' * padding)
2323
2323
2324 def pcfmt(value, total):
2324 def pcfmt(value, total):
2325 return (value, 100 * float(value) / total)
2325 return (value, 100 * float(value) / total)
2326
2326
2327 ui.write('format : %d\n' % format)
2327 ui.write('format : %d\n' % format)
2328 ui.write('flags : %s\n' % ', '.join(flags))
2328 ui.write('flags : %s\n' % ', '.join(flags))
2329
2329
2330 ui.write('\n')
2330 ui.write('\n')
2331 fmt = pcfmtstr(totalsize)
2331 fmt = pcfmtstr(totalsize)
2332 fmt2 = dfmtstr(totalsize)
2332 fmt2 = dfmtstr(totalsize)
2333 ui.write('revisions : ' + fmt2 % numrevs)
2333 ui.write('revisions : ' + fmt2 % numrevs)
2334 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2334 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2335 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2335 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2336 ui.write('revisions : ' + fmt2 % numrevs)
2336 ui.write('revisions : ' + fmt2 % numrevs)
2337 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2337 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2338 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2338 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2339 ui.write('revision size : ' + fmt2 % totalsize)
2339 ui.write('revision size : ' + fmt2 % totalsize)
2340 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2340 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2341 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2341 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2342
2342
2343 ui.write('\n')
2343 ui.write('\n')
2344 fmt = dfmtstr(max(avgchainlen, compratio))
2344 fmt = dfmtstr(max(avgchainlen, compratio))
2345 ui.write('avg chain length : ' + fmt % avgchainlen)
2345 ui.write('avg chain length : ' + fmt % avgchainlen)
2346 ui.write('compression ratio : ' + fmt % compratio)
2346 ui.write('compression ratio : ' + fmt % compratio)
2347
2347
2348 if format > 0:
2348 if format > 0:
2349 ui.write('\n')
2349 ui.write('\n')
2350 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2350 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2351 % tuple(datasize))
2351 % tuple(datasize))
2352 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2352 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2353 % tuple(fullsize))
2353 % tuple(fullsize))
2354 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2354 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2355 % tuple(deltasize))
2355 % tuple(deltasize))
2356
2356
2357 if numdeltas > 0:
2357 if numdeltas > 0:
2358 ui.write('\n')
2358 ui.write('\n')
2359 fmt = pcfmtstr(numdeltas)
2359 fmt = pcfmtstr(numdeltas)
2360 fmt2 = pcfmtstr(numdeltas, 4)
2360 fmt2 = pcfmtstr(numdeltas, 4)
2361 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2361 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2362 if numprev > 0:
2362 if numprev > 0:
2363 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2363 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2364 numprev))
2364 numprev))
2365 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2365 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2366 numprev))
2366 numprev))
2367 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2367 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2368 numprev))
2368 numprev))
2369 if gdelta:
2369 if gdelta:
2370 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2370 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2371 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2371 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2372 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2372 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2373 numdeltas))
2373 numdeltas))
2374
2374
2375 @command('debugrevspec', [], ('REVSPEC'))
2375 @command('debugrevspec', [], ('REVSPEC'))
2376 def debugrevspec(ui, repo, expr):
2376 def debugrevspec(ui, repo, expr):
2377 """parse and apply a revision specification
2377 """parse and apply a revision specification
2378
2378
2379 Use --verbose to print the parsed tree before and after aliases
2379 Use --verbose to print the parsed tree before and after aliases
2380 expansion.
2380 expansion.
2381 """
2381 """
2382 if ui.verbose:
2382 if ui.verbose:
2383 tree = revset.parse(expr)[0]
2383 tree = revset.parse(expr)[0]
2384 ui.note(revset.prettyformat(tree), "\n")
2384 ui.note(revset.prettyformat(tree), "\n")
2385 newtree = revset.findaliases(ui, tree)
2385 newtree = revset.findaliases(ui, tree)
2386 if newtree != tree:
2386 if newtree != tree:
2387 ui.note(revset.prettyformat(newtree), "\n")
2387 ui.note(revset.prettyformat(newtree), "\n")
2388 func = revset.match(ui, expr)
2388 func = revset.match(ui, expr)
2389 for c in func(repo, range(len(repo))):
2389 for c in func(repo, range(len(repo))):
2390 ui.write("%s\n" % c)
2390 ui.write("%s\n" % c)
2391
2391
2392 @command('debugsetparents', [], _('REV1 [REV2]'))
2392 @command('debugsetparents', [], _('REV1 [REV2]'))
2393 def debugsetparents(ui, repo, rev1, rev2=None):
2393 def debugsetparents(ui, repo, rev1, rev2=None):
2394 """manually set the parents of the current working directory
2394 """manually set the parents of the current working directory
2395
2395
2396 This is useful for writing repository conversion tools, but should
2396 This is useful for writing repository conversion tools, but should
2397 be used with care.
2397 be used with care.
2398
2398
2399 Returns 0 on success.
2399 Returns 0 on success.
2400 """
2400 """
2401
2401
2402 r1 = scmutil.revsingle(repo, rev1).node()
2402 r1 = scmutil.revsingle(repo, rev1).node()
2403 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2403 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2404
2404
2405 wlock = repo.wlock()
2405 wlock = repo.wlock()
2406 try:
2406 try:
2407 repo.setparents(r1, r2)
2407 repo.setparents(r1, r2)
2408 finally:
2408 finally:
2409 wlock.release()
2409 wlock.release()
2410
2410
2411 @command('debugstate',
2411 @command('debugstate',
2412 [('', 'nodates', None, _('do not display the saved mtime')),
2412 [('', 'nodates', None, _('do not display the saved mtime')),
2413 ('', 'datesort', None, _('sort by saved mtime'))],
2413 ('', 'datesort', None, _('sort by saved mtime'))],
2414 _('[OPTION]...'))
2414 _('[OPTION]...'))
2415 def debugstate(ui, repo, nodates=None, datesort=None):
2415 def debugstate(ui, repo, nodates=None, datesort=None):
2416 """show the contents of the current dirstate"""
2416 """show the contents of the current dirstate"""
2417 timestr = ""
2417 timestr = ""
2418 showdate = not nodates
2418 showdate = not nodates
2419 if datesort:
2419 if datesort:
2420 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2420 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2421 else:
2421 else:
2422 keyfunc = None # sort by filename
2422 keyfunc = None # sort by filename
2423 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2423 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2424 if showdate:
2424 if showdate:
2425 if ent[3] == -1:
2425 if ent[3] == -1:
2426 # Pad or slice to locale representation
2426 # Pad or slice to locale representation
2427 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2427 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2428 time.localtime(0)))
2428 time.localtime(0)))
2429 timestr = 'unset'
2429 timestr = 'unset'
2430 timestr = (timestr[:locale_len] +
2430 timestr = (timestr[:locale_len] +
2431 ' ' * (locale_len - len(timestr)))
2431 ' ' * (locale_len - len(timestr)))
2432 else:
2432 else:
2433 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2433 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2434 time.localtime(ent[3]))
2434 time.localtime(ent[3]))
2435 if ent[1] & 020000:
2435 if ent[1] & 020000:
2436 mode = 'lnk'
2436 mode = 'lnk'
2437 else:
2437 else:
2438 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2438 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2439 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2439 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2440 for f in repo.dirstate.copies():
2440 for f in repo.dirstate.copies():
2441 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2441 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2442
2442
2443 @command('debugsub',
2443 @command('debugsub',
2444 [('r', 'rev', '',
2444 [('r', 'rev', '',
2445 _('revision to check'), _('REV'))],
2445 _('revision to check'), _('REV'))],
2446 _('[-r REV] [REV]'))
2446 _('[-r REV] [REV]'))
2447 def debugsub(ui, repo, rev=None):
2447 def debugsub(ui, repo, rev=None):
2448 ctx = scmutil.revsingle(repo, rev, None)
2448 ctx = scmutil.revsingle(repo, rev, None)
2449 for k, v in sorted(ctx.substate.items()):
2449 for k, v in sorted(ctx.substate.items()):
2450 ui.write('path %s\n' % k)
2450 ui.write('path %s\n' % k)
2451 ui.write(' source %s\n' % v[0])
2451 ui.write(' source %s\n' % v[0])
2452 ui.write(' revision %s\n' % v[1])
2452 ui.write(' revision %s\n' % v[1])
2453
2453
2454 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2454 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2455 def debugwalk(ui, repo, *pats, **opts):
2455 def debugwalk(ui, repo, *pats, **opts):
2456 """show how files match on given patterns"""
2456 """show how files match on given patterns"""
2457 m = scmutil.match(repo[None], pats, opts)
2457 m = scmutil.match(repo[None], pats, opts)
2458 items = list(repo.walk(m))
2458 items = list(repo.walk(m))
2459 if not items:
2459 if not items:
2460 return
2460 return
2461 f = lambda fn: fn
2461 f = lambda fn: fn
2462 if ui.configbool('ui', 'slash') and os.sep != '/':
2462 if ui.configbool('ui', 'slash') and os.sep != '/':
2463 f = lambda fn: util.normpath(fn)
2463 f = lambda fn: util.normpath(fn)
2464 fmt = 'f %%-%ds %%-%ds %%s' % (
2464 fmt = 'f %%-%ds %%-%ds %%s' % (
2465 max([len(abs) for abs in items]),
2465 max([len(abs) for abs in items]),
2466 max([len(m.rel(abs)) for abs in items]))
2466 max([len(m.rel(abs)) for abs in items]))
2467 for abs in items:
2467 for abs in items:
2468 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2468 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2469 ui.write("%s\n" % line.rstrip())
2469 ui.write("%s\n" % line.rstrip())
2470
2470
2471 @command('debugwireargs',
2471 @command('debugwireargs',
2472 [('', 'three', '', 'three'),
2472 [('', 'three', '', 'three'),
2473 ('', 'four', '', 'four'),
2473 ('', 'four', '', 'four'),
2474 ('', 'five', '', 'five'),
2474 ('', 'five', '', 'five'),
2475 ] + remoteopts,
2475 ] + remoteopts,
2476 _('REPO [OPTIONS]... [ONE [TWO]]'))
2476 _('REPO [OPTIONS]... [ONE [TWO]]'))
2477 def debugwireargs(ui, repopath, *vals, **opts):
2477 def debugwireargs(ui, repopath, *vals, **opts):
2478 repo = hg.peer(ui, opts, repopath)
2478 repo = hg.peer(ui, opts, repopath)
2479 for opt in remoteopts:
2479 for opt in remoteopts:
2480 del opts[opt[1]]
2480 del opts[opt[1]]
2481 args = {}
2481 args = {}
2482 for k, v in opts.iteritems():
2482 for k, v in opts.iteritems():
2483 if v:
2483 if v:
2484 args[k] = v
2484 args[k] = v
2485 # run twice to check that we don't mess up the stream for the next command
2485 # run twice to check that we don't mess up the stream for the next command
2486 res1 = repo.debugwireargs(*vals, **args)
2486 res1 = repo.debugwireargs(*vals, **args)
2487 res2 = repo.debugwireargs(*vals, **args)
2487 res2 = repo.debugwireargs(*vals, **args)
2488 ui.write("%s\n" % res1)
2488 ui.write("%s\n" % res1)
2489 if res1 != res2:
2489 if res1 != res2:
2490 ui.warn("%s\n" % res2)
2490 ui.warn("%s\n" % res2)
2491
2491
2492 @command('^diff',
2492 @command('^diff',
2493 [('r', 'rev', [], _('revision'), _('REV')),
2493 [('r', 'rev', [], _('revision'), _('REV')),
2494 ('c', 'change', '', _('change made by revision'), _('REV'))
2494 ('c', 'change', '', _('change made by revision'), _('REV'))
2495 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2495 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2496 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2496 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2497 def diff(ui, repo, *pats, **opts):
2497 def diff(ui, repo, *pats, **opts):
2498 """diff repository (or selected files)
2498 """diff repository (or selected files)
2499
2499
2500 Show differences between revisions for the specified files.
2500 Show differences between revisions for the specified files.
2501
2501
2502 Differences between files are shown using the unified diff format.
2502 Differences between files are shown using the unified diff format.
2503
2503
2504 .. note::
2504 .. note::
2505 diff may generate unexpected results for merges, as it will
2505 diff may generate unexpected results for merges, as it will
2506 default to comparing against the working directory's first
2506 default to comparing against the working directory's first
2507 parent changeset if no revisions are specified.
2507 parent changeset if no revisions are specified.
2508
2508
2509 When two revision arguments are given, then changes are shown
2509 When two revision arguments are given, then changes are shown
2510 between those revisions. If only one revision is specified then
2510 between those revisions. If only one revision is specified then
2511 that revision is compared to the working directory, and, when no
2511 that revision is compared to the working directory, and, when no
2512 revisions are specified, the working directory files are compared
2512 revisions are specified, the working directory files are compared
2513 to its parent.
2513 to its parent.
2514
2514
2515 Alternatively you can specify -c/--change with a revision to see
2515 Alternatively you can specify -c/--change with a revision to see
2516 the changes in that changeset relative to its first parent.
2516 the changes in that changeset relative to its first parent.
2517
2517
2518 Without the -a/--text option, diff will avoid generating diffs of
2518 Without the -a/--text option, diff will avoid generating diffs of
2519 files it detects as binary. With -a, diff will generate a diff
2519 files it detects as binary. With -a, diff will generate a diff
2520 anyway, probably with undesirable results.
2520 anyway, probably with undesirable results.
2521
2521
2522 Use the -g/--git option to generate diffs in the git extended diff
2522 Use the -g/--git option to generate diffs in the git extended diff
2523 format. For more information, read :hg:`help diffs`.
2523 format. For more information, read :hg:`help diffs`.
2524
2524
2525 .. container:: verbose
2525 .. container:: verbose
2526
2526
2527 Examples:
2527 Examples:
2528
2528
2529 - compare a file in the current working directory to its parent::
2529 - compare a file in the current working directory to its parent::
2530
2530
2531 hg diff foo.c
2531 hg diff foo.c
2532
2532
2533 - compare two historical versions of a directory, with rename info::
2533 - compare two historical versions of a directory, with rename info::
2534
2534
2535 hg diff --git -r 1.0:1.2 lib/
2535 hg diff --git -r 1.0:1.2 lib/
2536
2536
2537 - get change stats relative to the last change on some date::
2537 - get change stats relative to the last change on some date::
2538
2538
2539 hg diff --stat -r "date('may 2')"
2539 hg diff --stat -r "date('may 2')"
2540
2540
2541 - diff all newly-added files that contain a keyword::
2541 - diff all newly-added files that contain a keyword::
2542
2542
2543 hg diff "set:added() and grep(GNU)"
2543 hg diff "set:added() and grep(GNU)"
2544
2544
2545 - compare a revision and its parents::
2545 - compare a revision and its parents::
2546
2546
2547 hg diff -c 9353 # compare against first parent
2547 hg diff -c 9353 # compare against first parent
2548 hg diff -r 9353^:9353 # same using revset syntax
2548 hg diff -r 9353^:9353 # same using revset syntax
2549 hg diff -r 9353^2:9353 # compare against the second parent
2549 hg diff -r 9353^2:9353 # compare against the second parent
2550
2550
2551 Returns 0 on success.
2551 Returns 0 on success.
2552 """
2552 """
2553
2553
2554 revs = opts.get('rev')
2554 revs = opts.get('rev')
2555 change = opts.get('change')
2555 change = opts.get('change')
2556 stat = opts.get('stat')
2556 stat = opts.get('stat')
2557 reverse = opts.get('reverse')
2557 reverse = opts.get('reverse')
2558
2558
2559 if revs and change:
2559 if revs and change:
2560 msg = _('cannot specify --rev and --change at the same time')
2560 msg = _('cannot specify --rev and --change at the same time')
2561 raise util.Abort(msg)
2561 raise util.Abort(msg)
2562 elif change:
2562 elif change:
2563 node2 = scmutil.revsingle(repo, change, None).node()
2563 node2 = scmutil.revsingle(repo, change, None).node()
2564 node1 = repo[node2].p1().node()
2564 node1 = repo[node2].p1().node()
2565 else:
2565 else:
2566 node1, node2 = scmutil.revpair(repo, revs)
2566 node1, node2 = scmutil.revpair(repo, revs)
2567
2567
2568 if reverse:
2568 if reverse:
2569 node1, node2 = node2, node1
2569 node1, node2 = node2, node1
2570
2570
2571 diffopts = patch.diffopts(ui, opts)
2571 diffopts = patch.diffopts(ui, opts)
2572 m = scmutil.match(repo[node2], pats, opts)
2572 m = scmutil.match(repo[node2], pats, opts)
2573 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2573 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2574 listsubrepos=opts.get('subrepos'))
2574 listsubrepos=opts.get('subrepos'))
2575
2575
2576 @command('^export',
2576 @command('^export',
2577 [('o', 'output', '',
2577 [('o', 'output', '',
2578 _('print output to file with formatted name'), _('FORMAT')),
2578 _('print output to file with formatted name'), _('FORMAT')),
2579 ('', 'switch-parent', None, _('diff against the second parent')),
2579 ('', 'switch-parent', None, _('diff against the second parent')),
2580 ('r', 'rev', [], _('revisions to export'), _('REV')),
2580 ('r', 'rev', [], _('revisions to export'), _('REV')),
2581 ] + diffopts,
2581 ] + diffopts,
2582 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2582 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2583 def export(ui, repo, *changesets, **opts):
2583 def export(ui, repo, *changesets, **opts):
2584 """dump the header and diffs for one or more changesets
2584 """dump the header and diffs for one or more changesets
2585
2585
2586 Print the changeset header and diffs for one or more revisions.
2586 Print the changeset header and diffs for one or more revisions.
2587
2587
2588 The information shown in the changeset header is: author, date,
2588 The information shown in the changeset header is: author, date,
2589 branch name (if non-default), changeset hash, parent(s) and commit
2589 branch name (if non-default), changeset hash, parent(s) and commit
2590 comment.
2590 comment.
2591
2591
2592 .. note::
2592 .. note::
2593 export may generate unexpected diff output for merge
2593 export may generate unexpected diff output for merge
2594 changesets, as it will compare the merge changeset against its
2594 changesets, as it will compare the merge changeset against its
2595 first parent only.
2595 first parent only.
2596
2596
2597 Output may be to a file, in which case the name of the file is
2597 Output may be to a file, in which case the name of the file is
2598 given using a format string. The formatting rules are as follows:
2598 given using a format string. The formatting rules are as follows:
2599
2599
2600 :``%%``: literal "%" character
2600 :``%%``: literal "%" character
2601 :``%H``: changeset hash (40 hexadecimal digits)
2601 :``%H``: changeset hash (40 hexadecimal digits)
2602 :``%N``: number of patches being generated
2602 :``%N``: number of patches being generated
2603 :``%R``: changeset revision number
2603 :``%R``: changeset revision number
2604 :``%b``: basename of the exporting repository
2604 :``%b``: basename of the exporting repository
2605 :``%h``: short-form changeset hash (12 hexadecimal digits)
2605 :``%h``: short-form changeset hash (12 hexadecimal digits)
2606 :``%m``: first line of the commit message (only alphanumeric characters)
2606 :``%m``: first line of the commit message (only alphanumeric characters)
2607 :``%n``: zero-padded sequence number, starting at 1
2607 :``%n``: zero-padded sequence number, starting at 1
2608 :``%r``: zero-padded changeset revision number
2608 :``%r``: zero-padded changeset revision number
2609
2609
2610 Without the -a/--text option, export will avoid generating diffs
2610 Without the -a/--text option, export will avoid generating diffs
2611 of files it detects as binary. With -a, export will generate a
2611 of files it detects as binary. With -a, export will generate a
2612 diff anyway, probably with undesirable results.
2612 diff anyway, probably with undesirable results.
2613
2613
2614 Use the -g/--git option to generate diffs in the git extended diff
2614 Use the -g/--git option to generate diffs in the git extended diff
2615 format. See :hg:`help diffs` for more information.
2615 format. See :hg:`help diffs` for more information.
2616
2616
2617 With the --switch-parent option, the diff will be against the
2617 With the --switch-parent option, the diff will be against the
2618 second parent. It can be useful to review a merge.
2618 second parent. It can be useful to review a merge.
2619
2619
2620 .. container:: verbose
2620 .. container:: verbose
2621
2621
2622 Examples:
2622 Examples:
2623
2623
2624 - use export and import to transplant a bugfix to the current
2624 - use export and import to transplant a bugfix to the current
2625 branch::
2625 branch::
2626
2626
2627 hg export -r 9353 | hg import -
2627 hg export -r 9353 | hg import -
2628
2628
2629 - export all the changesets between two revisions to a file with
2629 - export all the changesets between two revisions to a file with
2630 rename information::
2630 rename information::
2631
2631
2632 hg export --git -r 123:150 > changes.txt
2632 hg export --git -r 123:150 > changes.txt
2633
2633
2634 - split outgoing changes into a series of patches with
2634 - split outgoing changes into a series of patches with
2635 descriptive names::
2635 descriptive names::
2636
2636
2637 hg export -r "outgoing()" -o "%n-%m.patch"
2637 hg export -r "outgoing()" -o "%n-%m.patch"
2638
2638
2639 Returns 0 on success.
2639 Returns 0 on success.
2640 """
2640 """
2641 changesets += tuple(opts.get('rev', []))
2641 changesets += tuple(opts.get('rev', []))
2642 revs = scmutil.revrange(repo, changesets)
2642 revs = scmutil.revrange(repo, changesets)
2643 if not revs:
2643 if not revs:
2644 raise util.Abort(_("export requires at least one changeset"))
2644 raise util.Abort(_("export requires at least one changeset"))
2645 if len(revs) > 1:
2645 if len(revs) > 1:
2646 ui.note(_('exporting patches:\n'))
2646 ui.note(_('exporting patches:\n'))
2647 else:
2647 else:
2648 ui.note(_('exporting patch:\n'))
2648 ui.note(_('exporting patch:\n'))
2649 cmdutil.export(repo, revs, template=opts.get('output'),
2649 cmdutil.export(repo, revs, template=opts.get('output'),
2650 switch_parent=opts.get('switch_parent'),
2650 switch_parent=opts.get('switch_parent'),
2651 opts=patch.diffopts(ui, opts))
2651 opts=patch.diffopts(ui, opts))
2652
2652
2653 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2653 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2654 def forget(ui, repo, *pats, **opts):
2654 def forget(ui, repo, *pats, **opts):
2655 """forget the specified files on the next commit
2655 """forget the specified files on the next commit
2656
2656
2657 Mark the specified files so they will no longer be tracked
2657 Mark the specified files so they will no longer be tracked
2658 after the next commit.
2658 after the next commit.
2659
2659
2660 This only removes files from the current branch, not from the
2660 This only removes files from the current branch, not from the
2661 entire project history, and it does not delete them from the
2661 entire project history, and it does not delete them from the
2662 working directory.
2662 working directory.
2663
2663
2664 To undo a forget before the next commit, see :hg:`add`.
2664 To undo a forget before the next commit, see :hg:`add`.
2665
2665
2666 .. container:: verbose
2666 .. container:: verbose
2667
2667
2668 Examples:
2668 Examples:
2669
2669
2670 - forget newly-added binary files::
2670 - forget newly-added binary files::
2671
2671
2672 hg forget "set:added() and binary()"
2672 hg forget "set:added() and binary()"
2673
2673
2674 - forget files that would be excluded by .hgignore::
2674 - forget files that would be excluded by .hgignore::
2675
2675
2676 hg forget "set:hgignore()"
2676 hg forget "set:hgignore()"
2677
2677
2678 Returns 0 on success.
2678 Returns 0 on success.
2679 """
2679 """
2680
2680
2681 if not pats:
2681 if not pats:
2682 raise util.Abort(_('no files specified'))
2682 raise util.Abort(_('no files specified'))
2683
2683
2684 m = scmutil.match(repo[None], pats, opts)
2684 m = scmutil.match(repo[None], pats, opts)
2685 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2685 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2686 return rejected and 1 or 0
2686 return rejected and 1 or 0
2687
2687
2688 @command(
2688 @command(
2689 'graft',
2689 'graft',
2690 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2690 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2691 ('c', 'continue', False, _('resume interrupted graft')),
2691 ('c', 'continue', False, _('resume interrupted graft')),
2692 ('e', 'edit', False, _('invoke editor on commit messages')),
2692 ('e', 'edit', False, _('invoke editor on commit messages')),
2693 ('', 'log', None, _('append graft info to log message')),
2693 ('', 'log', None, _('append graft info to log message')),
2694 ('D', 'currentdate', False,
2694 ('D', 'currentdate', False,
2695 _('record the current date as commit date')),
2695 _('record the current date as commit date')),
2696 ('U', 'currentuser', False,
2696 ('U', 'currentuser', False,
2697 _('record the current user as committer'), _('DATE'))]
2697 _('record the current user as committer'), _('DATE'))]
2698 + commitopts2 + mergetoolopts + dryrunopts,
2698 + commitopts2 + mergetoolopts + dryrunopts,
2699 _('[OPTION]... [-r] REV...'))
2699 _('[OPTION]... [-r] REV...'))
2700 def graft(ui, repo, *revs, **opts):
2700 def graft(ui, repo, *revs, **opts):
2701 '''copy changes from other branches onto the current branch
2701 '''copy changes from other branches onto the current branch
2702
2702
2703 This command uses Mercurial's merge logic to copy individual
2703 This command uses Mercurial's merge logic to copy individual
2704 changes from other branches without merging branches in the
2704 changes from other branches without merging branches in the
2705 history graph. This is sometimes known as 'backporting' or
2705 history graph. This is sometimes known as 'backporting' or
2706 'cherry-picking'. By default, graft will copy user, date, and
2706 'cherry-picking'. By default, graft will copy user, date, and
2707 description from the source changesets.
2707 description from the source changesets.
2708
2708
2709 Changesets that are ancestors of the current revision, that have
2709 Changesets that are ancestors of the current revision, that have
2710 already been grafted, or that are merges will be skipped.
2710 already been grafted, or that are merges will be skipped.
2711
2711
2712 If --log is specified, log messages will have a comment appended
2712 If --log is specified, log messages will have a comment appended
2713 of the form::
2713 of the form::
2714
2714
2715 (grafted from CHANGESETHASH)
2715 (grafted from CHANGESETHASH)
2716
2716
2717 If a graft merge results in conflicts, the graft process is
2717 If a graft merge results in conflicts, the graft process is
2718 interrupted so that the current merge can be manually resolved.
2718 interrupted so that the current merge can be manually resolved.
2719 Once all conflicts are addressed, the graft process can be
2719 Once all conflicts are addressed, the graft process can be
2720 continued with the -c/--continue option.
2720 continued with the -c/--continue option.
2721
2721
2722 .. note::
2722 .. note::
2723 The -c/--continue option does not reapply earlier options.
2723 The -c/--continue option does not reapply earlier options.
2724
2724
2725 .. container:: verbose
2725 .. container:: verbose
2726
2726
2727 Examples:
2727 Examples:
2728
2728
2729 - copy a single change to the stable branch and edit its description::
2729 - copy a single change to the stable branch and edit its description::
2730
2730
2731 hg update stable
2731 hg update stable
2732 hg graft --edit 9393
2732 hg graft --edit 9393
2733
2733
2734 - graft a range of changesets with one exception, updating dates::
2734 - graft a range of changesets with one exception, updating dates::
2735
2735
2736 hg graft -D "2085::2093 and not 2091"
2736 hg graft -D "2085::2093 and not 2091"
2737
2737
2738 - continue a graft after resolving conflicts::
2738 - continue a graft after resolving conflicts::
2739
2739
2740 hg graft -c
2740 hg graft -c
2741
2741
2742 - show the source of a grafted changeset::
2742 - show the source of a grafted changeset::
2743
2743
2744 hg log --debug -r tip
2744 hg log --debug -r tip
2745
2745
2746 Returns 0 on successful completion.
2746 Returns 0 on successful completion.
2747 '''
2747 '''
2748
2748
2749 revs = list(revs)
2749 revs = list(revs)
2750 revs.extend(opts['rev'])
2750 revs.extend(opts['rev'])
2751
2751
2752 if not opts.get('user') and opts.get('currentuser'):
2752 if not opts.get('user') and opts.get('currentuser'):
2753 opts['user'] = ui.username()
2753 opts['user'] = ui.username()
2754 if not opts.get('date') and opts.get('currentdate'):
2754 if not opts.get('date') and opts.get('currentdate'):
2755 opts['date'] = "%d %d" % util.makedate()
2755 opts['date'] = "%d %d" % util.makedate()
2756
2756
2757 editor = None
2757 editor = None
2758 if opts.get('edit'):
2758 if opts.get('edit'):
2759 editor = cmdutil.commitforceeditor
2759 editor = cmdutil.commitforceeditor
2760
2760
2761 cont = False
2761 cont = False
2762 if opts['continue']:
2762 if opts['continue']:
2763 cont = True
2763 cont = True
2764 if revs:
2764 if revs:
2765 raise util.Abort(_("can't specify --continue and revisions"))
2765 raise util.Abort(_("can't specify --continue and revisions"))
2766 # read in unfinished revisions
2766 # read in unfinished revisions
2767 try:
2767 try:
2768 nodes = repo.opener.read('graftstate').splitlines()
2768 nodes = repo.opener.read('graftstate').splitlines()
2769 revs = [repo[node].rev() for node in nodes]
2769 revs = [repo[node].rev() for node in nodes]
2770 except IOError, inst:
2770 except IOError, inst:
2771 if inst.errno != errno.ENOENT:
2771 if inst.errno != errno.ENOENT:
2772 raise
2772 raise
2773 raise util.Abort(_("no graft state found, can't continue"))
2773 raise util.Abort(_("no graft state found, can't continue"))
2774 else:
2774 else:
2775 cmdutil.bailifchanged(repo)
2775 cmdutil.bailifchanged(repo)
2776 if not revs:
2776 if not revs:
2777 raise util.Abort(_('no revisions specified'))
2777 raise util.Abort(_('no revisions specified'))
2778 revs = scmutil.revrange(repo, revs)
2778 revs = scmutil.revrange(repo, revs)
2779
2779
2780 # check for merges
2780 # check for merges
2781 for rev in repo.revs('%ld and merge()', revs):
2781 for rev in repo.revs('%ld and merge()', revs):
2782 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2782 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2783 revs.remove(rev)
2783 revs.remove(rev)
2784 if not revs:
2784 if not revs:
2785 return -1
2785 return -1
2786
2786
2787 # check for ancestors of dest branch
2787 # check for ancestors of dest branch
2788 for rev in repo.revs('::. and %ld', revs):
2788 for rev in repo.revs('::. and %ld', revs):
2789 ui.warn(_('skipping ancestor revision %s\n') % rev)
2789 ui.warn(_('skipping ancestor revision %s\n') % rev)
2790 revs.remove(rev)
2790 revs.remove(rev)
2791 if not revs:
2791 if not revs:
2792 return -1
2792 return -1
2793
2793
2794 # analyze revs for earlier grafts
2794 # analyze revs for earlier grafts
2795 ids = {}
2795 ids = {}
2796 for ctx in repo.set("%ld", revs):
2796 for ctx in repo.set("%ld", revs):
2797 ids[ctx.hex()] = ctx.rev()
2797 ids[ctx.hex()] = ctx.rev()
2798 n = ctx.extra().get('source')
2798 n = ctx.extra().get('source')
2799 if n:
2799 if n:
2800 ids[n] = ctx.rev()
2800 ids[n] = ctx.rev()
2801
2801
2802 # check ancestors for earlier grafts
2802 # check ancestors for earlier grafts
2803 ui.debug('scanning for duplicate grafts\n')
2803 ui.debug('scanning for duplicate grafts\n')
2804 for ctx in repo.set("::. - ::%ld", revs):
2804 for ctx in repo.set("::. - ::%ld", revs):
2805 n = ctx.extra().get('source')
2805 n = ctx.extra().get('source')
2806 if n in ids:
2806 if n in ids:
2807 r = repo[n].rev()
2807 r = repo[n].rev()
2808 if r in revs:
2808 if r in revs:
2809 ui.warn(_('skipping already grafted revision %s\n') % r)
2809 ui.warn(_('skipping already grafted revision %s\n') % r)
2810 revs.remove(r)
2810 revs.remove(r)
2811 elif ids[n] in revs:
2811 elif ids[n] in revs:
2812 ui.warn(_('skipping already grafted revision %s '
2812 ui.warn(_('skipping already grafted revision %s '
2813 '(same origin %d)\n') % (ids[n], r))
2813 '(same origin %d)\n') % (ids[n], r))
2814 revs.remove(ids[n])
2814 revs.remove(ids[n])
2815 elif ctx.hex() in ids:
2815 elif ctx.hex() in ids:
2816 r = ids[ctx.hex()]
2816 r = ids[ctx.hex()]
2817 ui.warn(_('skipping already grafted revision %s '
2817 ui.warn(_('skipping already grafted revision %s '
2818 '(was grafted from %d)\n') % (r, ctx.rev()))
2818 '(was grafted from %d)\n') % (r, ctx.rev()))
2819 revs.remove(r)
2819 revs.remove(r)
2820 if not revs:
2820 if not revs:
2821 return -1
2821 return -1
2822
2822
2823 wlock = repo.wlock()
2823 wlock = repo.wlock()
2824 try:
2824 try:
2825 for pos, ctx in enumerate(repo.set("%ld", revs)):
2825 for pos, ctx in enumerate(repo.set("%ld", revs)):
2826 current = repo['.']
2826 current = repo['.']
2827
2827
2828 ui.status(_('grafting revision %s\n') % ctx.rev())
2828 ui.status(_('grafting revision %s\n') % ctx.rev())
2829 if opts.get('dry_run'):
2829 if opts.get('dry_run'):
2830 continue
2830 continue
2831
2831
2832 # we don't merge the first commit when continuing
2832 # we don't merge the first commit when continuing
2833 if not cont:
2833 if not cont:
2834 # perform the graft merge with p1(rev) as 'ancestor'
2834 # perform the graft merge with p1(rev) as 'ancestor'
2835 try:
2835 try:
2836 # ui.forcemerge is an internal variable, do not document
2836 # ui.forcemerge is an internal variable, do not document
2837 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2837 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2838 stats = mergemod.update(repo, ctx.node(), True, True, False,
2838 stats = mergemod.update(repo, ctx.node(), True, True, False,
2839 ctx.p1().node())
2839 ctx.p1().node())
2840 finally:
2840 finally:
2841 repo.ui.setconfig('ui', 'forcemerge', '')
2841 repo.ui.setconfig('ui', 'forcemerge', '')
2842 # report any conflicts
2842 # report any conflicts
2843 if stats and stats[3] > 0:
2843 if stats and stats[3] > 0:
2844 # write out state for --continue
2844 # write out state for --continue
2845 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2845 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2846 repo.opener.write('graftstate', ''.join(nodelines))
2846 repo.opener.write('graftstate', ''.join(nodelines))
2847 raise util.Abort(
2847 raise util.Abort(
2848 _("unresolved conflicts, can't continue"),
2848 _("unresolved conflicts, can't continue"),
2849 hint=_('use hg resolve and hg graft --continue'))
2849 hint=_('use hg resolve and hg graft --continue'))
2850 else:
2850 else:
2851 cont = False
2851 cont = False
2852
2852
2853 # drop the second merge parent
2853 # drop the second merge parent
2854 repo.setparents(current.node(), nullid)
2854 repo.setparents(current.node(), nullid)
2855 repo.dirstate.write()
2855 repo.dirstate.write()
2856 # fix up dirstate for copies and renames
2856 # fix up dirstate for copies and renames
2857 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2857 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2858
2858
2859 # commit
2859 # commit
2860 source = ctx.extra().get('source')
2860 source = ctx.extra().get('source')
2861 if not source:
2861 if not source:
2862 source = ctx.hex()
2862 source = ctx.hex()
2863 extra = {'source': source}
2863 extra = {'source': source}
2864 user = ctx.user()
2864 user = ctx.user()
2865 if opts.get('user'):
2865 if opts.get('user'):
2866 user = opts['user']
2866 user = opts['user']
2867 date = ctx.date()
2867 date = ctx.date()
2868 if opts.get('date'):
2868 if opts.get('date'):
2869 date = opts['date']
2869 date = opts['date']
2870 message = ctx.description()
2870 message = ctx.description()
2871 if opts.get('log'):
2871 if opts.get('log'):
2872 message += '\n(grafted from %s)' % ctx.hex()
2872 message += '\n(grafted from %s)' % ctx.hex()
2873 node = repo.commit(text=message, user=user,
2873 node = repo.commit(text=message, user=user,
2874 date=date, extra=extra, editor=editor)
2874 date=date, extra=extra, editor=editor)
2875 if node is None:
2875 if node is None:
2876 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2876 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2877 finally:
2877 finally:
2878 wlock.release()
2878 wlock.release()
2879
2879
2880 # remove state when we complete successfully
2880 # remove state when we complete successfully
2881 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2881 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2882 util.unlinkpath(repo.join('graftstate'))
2882 util.unlinkpath(repo.join('graftstate'))
2883
2883
2884 return 0
2884 return 0
2885
2885
2886 @command('grep',
2886 @command('grep',
2887 [('0', 'print0', None, _('end fields with NUL')),
2887 [('0', 'print0', None, _('end fields with NUL')),
2888 ('', 'all', None, _('print all revisions that match')),
2888 ('', 'all', None, _('print all revisions that match')),
2889 ('a', 'text', None, _('treat all files as text')),
2889 ('a', 'text', None, _('treat all files as text')),
2890 ('f', 'follow', None,
2890 ('f', 'follow', None,
2891 _('follow changeset history,'
2891 _('follow changeset history,'
2892 ' or file history across copies and renames')),
2892 ' or file history across copies and renames')),
2893 ('i', 'ignore-case', None, _('ignore case when matching')),
2893 ('i', 'ignore-case', None, _('ignore case when matching')),
2894 ('l', 'files-with-matches', None,
2894 ('l', 'files-with-matches', None,
2895 _('print only filenames and revisions that match')),
2895 _('print only filenames and revisions that match')),
2896 ('n', 'line-number', None, _('print matching line numbers')),
2896 ('n', 'line-number', None, _('print matching line numbers')),
2897 ('r', 'rev', [],
2897 ('r', 'rev', [],
2898 _('only search files changed within revision range'), _('REV')),
2898 _('only search files changed within revision range'), _('REV')),
2899 ('u', 'user', None, _('list the author (long with -v)')),
2899 ('u', 'user', None, _('list the author (long with -v)')),
2900 ('d', 'date', None, _('list the date (short with -q)')),
2900 ('d', 'date', None, _('list the date (short with -q)')),
2901 ] + walkopts,
2901 ] + walkopts,
2902 _('[OPTION]... PATTERN [FILE]...'))
2902 _('[OPTION]... PATTERN [FILE]...'))
2903 def grep(ui, repo, pattern, *pats, **opts):
2903 def grep(ui, repo, pattern, *pats, **opts):
2904 """search for a pattern in specified files and revisions
2904 """search for a pattern in specified files and revisions
2905
2905
2906 Search revisions of files for a regular expression.
2906 Search revisions of files for a regular expression.
2907
2907
2908 This command behaves differently than Unix grep. It only accepts
2908 This command behaves differently than Unix grep. It only accepts
2909 Python/Perl regexps. It searches repository history, not the
2909 Python/Perl regexps. It searches repository history, not the
2910 working directory. It always prints the revision number in which a
2910 working directory. It always prints the revision number in which a
2911 match appears.
2911 match appears.
2912
2912
2913 By default, grep only prints output for the first revision of a
2913 By default, grep only prints output for the first revision of a
2914 file in which it finds a match. To get it to print every revision
2914 file in which it finds a match. To get it to print every revision
2915 that contains a change in match status ("-" for a match that
2915 that contains a change in match status ("-" for a match that
2916 becomes a non-match, or "+" for a non-match that becomes a match),
2916 becomes a non-match, or "+" for a non-match that becomes a match),
2917 use the --all flag.
2917 use the --all flag.
2918
2918
2919 Returns 0 if a match is found, 1 otherwise.
2919 Returns 0 if a match is found, 1 otherwise.
2920 """
2920 """
2921 reflags = re.M
2921 reflags = re.M
2922 if opts.get('ignore_case'):
2922 if opts.get('ignore_case'):
2923 reflags |= re.I
2923 reflags |= re.I
2924 try:
2924 try:
2925 regexp = re.compile(pattern, reflags)
2925 regexp = re.compile(pattern, reflags)
2926 except re.error, inst:
2926 except re.error, inst:
2927 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2927 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2928 return 1
2928 return 1
2929 sep, eol = ':', '\n'
2929 sep, eol = ':', '\n'
2930 if opts.get('print0'):
2930 if opts.get('print0'):
2931 sep = eol = '\0'
2931 sep = eol = '\0'
2932
2932
2933 getfile = util.lrucachefunc(repo.file)
2933 getfile = util.lrucachefunc(repo.file)
2934
2934
2935 def matchlines(body):
2935 def matchlines(body):
2936 begin = 0
2936 begin = 0
2937 linenum = 0
2937 linenum = 0
2938 while True:
2938 while True:
2939 match = regexp.search(body, begin)
2939 match = regexp.search(body, begin)
2940 if not match:
2940 if not match:
2941 break
2941 break
2942 mstart, mend = match.span()
2942 mstart, mend = match.span()
2943 linenum += body.count('\n', begin, mstart) + 1
2943 linenum += body.count('\n', begin, mstart) + 1
2944 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2944 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2945 begin = body.find('\n', mend) + 1 or len(body) + 1
2945 begin = body.find('\n', mend) + 1 or len(body) + 1
2946 lend = begin - 1
2946 lend = begin - 1
2947 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2947 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2948
2948
2949 class linestate(object):
2949 class linestate(object):
2950 def __init__(self, line, linenum, colstart, colend):
2950 def __init__(self, line, linenum, colstart, colend):
2951 self.line = line
2951 self.line = line
2952 self.linenum = linenum
2952 self.linenum = linenum
2953 self.colstart = colstart
2953 self.colstart = colstart
2954 self.colend = colend
2954 self.colend = colend
2955
2955
2956 def __hash__(self):
2956 def __hash__(self):
2957 return hash((self.linenum, self.line))
2957 return hash((self.linenum, self.line))
2958
2958
2959 def __eq__(self, other):
2959 def __eq__(self, other):
2960 return self.line == other.line
2960 return self.line == other.line
2961
2961
2962 matches = {}
2962 matches = {}
2963 copies = {}
2963 copies = {}
2964 def grepbody(fn, rev, body):
2964 def grepbody(fn, rev, body):
2965 matches[rev].setdefault(fn, [])
2965 matches[rev].setdefault(fn, [])
2966 m = matches[rev][fn]
2966 m = matches[rev][fn]
2967 for lnum, cstart, cend, line in matchlines(body):
2967 for lnum, cstart, cend, line in matchlines(body):
2968 s = linestate(line, lnum, cstart, cend)
2968 s = linestate(line, lnum, cstart, cend)
2969 m.append(s)
2969 m.append(s)
2970
2970
2971 def difflinestates(a, b):
2971 def difflinestates(a, b):
2972 sm = difflib.SequenceMatcher(None, a, b)
2972 sm = difflib.SequenceMatcher(None, a, b)
2973 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2973 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2974 if tag == 'insert':
2974 if tag == 'insert':
2975 for i in xrange(blo, bhi):
2975 for i in xrange(blo, bhi):
2976 yield ('+', b[i])
2976 yield ('+', b[i])
2977 elif tag == 'delete':
2977 elif tag == 'delete':
2978 for i in xrange(alo, ahi):
2978 for i in xrange(alo, ahi):
2979 yield ('-', a[i])
2979 yield ('-', a[i])
2980 elif tag == 'replace':
2980 elif tag == 'replace':
2981 for i in xrange(alo, ahi):
2981 for i in xrange(alo, ahi):
2982 yield ('-', a[i])
2982 yield ('-', a[i])
2983 for i in xrange(blo, bhi):
2983 for i in xrange(blo, bhi):
2984 yield ('+', b[i])
2984 yield ('+', b[i])
2985
2985
2986 def display(fn, ctx, pstates, states):
2986 def display(fn, ctx, pstates, states):
2987 rev = ctx.rev()
2987 rev = ctx.rev()
2988 datefunc = ui.quiet and util.shortdate or util.datestr
2988 datefunc = ui.quiet and util.shortdate or util.datestr
2989 found = False
2989 found = False
2990 filerevmatches = {}
2990 filerevmatches = {}
2991 def binary():
2991 def binary():
2992 flog = getfile(fn)
2992 flog = getfile(fn)
2993 return util.binary(flog.read(ctx.filenode(fn)))
2993 return util.binary(flog.read(ctx.filenode(fn)))
2994
2994
2995 if opts.get('all'):
2995 if opts.get('all'):
2996 iter = difflinestates(pstates, states)
2996 iter = difflinestates(pstates, states)
2997 else:
2997 else:
2998 iter = [('', l) for l in states]
2998 iter = [('', l) for l in states]
2999 for change, l in iter:
2999 for change, l in iter:
3000 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3000 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3001 before, match, after = None, None, None
3001 before, match, after = None, None, None
3002
3002
3003 if opts.get('line_number'):
3003 if opts.get('line_number'):
3004 cols.append((str(l.linenum), 'grep.linenumber'))
3004 cols.append((str(l.linenum), 'grep.linenumber'))
3005 if opts.get('all'):
3005 if opts.get('all'):
3006 cols.append((change, 'grep.change'))
3006 cols.append((change, 'grep.change'))
3007 if opts.get('user'):
3007 if opts.get('user'):
3008 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3008 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3009 if opts.get('date'):
3009 if opts.get('date'):
3010 cols.append((datefunc(ctx.date()), 'grep.date'))
3010 cols.append((datefunc(ctx.date()), 'grep.date'))
3011 if opts.get('files_with_matches'):
3011 if opts.get('files_with_matches'):
3012 c = (fn, rev)
3012 c = (fn, rev)
3013 if c in filerevmatches:
3013 if c in filerevmatches:
3014 continue
3014 continue
3015 filerevmatches[c] = 1
3015 filerevmatches[c] = 1
3016 else:
3016 else:
3017 before = l.line[:l.colstart]
3017 before = l.line[:l.colstart]
3018 match = l.line[l.colstart:l.colend]
3018 match = l.line[l.colstart:l.colend]
3019 after = l.line[l.colend:]
3019 after = l.line[l.colend:]
3020 for col, label in cols[:-1]:
3020 for col, label in cols[:-1]:
3021 ui.write(col, label=label)
3021 ui.write(col, label=label)
3022 ui.write(sep, label='grep.sep')
3022 ui.write(sep, label='grep.sep')
3023 ui.write(cols[-1][0], label=cols[-1][1])
3023 ui.write(cols[-1][0], label=cols[-1][1])
3024 if before is not None:
3024 if before is not None:
3025 ui.write(sep, label='grep.sep')
3025 ui.write(sep, label='grep.sep')
3026 if not opts.get('text') and binary():
3026 if not opts.get('text') and binary():
3027 ui.write(" Binary file matches")
3027 ui.write(" Binary file matches")
3028 else:
3028 else:
3029 ui.write(before)
3029 ui.write(before)
3030 ui.write(match, label='grep.match')
3030 ui.write(match, label='grep.match')
3031 ui.write(after)
3031 ui.write(after)
3032 ui.write(eol)
3032 ui.write(eol)
3033 found = True
3033 found = True
3034 return found
3034 return found
3035
3035
3036 skip = {}
3036 skip = {}
3037 revfiles = {}
3037 revfiles = {}
3038 matchfn = scmutil.match(repo[None], pats, opts)
3038 matchfn = scmutil.match(repo[None], pats, opts)
3039 found = False
3039 found = False
3040 follow = opts.get('follow')
3040 follow = opts.get('follow')
3041
3041
3042 def prep(ctx, fns):
3042 def prep(ctx, fns):
3043 rev = ctx.rev()
3043 rev = ctx.rev()
3044 pctx = ctx.p1()
3044 pctx = ctx.p1()
3045 parent = pctx.rev()
3045 parent = pctx.rev()
3046 matches.setdefault(rev, {})
3046 matches.setdefault(rev, {})
3047 matches.setdefault(parent, {})
3047 matches.setdefault(parent, {})
3048 files = revfiles.setdefault(rev, [])
3048 files = revfiles.setdefault(rev, [])
3049 for fn in fns:
3049 for fn in fns:
3050 flog = getfile(fn)
3050 flog = getfile(fn)
3051 try:
3051 try:
3052 fnode = ctx.filenode(fn)
3052 fnode = ctx.filenode(fn)
3053 except error.LookupError:
3053 except error.LookupError:
3054 continue
3054 continue
3055
3055
3056 copied = flog.renamed(fnode)
3056 copied = flog.renamed(fnode)
3057 copy = follow and copied and copied[0]
3057 copy = follow and copied and copied[0]
3058 if copy:
3058 if copy:
3059 copies.setdefault(rev, {})[fn] = copy
3059 copies.setdefault(rev, {})[fn] = copy
3060 if fn in skip:
3060 if fn in skip:
3061 if copy:
3061 if copy:
3062 skip[copy] = True
3062 skip[copy] = True
3063 continue
3063 continue
3064 files.append(fn)
3064 files.append(fn)
3065
3065
3066 if fn not in matches[rev]:
3066 if fn not in matches[rev]:
3067 grepbody(fn, rev, flog.read(fnode))
3067 grepbody(fn, rev, flog.read(fnode))
3068
3068
3069 pfn = copy or fn
3069 pfn = copy or fn
3070 if pfn not in matches[parent]:
3070 if pfn not in matches[parent]:
3071 try:
3071 try:
3072 fnode = pctx.filenode(pfn)
3072 fnode = pctx.filenode(pfn)
3073 grepbody(pfn, parent, flog.read(fnode))
3073 grepbody(pfn, parent, flog.read(fnode))
3074 except error.LookupError:
3074 except error.LookupError:
3075 pass
3075 pass
3076
3076
3077 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3077 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3078 rev = ctx.rev()
3078 rev = ctx.rev()
3079 parent = ctx.p1().rev()
3079 parent = ctx.p1().rev()
3080 for fn in sorted(revfiles.get(rev, [])):
3080 for fn in sorted(revfiles.get(rev, [])):
3081 states = matches[rev][fn]
3081 states = matches[rev][fn]
3082 copy = copies.get(rev, {}).get(fn)
3082 copy = copies.get(rev, {}).get(fn)
3083 if fn in skip:
3083 if fn in skip:
3084 if copy:
3084 if copy:
3085 skip[copy] = True
3085 skip[copy] = True
3086 continue
3086 continue
3087 pstates = matches.get(parent, {}).get(copy or fn, [])
3087 pstates = matches.get(parent, {}).get(copy or fn, [])
3088 if pstates or states:
3088 if pstates or states:
3089 r = display(fn, ctx, pstates, states)
3089 r = display(fn, ctx, pstates, states)
3090 found = found or r
3090 found = found or r
3091 if r and not opts.get('all'):
3091 if r and not opts.get('all'):
3092 skip[fn] = True
3092 skip[fn] = True
3093 if copy:
3093 if copy:
3094 skip[copy] = True
3094 skip[copy] = True
3095 del matches[rev]
3095 del matches[rev]
3096 del revfiles[rev]
3096 del revfiles[rev]
3097
3097
3098 return not found
3098 return not found
3099
3099
3100 @command('heads',
3100 @command('heads',
3101 [('r', 'rev', '',
3101 [('r', 'rev', '',
3102 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3102 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3103 ('t', 'topo', False, _('show topological heads only')),
3103 ('t', 'topo', False, _('show topological heads only')),
3104 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3104 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3105 ('c', 'closed', False, _('show normal and closed branch heads')),
3105 ('c', 'closed', False, _('show normal and closed branch heads')),
3106 ] + templateopts,
3106 ] + templateopts,
3107 _('[-ct] [-r STARTREV] [REV]...'))
3107 _('[-ct] [-r STARTREV] [REV]...'))
3108 def heads(ui, repo, *branchrevs, **opts):
3108 def heads(ui, repo, *branchrevs, **opts):
3109 """show current repository heads or show branch heads
3109 """show current repository heads or show branch heads
3110
3110
3111 With no arguments, show all repository branch heads.
3111 With no arguments, show all repository branch heads.
3112
3112
3113 Repository "heads" are changesets with no child changesets. They are
3113 Repository "heads" are changesets with no child changesets. They are
3114 where development generally takes place and are the usual targets
3114 where development generally takes place and are the usual targets
3115 for update and merge operations. Branch heads are changesets that have
3115 for update and merge operations. Branch heads are changesets that have
3116 no child changeset on the same branch.
3116 no child changeset on the same branch.
3117
3117
3118 If one or more REVs are given, only branch heads on the branches
3118 If one or more REVs are given, only branch heads on the branches
3119 associated with the specified changesets are shown. This means
3119 associated with the specified changesets are shown. This means
3120 that you can use :hg:`heads foo` to see the heads on a branch
3120 that you can use :hg:`heads foo` to see the heads on a branch
3121 named ``foo``.
3121 named ``foo``.
3122
3122
3123 If -c/--closed is specified, also show branch heads marked closed
3123 If -c/--closed is specified, also show branch heads marked closed
3124 (see :hg:`commit --close-branch`).
3124 (see :hg:`commit --close-branch`).
3125
3125
3126 If STARTREV is specified, only those heads that are descendants of
3126 If STARTREV is specified, only those heads that are descendants of
3127 STARTREV will be displayed.
3127 STARTREV will be displayed.
3128
3128
3129 If -t/--topo is specified, named branch mechanics will be ignored and only
3129 If -t/--topo is specified, named branch mechanics will be ignored and only
3130 changesets without children will be shown.
3130 changesets without children will be shown.
3131
3131
3132 Returns 0 if matching heads are found, 1 if not.
3132 Returns 0 if matching heads are found, 1 if not.
3133 """
3133 """
3134
3134
3135 start = None
3135 start = None
3136 if 'rev' in opts:
3136 if 'rev' in opts:
3137 start = scmutil.revsingle(repo, opts['rev'], None).node()
3137 start = scmutil.revsingle(repo, opts['rev'], None).node()
3138
3138
3139 if opts.get('topo'):
3139 if opts.get('topo'):
3140 heads = [repo[h] for h in repo.heads(start)]
3140 heads = [repo[h] for h in repo.heads(start)]
3141 else:
3141 else:
3142 heads = []
3142 heads = []
3143 for branch in repo.branchmap():
3143 for branch in repo.branchmap():
3144 heads += repo.branchheads(branch, start, opts.get('closed'))
3144 heads += repo.branchheads(branch, start, opts.get('closed'))
3145 heads = [repo[h] for h in heads]
3145 heads = [repo[h] for h in heads]
3146
3146
3147 if branchrevs:
3147 if branchrevs:
3148 branches = set(repo[br].branch() for br in branchrevs)
3148 branches = set(repo[br].branch() for br in branchrevs)
3149 heads = [h for h in heads if h.branch() in branches]
3149 heads = [h for h in heads if h.branch() in branches]
3150
3150
3151 if opts.get('active') and branchrevs:
3151 if opts.get('active') and branchrevs:
3152 dagheads = repo.heads(start)
3152 dagheads = repo.heads(start)
3153 heads = [h for h in heads if h.node() in dagheads]
3153 heads = [h for h in heads if h.node() in dagheads]
3154
3154
3155 if branchrevs:
3155 if branchrevs:
3156 haveheads = set(h.branch() for h in heads)
3156 haveheads = set(h.branch() for h in heads)
3157 if branches - haveheads:
3157 if branches - haveheads:
3158 headless = ', '.join(b for b in branches - haveheads)
3158 headless = ', '.join(b for b in branches - haveheads)
3159 msg = _('no open branch heads found on branches %s')
3159 msg = _('no open branch heads found on branches %s')
3160 if opts.get('rev'):
3160 if opts.get('rev'):
3161 msg += _(' (started at %s)') % opts['rev']
3161 msg += _(' (started at %s)') % opts['rev']
3162 ui.warn((msg + '\n') % headless)
3162 ui.warn((msg + '\n') % headless)
3163
3163
3164 if not heads:
3164 if not heads:
3165 return 1
3165 return 1
3166
3166
3167 heads = sorted(heads, key=lambda x: -x.rev())
3167 heads = sorted(heads, key=lambda x: -x.rev())
3168 displayer = cmdutil.show_changeset(ui, repo, opts)
3168 displayer = cmdutil.show_changeset(ui, repo, opts)
3169 for ctx in heads:
3169 for ctx in heads:
3170 displayer.show(ctx)
3170 displayer.show(ctx)
3171 displayer.close()
3171 displayer.close()
3172
3172
3173 @command('help',
3173 @command('help',
3174 [('e', 'extension', None, _('show only help for extensions')),
3174 [('e', 'extension', None, _('show only help for extensions')),
3175 ('c', 'command', None, _('show only help for commands')),
3175 ('c', 'command', None, _('show only help for commands')),
3176 ('k', 'keyword', '', _('show topics matching keyword')),
3176 ('k', 'keyword', '', _('show topics matching keyword')),
3177 ],
3177 ],
3178 _('[-ec] [TOPIC]'))
3178 _('[-ec] [TOPIC]'))
3179 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3179 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3180 """show help for a given topic or a help overview
3180 """show help for a given topic or a help overview
3181
3181
3182 With no arguments, print a list of commands with short help messages.
3182 With no arguments, print a list of commands with short help messages.
3183
3183
3184 Given a topic, extension, or command name, print help for that
3184 Given a topic, extension, or command name, print help for that
3185 topic.
3185 topic.
3186
3186
3187 Returns 0 if successful.
3187 Returns 0 if successful.
3188 """
3188 """
3189
3189
3190 textwidth = min(ui.termwidth(), 80) - 2
3190 textwidth = min(ui.termwidth(), 80) - 2
3191
3191
3192 def helpcmd(name):
3192 def helpcmd(name):
3193 try:
3193 try:
3194 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3194 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3195 except error.AmbiguousCommand, inst:
3195 except error.AmbiguousCommand, inst:
3196 # py3k fix: except vars can't be used outside the scope of the
3196 # py3k fix: except vars can't be used outside the scope of the
3197 # except block, nor can be used inside a lambda. python issue4617
3197 # except block, nor can be used inside a lambda. python issue4617
3198 prefix = inst.args[0]
3198 prefix = inst.args[0]
3199 select = lambda c: c.lstrip('^').startswith(prefix)
3199 select = lambda c: c.lstrip('^').startswith(prefix)
3200 rst = helplist(select)
3200 rst = helplist(select)
3201 return rst
3201 return rst
3202
3202
3203 rst = []
3203 rst = []
3204
3204
3205 # check if it's an invalid alias and display its error if it is
3205 # check if it's an invalid alias and display its error if it is
3206 if getattr(entry[0], 'badalias', False):
3206 if getattr(entry[0], 'badalias', False):
3207 if not unknowncmd:
3207 if not unknowncmd:
3208 ui.pushbuffer()
3208 ui.pushbuffer()
3209 entry[0](ui)
3209 entry[0](ui)
3210 rst.append(ui.popbuffer())
3210 rst.append(ui.popbuffer())
3211 return rst
3211 return rst
3212
3212
3213 # synopsis
3213 # synopsis
3214 if len(entry) > 2:
3214 if len(entry) > 2:
3215 if entry[2].startswith('hg'):
3215 if entry[2].startswith('hg'):
3216 rst.append("%s\n" % entry[2])
3216 rst.append("%s\n" % entry[2])
3217 else:
3217 else:
3218 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3218 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3219 else:
3219 else:
3220 rst.append('hg %s\n' % aliases[0])
3220 rst.append('hg %s\n' % aliases[0])
3221 # aliases
3221 # aliases
3222 if full and not ui.quiet and len(aliases) > 1:
3222 if full and not ui.quiet and len(aliases) > 1:
3223 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3223 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3224 rst.append('\n')
3224 rst.append('\n')
3225
3225
3226 # description
3226 # description
3227 doc = gettext(entry[0].__doc__)
3227 doc = gettext(entry[0].__doc__)
3228 if not doc:
3228 if not doc:
3229 doc = _("(no help text available)")
3229 doc = _("(no help text available)")
3230 if util.safehasattr(entry[0], 'definition'): # aliased command
3230 if util.safehasattr(entry[0], 'definition'): # aliased command
3231 if entry[0].definition.startswith('!'): # shell alias
3231 if entry[0].definition.startswith('!'): # shell alias
3232 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3232 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3233 else:
3233 else:
3234 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3234 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3235 doc = doc.splitlines(True)
3235 doc = doc.splitlines(True)
3236 if ui.quiet or not full:
3236 if ui.quiet or not full:
3237 rst.append(doc[0])
3237 rst.append(doc[0])
3238 else:
3238 else:
3239 rst.extend(doc)
3239 rst.extend(doc)
3240 rst.append('\n')
3240 rst.append('\n')
3241
3241
3242 # check if this command shadows a non-trivial (multi-line)
3242 # check if this command shadows a non-trivial (multi-line)
3243 # extension help text
3243 # extension help text
3244 try:
3244 try:
3245 mod = extensions.find(name)
3245 mod = extensions.find(name)
3246 doc = gettext(mod.__doc__) or ''
3246 doc = gettext(mod.__doc__) or ''
3247 if '\n' in doc.strip():
3247 if '\n' in doc.strip():
3248 msg = _('use "hg help -e %s" to show help for '
3248 msg = _('use "hg help -e %s" to show help for '
3249 'the %s extension') % (name, name)
3249 'the %s extension') % (name, name)
3250 rst.append('\n%s\n' % msg)
3250 rst.append('\n%s\n' % msg)
3251 except KeyError:
3251 except KeyError:
3252 pass
3252 pass
3253
3253
3254 # options
3254 # options
3255 if not ui.quiet and entry[1]:
3255 if not ui.quiet and entry[1]:
3256 rst.append('\n%s\n\n' % _("options:"))
3256 rst.append('\n%s\n\n' % _("options:"))
3257 rst.append(help.optrst(entry[1], ui.verbose))
3257 rst.append(help.optrst(entry[1], ui.verbose))
3258
3258
3259 if ui.verbose:
3259 if ui.verbose:
3260 rst.append('\n%s\n\n' % _("global options:"))
3260 rst.append('\n%s\n\n' % _("global options:"))
3261 rst.append(help.optrst(globalopts, ui.verbose))
3261 rst.append(help.optrst(globalopts, ui.verbose))
3262
3262
3263 if not ui.verbose:
3263 if not ui.verbose:
3264 if not full:
3264 if not full:
3265 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3265 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3266 % name)
3266 % name)
3267 elif not ui.quiet:
3267 elif not ui.quiet:
3268 omitted = _('use "hg -v help %s" to show more complete'
3268 omitted = _('use "hg -v help %s" to show more complete'
3269 ' help and the global options') % name
3269 ' help and the global options') % name
3270 notomitted = _('use "hg -v help %s" to show'
3270 notomitted = _('use "hg -v help %s" to show'
3271 ' the global options') % name
3271 ' the global options') % name
3272 help.indicateomitted(rst, omitted, notomitted)
3272 help.indicateomitted(rst, omitted, notomitted)
3273
3273
3274 return rst
3274 return rst
3275
3275
3276
3276
3277 def helplist(select=None):
3277 def helplist(select=None):
3278 # list of commands
3278 # list of commands
3279 if name == "shortlist":
3279 if name == "shortlist":
3280 header = _('basic commands:\n\n')
3280 header = _('basic commands:\n\n')
3281 else:
3281 else:
3282 header = _('list of commands:\n\n')
3282 header = _('list of commands:\n\n')
3283
3283
3284 h = {}
3284 h = {}
3285 cmds = {}
3285 cmds = {}
3286 for c, e in table.iteritems():
3286 for c, e in table.iteritems():
3287 f = c.split("|", 1)[0]
3287 f = c.split("|", 1)[0]
3288 if select and not select(f):
3288 if select and not select(f):
3289 continue
3289 continue
3290 if (not select and name != 'shortlist' and
3290 if (not select and name != 'shortlist' and
3291 e[0].__module__ != __name__):
3291 e[0].__module__ != __name__):
3292 continue
3292 continue
3293 if name == "shortlist" and not f.startswith("^"):
3293 if name == "shortlist" and not f.startswith("^"):
3294 continue
3294 continue
3295 f = f.lstrip("^")
3295 f = f.lstrip("^")
3296 if not ui.debugflag and f.startswith("debug"):
3296 if not ui.debugflag and f.startswith("debug"):
3297 continue
3297 continue
3298 doc = e[0].__doc__
3298 doc = e[0].__doc__
3299 if doc and 'DEPRECATED' in doc and not ui.verbose:
3299 if doc and 'DEPRECATED' in doc and not ui.verbose:
3300 continue
3300 continue
3301 doc = gettext(doc)
3301 doc = gettext(doc)
3302 if not doc:
3302 if not doc:
3303 doc = _("(no help text available)")
3303 doc = _("(no help text available)")
3304 h[f] = doc.splitlines()[0].rstrip()
3304 h[f] = doc.splitlines()[0].rstrip()
3305 cmds[f] = c.lstrip("^")
3305 cmds[f] = c.lstrip("^")
3306
3306
3307 rst = []
3307 rst = []
3308 if not h:
3308 if not h:
3309 if not ui.quiet:
3309 if not ui.quiet:
3310 rst.append(_('no commands defined\n'))
3310 rst.append(_('no commands defined\n'))
3311 return rst
3311 return rst
3312
3312
3313 if not ui.quiet:
3313 if not ui.quiet:
3314 rst.append(header)
3314 rst.append(header)
3315 fns = sorted(h)
3315 fns = sorted(h)
3316 for f in fns:
3316 for f in fns:
3317 if ui.verbose:
3317 if ui.verbose:
3318 commands = cmds[f].replace("|",", ")
3318 commands = cmds[f].replace("|",", ")
3319 rst.append(" :%s: %s\n" % (commands, h[f]))
3319 rst.append(" :%s: %s\n" % (commands, h[f]))
3320 else:
3320 else:
3321 rst.append(' :%s: %s\n' % (f, h[f]))
3321 rst.append(' :%s: %s\n' % (f, h[f]))
3322
3322
3323 if not name:
3323 if not name:
3324 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3324 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3325 if exts:
3325 if exts:
3326 rst.append('\n')
3326 rst.append('\n')
3327 rst.extend(exts)
3327 rst.extend(exts)
3328
3328
3329 rst.append(_("\nadditional help topics:\n\n"))
3329 rst.append(_("\nadditional help topics:\n\n"))
3330 topics = []
3330 topics = []
3331 for names, header, doc in help.helptable:
3331 for names, header, doc in help.helptable:
3332 topics.append((names[0], header))
3332 topics.append((names[0], header))
3333 for t, desc in topics:
3333 for t, desc in topics:
3334 rst.append(" :%s: %s\n" % (t, desc))
3334 rst.append(" :%s: %s\n" % (t, desc))
3335
3335
3336 optlist = []
3336 optlist = []
3337 if not ui.quiet:
3337 if not ui.quiet:
3338 if ui.verbose:
3338 if ui.verbose:
3339 optlist.append((_("global options:"), globalopts))
3339 optlist.append((_("global options:"), globalopts))
3340 if name == 'shortlist':
3340 if name == 'shortlist':
3341 optlist.append((_('use "hg help" for the full list '
3341 optlist.append((_('use "hg help" for the full list '
3342 'of commands'), ()))
3342 'of commands'), ()))
3343 else:
3343 else:
3344 if name == 'shortlist':
3344 if name == 'shortlist':
3345 msg = _('use "hg help" for the full list of commands '
3345 msg = _('use "hg help" for the full list of commands '
3346 'or "hg -v" for details')
3346 'or "hg -v" for details')
3347 elif name and not full:
3347 elif name and not full:
3348 msg = _('use "hg help %s" to show the full help '
3348 msg = _('use "hg help %s" to show the full help '
3349 'text') % name
3349 'text') % name
3350 else:
3350 else:
3351 msg = _('use "hg -v help%s" to show builtin aliases and '
3351 msg = _('use "hg -v help%s" to show builtin aliases and '
3352 'global options') % (name and " " + name or "")
3352 'global options') % (name and " " + name or "")
3353 optlist.append((msg, ()))
3353 optlist.append((msg, ()))
3354
3354
3355 if optlist:
3355 if optlist:
3356 for title, options in optlist:
3356 for title, options in optlist:
3357 rst.append('\n%s\n' % title)
3357 rst.append('\n%s\n' % title)
3358 if options:
3358 if options:
3359 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3359 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3360 return rst
3360 return rst
3361
3361
3362 def helptopic(name):
3362 def helptopic(name):
3363 for names, header, doc in help.helptable:
3363 for names, header, doc in help.helptable:
3364 if name in names:
3364 if name in names:
3365 break
3365 break
3366 else:
3366 else:
3367 raise error.UnknownCommand(name)
3367 raise error.UnknownCommand(name)
3368
3368
3369 rst = ["%s\n\n" % header]
3369 rst = ["%s\n\n" % header]
3370 # description
3370 # description
3371 if not doc:
3371 if not doc:
3372 rst.append(" %s\n" % _("(no help text available)"))
3372 rst.append(" %s\n" % _("(no help text available)"))
3373 if util.safehasattr(doc, '__call__'):
3373 if util.safehasattr(doc, '__call__'):
3374 rst += [" %s\n" % l for l in doc().splitlines()]
3374 rst += [" %s\n" % l for l in doc().splitlines()]
3375
3375
3376 if not ui.verbose:
3376 if not ui.verbose:
3377 omitted = (_('use "hg help -v %s" to show more complete help') %
3377 omitted = (_('use "hg help -v %s" to show more complete help') %
3378 name)
3378 name)
3379 help.indicateomitted(rst, omitted)
3379 help.indicateomitted(rst, omitted)
3380
3380
3381 try:
3381 try:
3382 cmdutil.findcmd(name, table)
3382 cmdutil.findcmd(name, table)
3383 rst.append(_('\nuse "hg help -c %s" to see help for '
3383 rst.append(_('\nuse "hg help -c %s" to see help for '
3384 'the %s command\n') % (name, name))
3384 'the %s command\n') % (name, name))
3385 except error.UnknownCommand:
3385 except error.UnknownCommand:
3386 pass
3386 pass
3387 return rst
3387 return rst
3388
3388
3389 def helpext(name):
3389 def helpext(name):
3390 try:
3390 try:
3391 mod = extensions.find(name)
3391 mod = extensions.find(name)
3392 doc = gettext(mod.__doc__) or _('no help text available')
3392 doc = gettext(mod.__doc__) or _('no help text available')
3393 except KeyError:
3393 except KeyError:
3394 mod = None
3394 mod = None
3395 doc = extensions.disabledext(name)
3395 doc = extensions.disabledext(name)
3396 if not doc:
3396 if not doc:
3397 raise error.UnknownCommand(name)
3397 raise error.UnknownCommand(name)
3398
3398
3399 if '\n' not in doc:
3399 if '\n' not in doc:
3400 head, tail = doc, ""
3400 head, tail = doc, ""
3401 else:
3401 else:
3402 head, tail = doc.split('\n', 1)
3402 head, tail = doc.split('\n', 1)
3403 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3403 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3404 if tail:
3404 if tail:
3405 rst.extend(tail.splitlines(True))
3405 rst.extend(tail.splitlines(True))
3406 rst.append('\n')
3406 rst.append('\n')
3407
3407
3408 if not ui.verbose:
3408 if not ui.verbose:
3409 omitted = (_('use "hg help -v %s" to show more complete help') %
3409 omitted = (_('use "hg help -v %s" to show more complete help') %
3410 name)
3410 name)
3411 help.indicateomitted(rst, omitted)
3411 help.indicateomitted(rst, omitted)
3412
3412
3413 if mod:
3413 if mod:
3414 try:
3414 try:
3415 ct = mod.cmdtable
3415 ct = mod.cmdtable
3416 except AttributeError:
3416 except AttributeError:
3417 ct = {}
3417 ct = {}
3418 modcmds = set([c.split('|', 1)[0] for c in ct])
3418 modcmds = set([c.split('|', 1)[0] for c in ct])
3419 rst.extend(helplist(modcmds.__contains__))
3419 rst.extend(helplist(modcmds.__contains__))
3420 else:
3420 else:
3421 rst.append(_('use "hg help extensions" for information on enabling '
3421 rst.append(_('use "hg help extensions" for information on enabling '
3422 'extensions\n'))
3422 'extensions\n'))
3423 return rst
3423 return rst
3424
3424
3425 def helpextcmd(name):
3425 def helpextcmd(name):
3426 cmd, ext, mod = extensions.disabledcmd(ui, name,
3426 cmd, ext, mod = extensions.disabledcmd(ui, name,
3427 ui.configbool('ui', 'strict'))
3427 ui.configbool('ui', 'strict'))
3428 doc = gettext(mod.__doc__).splitlines()[0]
3428 doc = gettext(mod.__doc__).splitlines()[0]
3429
3429
3430 rst = help.listexts(_("'%s' is provided by the following "
3430 rst = help.listexts(_("'%s' is provided by the following "
3431 "extension:") % cmd, {ext: doc}, indent=4)
3431 "extension:") % cmd, {ext: doc}, indent=4)
3432 rst.append('\n')
3432 rst.append('\n')
3433 rst.append(_('use "hg help extensions" for information on enabling '
3433 rst.append(_('use "hg help extensions" for information on enabling '
3434 'extensions\n'))
3434 'extensions\n'))
3435 return rst
3435 return rst
3436
3436
3437
3437
3438 rst = []
3438 rst = []
3439 kw = opts.get('keyword')
3439 kw = opts.get('keyword')
3440 if kw:
3440 if kw:
3441 matches = help.topicmatch(kw)
3441 matches = help.topicmatch(kw)
3442 for t, title in (('topics', _('Topics')),
3442 for t, title in (('topics', _('Topics')),
3443 ('commands', _('Commands')),
3443 ('commands', _('Commands')),
3444 ('extensions', _('Extensions')),
3444 ('extensions', _('Extensions')),
3445 ('extensioncommands', _('Extension Commands'))):
3445 ('extensioncommands', _('Extension Commands'))):
3446 if matches[t]:
3446 if matches[t]:
3447 rst.append('%s:\n\n' % title)
3447 rst.append('%s:\n\n' % title)
3448 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3448 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3449 rst.append('\n')
3449 rst.append('\n')
3450 elif name and name != 'shortlist':
3450 elif name and name != 'shortlist':
3451 i = None
3451 i = None
3452 if unknowncmd:
3452 if unknowncmd:
3453 queries = (helpextcmd,)
3453 queries = (helpextcmd,)
3454 elif opts.get('extension'):
3454 elif opts.get('extension'):
3455 queries = (helpext,)
3455 queries = (helpext,)
3456 elif opts.get('command'):
3456 elif opts.get('command'):
3457 queries = (helpcmd,)
3457 queries = (helpcmd,)
3458 else:
3458 else:
3459 queries = (helptopic, helpcmd, helpext, helpextcmd)
3459 queries = (helptopic, helpcmd, helpext, helpextcmd)
3460 for f in queries:
3460 for f in queries:
3461 try:
3461 try:
3462 rst = f(name)
3462 rst = f(name)
3463 i = None
3463 i = None
3464 break
3464 break
3465 except error.UnknownCommand, inst:
3465 except error.UnknownCommand, inst:
3466 i = inst
3466 i = inst
3467 if i:
3467 if i:
3468 raise i
3468 raise i
3469 else:
3469 else:
3470 # program name
3470 # program name
3471 if not ui.quiet:
3471 if not ui.quiet:
3472 rst = [_("Mercurial Distributed SCM\n"), '\n']
3472 rst = [_("Mercurial Distributed SCM\n"), '\n']
3473 rst.extend(helplist())
3473 rst.extend(helplist())
3474
3474
3475 keep = ui.verbose and ['verbose'] or []
3475 keep = ui.verbose and ['verbose'] or []
3476 text = ''.join(rst)
3476 text = ''.join(rst)
3477 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3477 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3478 if 'verbose' in pruned:
3478 if 'verbose' in pruned:
3479 keep.append('omitted')
3479 keep.append('omitted')
3480 else:
3480 else:
3481 keep.append('notomitted')
3481 keep.append('notomitted')
3482 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3482 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3483 ui.write(formatted)
3483 ui.write(formatted)
3484
3484
3485
3485
3486 @command('identify|id',
3486 @command('identify|id',
3487 [('r', 'rev', '',
3487 [('r', 'rev', '',
3488 _('identify the specified revision'), _('REV')),
3488 _('identify the specified revision'), _('REV')),
3489 ('n', 'num', None, _('show local revision number')),
3489 ('n', 'num', None, _('show local revision number')),
3490 ('i', 'id', None, _('show global revision id')),
3490 ('i', 'id', None, _('show global revision id')),
3491 ('b', 'branch', None, _('show branch')),
3491 ('b', 'branch', None, _('show branch')),
3492 ('t', 'tags', None, _('show tags')),
3492 ('t', 'tags', None, _('show tags')),
3493 ('B', 'bookmarks', None, _('show bookmarks')),
3493 ('B', 'bookmarks', None, _('show bookmarks')),
3494 ] + remoteopts,
3494 ] + remoteopts,
3495 _('[-nibtB] [-r REV] [SOURCE]'))
3495 _('[-nibtB] [-r REV] [SOURCE]'))
3496 def identify(ui, repo, source=None, rev=None,
3496 def identify(ui, repo, source=None, rev=None,
3497 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3497 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3498 """identify the working copy or specified revision
3498 """identify the working copy or specified revision
3499
3499
3500 Print a summary identifying the repository state at REV using one or
3500 Print a summary identifying the repository state at REV using one or
3501 two parent hash identifiers, followed by a "+" if the working
3501 two parent hash identifiers, followed by a "+" if the working
3502 directory has uncommitted changes, the branch name (if not default),
3502 directory has uncommitted changes, the branch name (if not default),
3503 a list of tags, and a list of bookmarks.
3503 a list of tags, and a list of bookmarks.
3504
3504
3505 When REV is not given, print a summary of the current state of the
3505 When REV is not given, print a summary of the current state of the
3506 repository.
3506 repository.
3507
3507
3508 Specifying a path to a repository root or Mercurial bundle will
3508 Specifying a path to a repository root or Mercurial bundle will
3509 cause lookup to operate on that repository/bundle.
3509 cause lookup to operate on that repository/bundle.
3510
3510
3511 .. container:: verbose
3511 .. container:: verbose
3512
3512
3513 Examples:
3513 Examples:
3514
3514
3515 - generate a build identifier for the working directory::
3515 - generate a build identifier for the working directory::
3516
3516
3517 hg id --id > build-id.dat
3517 hg id --id > build-id.dat
3518
3518
3519 - find the revision corresponding to a tag::
3519 - find the revision corresponding to a tag::
3520
3520
3521 hg id -n -r 1.3
3521 hg id -n -r 1.3
3522
3522
3523 - check the most recent revision of a remote repository::
3523 - check the most recent revision of a remote repository::
3524
3524
3525 hg id -r tip http://selenic.com/hg/
3525 hg id -r tip http://selenic.com/hg/
3526
3526
3527 Returns 0 if successful.
3527 Returns 0 if successful.
3528 """
3528 """
3529
3529
3530 if not repo and not source:
3530 if not repo and not source:
3531 raise util.Abort(_("there is no Mercurial repository here "
3531 raise util.Abort(_("there is no Mercurial repository here "
3532 "(.hg not found)"))
3532 "(.hg not found)"))
3533
3533
3534 hexfunc = ui.debugflag and hex or short
3534 hexfunc = ui.debugflag and hex or short
3535 default = not (num or id or branch or tags or bookmarks)
3535 default = not (num or id or branch or tags or bookmarks)
3536 output = []
3536 output = []
3537 revs = []
3537 revs = []
3538
3538
3539 if source:
3539 if source:
3540 source, branches = hg.parseurl(ui.expandpath(source))
3540 source, branches = hg.parseurl(ui.expandpath(source))
3541 peer = hg.peer(ui, opts, source)
3541 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3542 repo = peer.local()
3542 repo = peer.local()
3543 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3543 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3544
3544
3545 if not repo:
3545 if not repo:
3546 if num or branch or tags:
3546 if num or branch or tags:
3547 raise util.Abort(
3547 raise util.Abort(
3548 _("can't query remote revision number, branch, or tags"))
3548 _("can't query remote revision number, branch, or tags"))
3549 if not rev and revs:
3549 if not rev and revs:
3550 rev = revs[0]
3550 rev = revs[0]
3551 if not rev:
3551 if not rev:
3552 rev = "tip"
3552 rev = "tip"
3553
3553
3554 remoterev = peer.lookup(rev)
3554 remoterev = peer.lookup(rev)
3555 if default or id:
3555 if default or id:
3556 output = [hexfunc(remoterev)]
3556 output = [hexfunc(remoterev)]
3557
3557
3558 def getbms():
3558 def getbms():
3559 bms = []
3559 bms = []
3560
3560
3561 if 'bookmarks' in peer.listkeys('namespaces'):
3561 if 'bookmarks' in peer.listkeys('namespaces'):
3562 hexremoterev = hex(remoterev)
3562 hexremoterev = hex(remoterev)
3563 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3563 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3564 if bmr == hexremoterev]
3564 if bmr == hexremoterev]
3565
3565
3566 return bms
3566 return bms
3567
3567
3568 if bookmarks:
3568 if bookmarks:
3569 output.extend(getbms())
3569 output.extend(getbms())
3570 elif default and not ui.quiet:
3570 elif default and not ui.quiet:
3571 # multiple bookmarks for a single parent separated by '/'
3571 # multiple bookmarks for a single parent separated by '/'
3572 bm = '/'.join(getbms())
3572 bm = '/'.join(getbms())
3573 if bm:
3573 if bm:
3574 output.append(bm)
3574 output.append(bm)
3575 else:
3575 else:
3576 if not rev:
3576 if not rev:
3577 ctx = repo[None]
3577 ctx = repo[None]
3578 parents = ctx.parents()
3578 parents = ctx.parents()
3579 changed = ""
3579 changed = ""
3580 if default or id or num:
3580 if default or id or num:
3581 if (util.any(repo.status())
3581 if (util.any(repo.status())
3582 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3582 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3583 changed = '+'
3583 changed = '+'
3584 if default or id:
3584 if default or id:
3585 output = ["%s%s" %
3585 output = ["%s%s" %
3586 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3586 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3587 if num:
3587 if num:
3588 output.append("%s%s" %
3588 output.append("%s%s" %
3589 ('+'.join([str(p.rev()) for p in parents]), changed))
3589 ('+'.join([str(p.rev()) for p in parents]), changed))
3590 else:
3590 else:
3591 ctx = scmutil.revsingle(repo, rev)
3591 ctx = scmutil.revsingle(repo, rev)
3592 if default or id:
3592 if default or id:
3593 output = [hexfunc(ctx.node())]
3593 output = [hexfunc(ctx.node())]
3594 if num:
3594 if num:
3595 output.append(str(ctx.rev()))
3595 output.append(str(ctx.rev()))
3596
3596
3597 if default and not ui.quiet:
3597 if default and not ui.quiet:
3598 b = ctx.branch()
3598 b = ctx.branch()
3599 if b != 'default':
3599 if b != 'default':
3600 output.append("(%s)" % b)
3600 output.append("(%s)" % b)
3601
3601
3602 # multiple tags for a single parent separated by '/'
3602 # multiple tags for a single parent separated by '/'
3603 t = '/'.join(ctx.tags())
3603 t = '/'.join(ctx.tags())
3604 if t:
3604 if t:
3605 output.append(t)
3605 output.append(t)
3606
3606
3607 # multiple bookmarks for a single parent separated by '/'
3607 # multiple bookmarks for a single parent separated by '/'
3608 bm = '/'.join(ctx.bookmarks())
3608 bm = '/'.join(ctx.bookmarks())
3609 if bm:
3609 if bm:
3610 output.append(bm)
3610 output.append(bm)
3611 else:
3611 else:
3612 if branch:
3612 if branch:
3613 output.append(ctx.branch())
3613 output.append(ctx.branch())
3614
3614
3615 if tags:
3615 if tags:
3616 output.extend(ctx.tags())
3616 output.extend(ctx.tags())
3617
3617
3618 if bookmarks:
3618 if bookmarks:
3619 output.extend(ctx.bookmarks())
3619 output.extend(ctx.bookmarks())
3620
3620
3621 ui.write("%s\n" % ' '.join(output))
3621 ui.write("%s\n" % ' '.join(output))
3622
3622
3623 @command('import|patch',
3623 @command('import|patch',
3624 [('p', 'strip', 1,
3624 [('p', 'strip', 1,
3625 _('directory strip option for patch. This has the same '
3625 _('directory strip option for patch. This has the same '
3626 'meaning as the corresponding patch option'), _('NUM')),
3626 'meaning as the corresponding patch option'), _('NUM')),
3627 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3627 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3628 ('e', 'edit', False, _('invoke editor on commit messages')),
3628 ('e', 'edit', False, _('invoke editor on commit messages')),
3629 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3629 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3630 ('', 'no-commit', None,
3630 ('', 'no-commit', None,
3631 _("don't commit, just update the working directory")),
3631 _("don't commit, just update the working directory")),
3632 ('', 'bypass', None,
3632 ('', 'bypass', None,
3633 _("apply patch without touching the working directory")),
3633 _("apply patch without touching the working directory")),
3634 ('', 'exact', None,
3634 ('', 'exact', None,
3635 _('apply patch to the nodes from which it was generated')),
3635 _('apply patch to the nodes from which it was generated')),
3636 ('', 'import-branch', None,
3636 ('', 'import-branch', None,
3637 _('use any branch information in patch (implied by --exact)'))] +
3637 _('use any branch information in patch (implied by --exact)'))] +
3638 commitopts + commitopts2 + similarityopts,
3638 commitopts + commitopts2 + similarityopts,
3639 _('[OPTION]... PATCH...'))
3639 _('[OPTION]... PATCH...'))
3640 def import_(ui, repo, patch1=None, *patches, **opts):
3640 def import_(ui, repo, patch1=None, *patches, **opts):
3641 """import an ordered set of patches
3641 """import an ordered set of patches
3642
3642
3643 Import a list of patches and commit them individually (unless
3643 Import a list of patches and commit them individually (unless
3644 --no-commit is specified).
3644 --no-commit is specified).
3645
3645
3646 If there are outstanding changes in the working directory, import
3646 If there are outstanding changes in the working directory, import
3647 will abort unless given the -f/--force flag.
3647 will abort unless given the -f/--force flag.
3648
3648
3649 You can import a patch straight from a mail message. Even patches
3649 You can import a patch straight from a mail message. Even patches
3650 as attachments work (to use the body part, it must have type
3650 as attachments work (to use the body part, it must have type
3651 text/plain or text/x-patch). From and Subject headers of email
3651 text/plain or text/x-patch). From and Subject headers of email
3652 message are used as default committer and commit message. All
3652 message are used as default committer and commit message. All
3653 text/plain body parts before first diff are added to commit
3653 text/plain body parts before first diff are added to commit
3654 message.
3654 message.
3655
3655
3656 If the imported patch was generated by :hg:`export`, user and
3656 If the imported patch was generated by :hg:`export`, user and
3657 description from patch override values from message headers and
3657 description from patch override values from message headers and
3658 body. Values given on command line with -m/--message and -u/--user
3658 body. Values given on command line with -m/--message and -u/--user
3659 override these.
3659 override these.
3660
3660
3661 If --exact is specified, import will set the working directory to
3661 If --exact is specified, import will set the working directory to
3662 the parent of each patch before applying it, and will abort if the
3662 the parent of each patch before applying it, and will abort if the
3663 resulting changeset has a different ID than the one recorded in
3663 resulting changeset has a different ID than the one recorded in
3664 the patch. This may happen due to character set problems or other
3664 the patch. This may happen due to character set problems or other
3665 deficiencies in the text patch format.
3665 deficiencies in the text patch format.
3666
3666
3667 Use --bypass to apply and commit patches directly to the
3667 Use --bypass to apply and commit patches directly to the
3668 repository, not touching the working directory. Without --exact,
3668 repository, not touching the working directory. Without --exact,
3669 patches will be applied on top of the working directory parent
3669 patches will be applied on top of the working directory parent
3670 revision.
3670 revision.
3671
3671
3672 With -s/--similarity, hg will attempt to discover renames and
3672 With -s/--similarity, hg will attempt to discover renames and
3673 copies in the patch in the same way as :hg:`addremove`.
3673 copies in the patch in the same way as :hg:`addremove`.
3674
3674
3675 To read a patch from standard input, use "-" as the patch name. If
3675 To read a patch from standard input, use "-" as the patch name. If
3676 a URL is specified, the patch will be downloaded from it.
3676 a URL is specified, the patch will be downloaded from it.
3677 See :hg:`help dates` for a list of formats valid for -d/--date.
3677 See :hg:`help dates` for a list of formats valid for -d/--date.
3678
3678
3679 .. container:: verbose
3679 .. container:: verbose
3680
3680
3681 Examples:
3681 Examples:
3682
3682
3683 - import a traditional patch from a website and detect renames::
3683 - import a traditional patch from a website and detect renames::
3684
3684
3685 hg import -s 80 http://example.com/bugfix.patch
3685 hg import -s 80 http://example.com/bugfix.patch
3686
3686
3687 - import a changeset from an hgweb server::
3687 - import a changeset from an hgweb server::
3688
3688
3689 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3689 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3690
3690
3691 - import all the patches in an Unix-style mbox::
3691 - import all the patches in an Unix-style mbox::
3692
3692
3693 hg import incoming-patches.mbox
3693 hg import incoming-patches.mbox
3694
3694
3695 - attempt to exactly restore an exported changeset (not always
3695 - attempt to exactly restore an exported changeset (not always
3696 possible)::
3696 possible)::
3697
3697
3698 hg import --exact proposed-fix.patch
3698 hg import --exact proposed-fix.patch
3699
3699
3700 Returns 0 on success.
3700 Returns 0 on success.
3701 """
3701 """
3702
3702
3703 if not patch1:
3703 if not patch1:
3704 raise util.Abort(_('need at least one patch to import'))
3704 raise util.Abort(_('need at least one patch to import'))
3705
3705
3706 patches = (patch1,) + patches
3706 patches = (patch1,) + patches
3707
3707
3708 date = opts.get('date')
3708 date = opts.get('date')
3709 if date:
3709 if date:
3710 opts['date'] = util.parsedate(date)
3710 opts['date'] = util.parsedate(date)
3711
3711
3712 editor = cmdutil.commiteditor
3712 editor = cmdutil.commiteditor
3713 if opts.get('edit'):
3713 if opts.get('edit'):
3714 editor = cmdutil.commitforceeditor
3714 editor = cmdutil.commitforceeditor
3715
3715
3716 update = not opts.get('bypass')
3716 update = not opts.get('bypass')
3717 if not update and opts.get('no_commit'):
3717 if not update and opts.get('no_commit'):
3718 raise util.Abort(_('cannot use --no-commit with --bypass'))
3718 raise util.Abort(_('cannot use --no-commit with --bypass'))
3719 try:
3719 try:
3720 sim = float(opts.get('similarity') or 0)
3720 sim = float(opts.get('similarity') or 0)
3721 except ValueError:
3721 except ValueError:
3722 raise util.Abort(_('similarity must be a number'))
3722 raise util.Abort(_('similarity must be a number'))
3723 if sim < 0 or sim > 100:
3723 if sim < 0 or sim > 100:
3724 raise util.Abort(_('similarity must be between 0 and 100'))
3724 raise util.Abort(_('similarity must be between 0 and 100'))
3725 if sim and not update:
3725 if sim and not update:
3726 raise util.Abort(_('cannot use --similarity with --bypass'))
3726 raise util.Abort(_('cannot use --similarity with --bypass'))
3727
3727
3728 if (opts.get('exact') or not opts.get('force')) and update:
3728 if (opts.get('exact') or not opts.get('force')) and update:
3729 cmdutil.bailifchanged(repo)
3729 cmdutil.bailifchanged(repo)
3730
3730
3731 base = opts["base"]
3731 base = opts["base"]
3732 strip = opts["strip"]
3732 strip = opts["strip"]
3733 wlock = lock = tr = None
3733 wlock = lock = tr = None
3734 msgs = []
3734 msgs = []
3735
3735
3736 def checkexact(repo, n, nodeid):
3736 def checkexact(repo, n, nodeid):
3737 if opts.get('exact') and hex(n) != nodeid:
3737 if opts.get('exact') and hex(n) != nodeid:
3738 repo.rollback()
3738 repo.rollback()
3739 raise util.Abort(_('patch is damaged or loses information'))
3739 raise util.Abort(_('patch is damaged or loses information'))
3740
3740
3741 def tryone(ui, hunk, parents):
3741 def tryone(ui, hunk, parents):
3742 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3742 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3743 patch.extract(ui, hunk)
3743 patch.extract(ui, hunk)
3744
3744
3745 if not tmpname:
3745 if not tmpname:
3746 return (None, None)
3746 return (None, None)
3747 msg = _('applied to working directory')
3747 msg = _('applied to working directory')
3748
3748
3749 try:
3749 try:
3750 cmdline_message = cmdutil.logmessage(ui, opts)
3750 cmdline_message = cmdutil.logmessage(ui, opts)
3751 if cmdline_message:
3751 if cmdline_message:
3752 # pickup the cmdline msg
3752 # pickup the cmdline msg
3753 message = cmdline_message
3753 message = cmdline_message
3754 elif message:
3754 elif message:
3755 # pickup the patch msg
3755 # pickup the patch msg
3756 message = message.strip()
3756 message = message.strip()
3757 else:
3757 else:
3758 # launch the editor
3758 # launch the editor
3759 message = None
3759 message = None
3760 ui.debug('message:\n%s\n' % message)
3760 ui.debug('message:\n%s\n' % message)
3761
3761
3762 if len(parents) == 1:
3762 if len(parents) == 1:
3763 parents.append(repo[nullid])
3763 parents.append(repo[nullid])
3764 if opts.get('exact'):
3764 if opts.get('exact'):
3765 if not nodeid or not p1:
3765 if not nodeid or not p1:
3766 raise util.Abort(_('not a Mercurial patch'))
3766 raise util.Abort(_('not a Mercurial patch'))
3767 p1 = repo[p1]
3767 p1 = repo[p1]
3768 p2 = repo[p2 or nullid]
3768 p2 = repo[p2 or nullid]
3769 elif p2:
3769 elif p2:
3770 try:
3770 try:
3771 p1 = repo[p1]
3771 p1 = repo[p1]
3772 p2 = repo[p2]
3772 p2 = repo[p2]
3773 # Without any options, consider p2 only if the
3773 # Without any options, consider p2 only if the
3774 # patch is being applied on top of the recorded
3774 # patch is being applied on top of the recorded
3775 # first parent.
3775 # first parent.
3776 if p1 != parents[0]:
3776 if p1 != parents[0]:
3777 p1 = parents[0]
3777 p1 = parents[0]
3778 p2 = repo[nullid]
3778 p2 = repo[nullid]
3779 except error.RepoError:
3779 except error.RepoError:
3780 p1, p2 = parents
3780 p1, p2 = parents
3781 else:
3781 else:
3782 p1, p2 = parents
3782 p1, p2 = parents
3783
3783
3784 n = None
3784 n = None
3785 if update:
3785 if update:
3786 if p1 != parents[0]:
3786 if p1 != parents[0]:
3787 hg.clean(repo, p1.node())
3787 hg.clean(repo, p1.node())
3788 if p2 != parents[1]:
3788 if p2 != parents[1]:
3789 repo.setparents(p1.node(), p2.node())
3789 repo.setparents(p1.node(), p2.node())
3790
3790
3791 if opts.get('exact') or opts.get('import_branch'):
3791 if opts.get('exact') or opts.get('import_branch'):
3792 repo.dirstate.setbranch(branch or 'default')
3792 repo.dirstate.setbranch(branch or 'default')
3793
3793
3794 files = set()
3794 files = set()
3795 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3795 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3796 eolmode=None, similarity=sim / 100.0)
3796 eolmode=None, similarity=sim / 100.0)
3797 files = list(files)
3797 files = list(files)
3798 if opts.get('no_commit'):
3798 if opts.get('no_commit'):
3799 if message:
3799 if message:
3800 msgs.append(message)
3800 msgs.append(message)
3801 else:
3801 else:
3802 if opts.get('exact') or p2:
3802 if opts.get('exact') or p2:
3803 # If you got here, you either use --force and know what
3803 # If you got here, you either use --force and know what
3804 # you are doing or used --exact or a merge patch while
3804 # you are doing or used --exact or a merge patch while
3805 # being updated to its first parent.
3805 # being updated to its first parent.
3806 m = None
3806 m = None
3807 else:
3807 else:
3808 m = scmutil.matchfiles(repo, files or [])
3808 m = scmutil.matchfiles(repo, files or [])
3809 n = repo.commit(message, opts.get('user') or user,
3809 n = repo.commit(message, opts.get('user') or user,
3810 opts.get('date') or date, match=m,
3810 opts.get('date') or date, match=m,
3811 editor=editor)
3811 editor=editor)
3812 checkexact(repo, n, nodeid)
3812 checkexact(repo, n, nodeid)
3813 else:
3813 else:
3814 if opts.get('exact') or opts.get('import_branch'):
3814 if opts.get('exact') or opts.get('import_branch'):
3815 branch = branch or 'default'
3815 branch = branch or 'default'
3816 else:
3816 else:
3817 branch = p1.branch()
3817 branch = p1.branch()
3818 store = patch.filestore()
3818 store = patch.filestore()
3819 try:
3819 try:
3820 files = set()
3820 files = set()
3821 try:
3821 try:
3822 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3822 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3823 files, eolmode=None)
3823 files, eolmode=None)
3824 except patch.PatchError, e:
3824 except patch.PatchError, e:
3825 raise util.Abort(str(e))
3825 raise util.Abort(str(e))
3826 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3826 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3827 message,
3827 message,
3828 opts.get('user') or user,
3828 opts.get('user') or user,
3829 opts.get('date') or date,
3829 opts.get('date') or date,
3830 branch, files, store,
3830 branch, files, store,
3831 editor=cmdutil.commiteditor)
3831 editor=cmdutil.commiteditor)
3832 repo.savecommitmessage(memctx.description())
3832 repo.savecommitmessage(memctx.description())
3833 n = memctx.commit()
3833 n = memctx.commit()
3834 checkexact(repo, n, nodeid)
3834 checkexact(repo, n, nodeid)
3835 finally:
3835 finally:
3836 store.close()
3836 store.close()
3837 if n:
3837 if n:
3838 # i18n: refers to a short changeset id
3838 # i18n: refers to a short changeset id
3839 msg = _('created %s') % short(n)
3839 msg = _('created %s') % short(n)
3840 return (msg, n)
3840 return (msg, n)
3841 finally:
3841 finally:
3842 os.unlink(tmpname)
3842 os.unlink(tmpname)
3843
3843
3844 try:
3844 try:
3845 try:
3845 try:
3846 wlock = repo.wlock()
3846 wlock = repo.wlock()
3847 if not opts.get('no_commit'):
3847 if not opts.get('no_commit'):
3848 lock = repo.lock()
3848 lock = repo.lock()
3849 tr = repo.transaction('import')
3849 tr = repo.transaction('import')
3850 parents = repo.parents()
3850 parents = repo.parents()
3851 for patchurl in patches:
3851 for patchurl in patches:
3852 if patchurl == '-':
3852 if patchurl == '-':
3853 ui.status(_('applying patch from stdin\n'))
3853 ui.status(_('applying patch from stdin\n'))
3854 patchfile = ui.fin
3854 patchfile = ui.fin
3855 patchurl = 'stdin' # for error message
3855 patchurl = 'stdin' # for error message
3856 else:
3856 else:
3857 patchurl = os.path.join(base, patchurl)
3857 patchurl = os.path.join(base, patchurl)
3858 ui.status(_('applying %s\n') % patchurl)
3858 ui.status(_('applying %s\n') % patchurl)
3859 patchfile = url.open(ui, patchurl)
3859 patchfile = url.open(ui, patchurl)
3860
3860
3861 haspatch = False
3861 haspatch = False
3862 for hunk in patch.split(patchfile):
3862 for hunk in patch.split(patchfile):
3863 (msg, node) = tryone(ui, hunk, parents)
3863 (msg, node) = tryone(ui, hunk, parents)
3864 if msg:
3864 if msg:
3865 haspatch = True
3865 haspatch = True
3866 ui.note(msg + '\n')
3866 ui.note(msg + '\n')
3867 if update or opts.get('exact'):
3867 if update or opts.get('exact'):
3868 parents = repo.parents()
3868 parents = repo.parents()
3869 else:
3869 else:
3870 parents = [repo[node]]
3870 parents = [repo[node]]
3871
3871
3872 if not haspatch:
3872 if not haspatch:
3873 raise util.Abort(_('%s: no diffs found') % patchurl)
3873 raise util.Abort(_('%s: no diffs found') % patchurl)
3874
3874
3875 if tr:
3875 if tr:
3876 tr.close()
3876 tr.close()
3877 if msgs:
3877 if msgs:
3878 repo.savecommitmessage('\n* * *\n'.join(msgs))
3878 repo.savecommitmessage('\n* * *\n'.join(msgs))
3879 except: # re-raises
3879 except: # re-raises
3880 # wlock.release() indirectly calls dirstate.write(): since
3880 # wlock.release() indirectly calls dirstate.write(): since
3881 # we're crashing, we do not want to change the working dir
3881 # we're crashing, we do not want to change the working dir
3882 # parent after all, so make sure it writes nothing
3882 # parent after all, so make sure it writes nothing
3883 repo.dirstate.invalidate()
3883 repo.dirstate.invalidate()
3884 raise
3884 raise
3885 finally:
3885 finally:
3886 if tr:
3886 if tr:
3887 tr.release()
3887 tr.release()
3888 release(lock, wlock)
3888 release(lock, wlock)
3889
3889
3890 @command('incoming|in',
3890 @command('incoming|in',
3891 [('f', 'force', None,
3891 [('f', 'force', None,
3892 _('run even if remote repository is unrelated')),
3892 _('run even if remote repository is unrelated')),
3893 ('n', 'newest-first', None, _('show newest record first')),
3893 ('n', 'newest-first', None, _('show newest record first')),
3894 ('', 'bundle', '',
3894 ('', 'bundle', '',
3895 _('file to store the bundles into'), _('FILE')),
3895 _('file to store the bundles into'), _('FILE')),
3896 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3896 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3897 ('B', 'bookmarks', False, _("compare bookmarks")),
3897 ('B', 'bookmarks', False, _("compare bookmarks")),
3898 ('b', 'branch', [],
3898 ('b', 'branch', [],
3899 _('a specific branch you would like to pull'), _('BRANCH')),
3899 _('a specific branch you would like to pull'), _('BRANCH')),
3900 ] + logopts + remoteopts + subrepoopts,
3900 ] + logopts + remoteopts + subrepoopts,
3901 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3901 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3902 def incoming(ui, repo, source="default", **opts):
3902 def incoming(ui, repo, source="default", **opts):
3903 """show new changesets found in source
3903 """show new changesets found in source
3904
3904
3905 Show new changesets found in the specified path/URL or the default
3905 Show new changesets found in the specified path/URL or the default
3906 pull location. These are the changesets that would have been pulled
3906 pull location. These are the changesets that would have been pulled
3907 if a pull at the time you issued this command.
3907 if a pull at the time you issued this command.
3908
3908
3909 For remote repository, using --bundle avoids downloading the
3909 For remote repository, using --bundle avoids downloading the
3910 changesets twice if the incoming is followed by a pull.
3910 changesets twice if the incoming is followed by a pull.
3911
3911
3912 See pull for valid source format details.
3912 See pull for valid source format details.
3913
3913
3914 Returns 0 if there are incoming changes, 1 otherwise.
3914 Returns 0 if there are incoming changes, 1 otherwise.
3915 """
3915 """
3916 if opts.get('graph'):
3916 if opts.get('graph'):
3917 cmdutil.checkunsupportedgraphflags([], opts)
3917 cmdutil.checkunsupportedgraphflags([], opts)
3918 def display(other, chlist, displayer):
3918 def display(other, chlist, displayer):
3919 revdag = cmdutil.graphrevs(other, chlist, opts)
3919 revdag = cmdutil.graphrevs(other, chlist, opts)
3920 showparents = [ctx.node() for ctx in repo[None].parents()]
3920 showparents = [ctx.node() for ctx in repo[None].parents()]
3921 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3921 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3922 graphmod.asciiedges)
3922 graphmod.asciiedges)
3923
3923
3924 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3924 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3925 return 0
3925 return 0
3926
3926
3927 if opts.get('bundle') and opts.get('subrepos'):
3927 if opts.get('bundle') and opts.get('subrepos'):
3928 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3928 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3929
3929
3930 if opts.get('bookmarks'):
3930 if opts.get('bookmarks'):
3931 source, branches = hg.parseurl(ui.expandpath(source),
3931 source, branches = hg.parseurl(ui.expandpath(source),
3932 opts.get('branch'))
3932 opts.get('branch'))
3933 other = hg.peer(repo, opts, source)
3933 other = hg.peer(repo, opts, source)
3934 if 'bookmarks' not in other.listkeys('namespaces'):
3934 if 'bookmarks' not in other.listkeys('namespaces'):
3935 ui.warn(_("remote doesn't support bookmarks\n"))
3935 ui.warn(_("remote doesn't support bookmarks\n"))
3936 return 0
3936 return 0
3937 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3937 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3938 return bookmarks.diff(ui, repo, other)
3938 return bookmarks.diff(ui, repo, other)
3939
3939
3940 repo._subtoppath = ui.expandpath(source)
3940 repo._subtoppath = ui.expandpath(source)
3941 try:
3941 try:
3942 return hg.incoming(ui, repo, source, opts)
3942 return hg.incoming(ui, repo, source, opts)
3943 finally:
3943 finally:
3944 del repo._subtoppath
3944 del repo._subtoppath
3945
3945
3946
3946
3947 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3947 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3948 def init(ui, dest=".", **opts):
3948 def init(ui, dest=".", **opts):
3949 """create a new repository in the given directory
3949 """create a new repository in the given directory
3950
3950
3951 Initialize a new repository in the given directory. If the given
3951 Initialize a new repository in the given directory. If the given
3952 directory does not exist, it will be created.
3952 directory does not exist, it will be created.
3953
3953
3954 If no directory is given, the current directory is used.
3954 If no directory is given, the current directory is used.
3955
3955
3956 It is possible to specify an ``ssh://`` URL as the destination.
3956 It is possible to specify an ``ssh://`` URL as the destination.
3957 See :hg:`help urls` for more information.
3957 See :hg:`help urls` for more information.
3958
3958
3959 Returns 0 on success.
3959 Returns 0 on success.
3960 """
3960 """
3961 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3961 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3962
3962
3963 @command('locate',
3963 @command('locate',
3964 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3964 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3965 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3965 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3966 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3966 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3967 ] + walkopts,
3967 ] + walkopts,
3968 _('[OPTION]... [PATTERN]...'))
3968 _('[OPTION]... [PATTERN]...'))
3969 def locate(ui, repo, *pats, **opts):
3969 def locate(ui, repo, *pats, **opts):
3970 """locate files matching specific patterns
3970 """locate files matching specific patterns
3971
3971
3972 Print files under Mercurial control in the working directory whose
3972 Print files under Mercurial control in the working directory whose
3973 names match the given patterns.
3973 names match the given patterns.
3974
3974
3975 By default, this command searches all directories in the working
3975 By default, this command searches all directories in the working
3976 directory. To search just the current directory and its
3976 directory. To search just the current directory and its
3977 subdirectories, use "--include .".
3977 subdirectories, use "--include .".
3978
3978
3979 If no patterns are given to match, this command prints the names
3979 If no patterns are given to match, this command prints the names
3980 of all files under Mercurial control in the working directory.
3980 of all files under Mercurial control in the working directory.
3981
3981
3982 If you want to feed the output of this command into the "xargs"
3982 If you want to feed the output of this command into the "xargs"
3983 command, use the -0 option to both this command and "xargs". This
3983 command, use the -0 option to both this command and "xargs". This
3984 will avoid the problem of "xargs" treating single filenames that
3984 will avoid the problem of "xargs" treating single filenames that
3985 contain whitespace as multiple filenames.
3985 contain whitespace as multiple filenames.
3986
3986
3987 Returns 0 if a match is found, 1 otherwise.
3987 Returns 0 if a match is found, 1 otherwise.
3988 """
3988 """
3989 end = opts.get('print0') and '\0' or '\n'
3989 end = opts.get('print0') and '\0' or '\n'
3990 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3990 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3991
3991
3992 ret = 1
3992 ret = 1
3993 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3993 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3994 m.bad = lambda x, y: False
3994 m.bad = lambda x, y: False
3995 for abs in repo[rev].walk(m):
3995 for abs in repo[rev].walk(m):
3996 if not rev and abs not in repo.dirstate:
3996 if not rev and abs not in repo.dirstate:
3997 continue
3997 continue
3998 if opts.get('fullpath'):
3998 if opts.get('fullpath'):
3999 ui.write(repo.wjoin(abs), end)
3999 ui.write(repo.wjoin(abs), end)
4000 else:
4000 else:
4001 ui.write(((pats and m.rel(abs)) or abs), end)
4001 ui.write(((pats and m.rel(abs)) or abs), end)
4002 ret = 0
4002 ret = 0
4003
4003
4004 return ret
4004 return ret
4005
4005
4006 @command('^log|history',
4006 @command('^log|history',
4007 [('f', 'follow', None,
4007 [('f', 'follow', None,
4008 _('follow changeset history, or file history across copies and renames')),
4008 _('follow changeset history, or file history across copies and renames')),
4009 ('', 'follow-first', None,
4009 ('', 'follow-first', None,
4010 _('only follow the first parent of merge changesets (DEPRECATED)')),
4010 _('only follow the first parent of merge changesets (DEPRECATED)')),
4011 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4011 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4012 ('C', 'copies', None, _('show copied files')),
4012 ('C', 'copies', None, _('show copied files')),
4013 ('k', 'keyword', [],
4013 ('k', 'keyword', [],
4014 _('do case-insensitive search for a given text'), _('TEXT')),
4014 _('do case-insensitive search for a given text'), _('TEXT')),
4015 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4015 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4016 ('', 'removed', None, _('include revisions where files were removed')),
4016 ('', 'removed', None, _('include revisions where files were removed')),
4017 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4017 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4018 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4018 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4019 ('', 'only-branch', [],
4019 ('', 'only-branch', [],
4020 _('show only changesets within the given named branch (DEPRECATED)'),
4020 _('show only changesets within the given named branch (DEPRECATED)'),
4021 _('BRANCH')),
4021 _('BRANCH')),
4022 ('b', 'branch', [],
4022 ('b', 'branch', [],
4023 _('show changesets within the given named branch'), _('BRANCH')),
4023 _('show changesets within the given named branch'), _('BRANCH')),
4024 ('P', 'prune', [],
4024 ('P', 'prune', [],
4025 _('do not display revision or any of its ancestors'), _('REV')),
4025 _('do not display revision or any of its ancestors'), _('REV')),
4026 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4026 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4027 ] + logopts + walkopts,
4027 ] + logopts + walkopts,
4028 _('[OPTION]... [FILE]'))
4028 _('[OPTION]... [FILE]'))
4029 def log(ui, repo, *pats, **opts):
4029 def log(ui, repo, *pats, **opts):
4030 """show revision history of entire repository or files
4030 """show revision history of entire repository or files
4031
4031
4032 Print the revision history of the specified files or the entire
4032 Print the revision history of the specified files or the entire
4033 project.
4033 project.
4034
4034
4035 If no revision range is specified, the default is ``tip:0`` unless
4035 If no revision range is specified, the default is ``tip:0`` unless
4036 --follow is set, in which case the working directory parent is
4036 --follow is set, in which case the working directory parent is
4037 used as the starting revision.
4037 used as the starting revision.
4038
4038
4039 File history is shown without following rename or copy history of
4039 File history is shown without following rename or copy history of
4040 files. Use -f/--follow with a filename to follow history across
4040 files. Use -f/--follow with a filename to follow history across
4041 renames and copies. --follow without a filename will only show
4041 renames and copies. --follow without a filename will only show
4042 ancestors or descendants of the starting revision.
4042 ancestors or descendants of the starting revision.
4043
4043
4044 By default this command prints revision number and changeset id,
4044 By default this command prints revision number and changeset id,
4045 tags, non-trivial parents, user, date and time, and a summary for
4045 tags, non-trivial parents, user, date and time, and a summary for
4046 each commit. When the -v/--verbose switch is used, the list of
4046 each commit. When the -v/--verbose switch is used, the list of
4047 changed files and full commit message are shown.
4047 changed files and full commit message are shown.
4048
4048
4049 .. note::
4049 .. note::
4050 log -p/--patch may generate unexpected diff output for merge
4050 log -p/--patch may generate unexpected diff output for merge
4051 changesets, as it will only compare the merge changeset against
4051 changesets, as it will only compare the merge changeset against
4052 its first parent. Also, only files different from BOTH parents
4052 its first parent. Also, only files different from BOTH parents
4053 will appear in files:.
4053 will appear in files:.
4054
4054
4055 .. note::
4055 .. note::
4056 for performance reasons, log FILE may omit duplicate changes
4056 for performance reasons, log FILE may omit duplicate changes
4057 made on branches and will not show deletions. To see all
4057 made on branches and will not show deletions. To see all
4058 changes including duplicates and deletions, use the --removed
4058 changes including duplicates and deletions, use the --removed
4059 switch.
4059 switch.
4060
4060
4061 .. container:: verbose
4061 .. container:: verbose
4062
4062
4063 Some examples:
4063 Some examples:
4064
4064
4065 - changesets with full descriptions and file lists::
4065 - changesets with full descriptions and file lists::
4066
4066
4067 hg log -v
4067 hg log -v
4068
4068
4069 - changesets ancestral to the working directory::
4069 - changesets ancestral to the working directory::
4070
4070
4071 hg log -f
4071 hg log -f
4072
4072
4073 - last 10 commits on the current branch::
4073 - last 10 commits on the current branch::
4074
4074
4075 hg log -l 10 -b .
4075 hg log -l 10 -b .
4076
4076
4077 - changesets showing all modifications of a file, including removals::
4077 - changesets showing all modifications of a file, including removals::
4078
4078
4079 hg log --removed file.c
4079 hg log --removed file.c
4080
4080
4081 - all changesets that touch a directory, with diffs, excluding merges::
4081 - all changesets that touch a directory, with diffs, excluding merges::
4082
4082
4083 hg log -Mp lib/
4083 hg log -Mp lib/
4084
4084
4085 - all revision numbers that match a keyword::
4085 - all revision numbers that match a keyword::
4086
4086
4087 hg log -k bug --template "{rev}\\n"
4087 hg log -k bug --template "{rev}\\n"
4088
4088
4089 - check if a given changeset is included is a tagged release::
4089 - check if a given changeset is included is a tagged release::
4090
4090
4091 hg log -r "a21ccf and ancestor(1.9)"
4091 hg log -r "a21ccf and ancestor(1.9)"
4092
4092
4093 - find all changesets by some user in a date range::
4093 - find all changesets by some user in a date range::
4094
4094
4095 hg log -k alice -d "may 2008 to jul 2008"
4095 hg log -k alice -d "may 2008 to jul 2008"
4096
4096
4097 - summary of all changesets after the last tag::
4097 - summary of all changesets after the last tag::
4098
4098
4099 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4099 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4100
4100
4101 See :hg:`help dates` for a list of formats valid for -d/--date.
4101 See :hg:`help dates` for a list of formats valid for -d/--date.
4102
4102
4103 See :hg:`help revisions` and :hg:`help revsets` for more about
4103 See :hg:`help revisions` and :hg:`help revsets` for more about
4104 specifying revisions.
4104 specifying revisions.
4105
4105
4106 See :hg:`help templates` for more about pre-packaged styles and
4106 See :hg:`help templates` for more about pre-packaged styles and
4107 specifying custom templates.
4107 specifying custom templates.
4108
4108
4109 Returns 0 on success.
4109 Returns 0 on success.
4110 """
4110 """
4111 if opts.get('graph'):
4111 if opts.get('graph'):
4112 return cmdutil.graphlog(ui, repo, *pats, **opts)
4112 return cmdutil.graphlog(ui, repo, *pats, **opts)
4113
4113
4114 matchfn = scmutil.match(repo[None], pats, opts)
4114 matchfn = scmutil.match(repo[None], pats, opts)
4115 limit = cmdutil.loglimit(opts)
4115 limit = cmdutil.loglimit(opts)
4116 count = 0
4116 count = 0
4117
4117
4118 getrenamed, endrev = None, None
4118 getrenamed, endrev = None, None
4119 if opts.get('copies'):
4119 if opts.get('copies'):
4120 if opts.get('rev'):
4120 if opts.get('rev'):
4121 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4121 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4122 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4122 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4123
4123
4124 df = False
4124 df = False
4125 if opts.get("date"):
4125 if opts.get("date"):
4126 df = util.matchdate(opts["date"])
4126 df = util.matchdate(opts["date"])
4127
4127
4128 branches = opts.get('branch', []) + opts.get('only_branch', [])
4128 branches = opts.get('branch', []) + opts.get('only_branch', [])
4129 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4129 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4130
4130
4131 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4131 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4132 def prep(ctx, fns):
4132 def prep(ctx, fns):
4133 rev = ctx.rev()
4133 rev = ctx.rev()
4134 parents = [p for p in repo.changelog.parentrevs(rev)
4134 parents = [p for p in repo.changelog.parentrevs(rev)
4135 if p != nullrev]
4135 if p != nullrev]
4136 if opts.get('no_merges') and len(parents) == 2:
4136 if opts.get('no_merges') and len(parents) == 2:
4137 return
4137 return
4138 if opts.get('only_merges') and len(parents) != 2:
4138 if opts.get('only_merges') and len(parents) != 2:
4139 return
4139 return
4140 if opts.get('branch') and ctx.branch() not in opts['branch']:
4140 if opts.get('branch') and ctx.branch() not in opts['branch']:
4141 return
4141 return
4142 if not opts.get('hidden') and ctx.hidden():
4142 if not opts.get('hidden') and ctx.hidden():
4143 return
4143 return
4144 if df and not df(ctx.date()[0]):
4144 if df and not df(ctx.date()[0]):
4145 return
4145 return
4146
4146
4147 lower = encoding.lower
4147 lower = encoding.lower
4148 if opts.get('user'):
4148 if opts.get('user'):
4149 luser = lower(ctx.user())
4149 luser = lower(ctx.user())
4150 for k in [lower(x) for x in opts['user']]:
4150 for k in [lower(x) for x in opts['user']]:
4151 if (k in luser):
4151 if (k in luser):
4152 break
4152 break
4153 else:
4153 else:
4154 return
4154 return
4155 if opts.get('keyword'):
4155 if opts.get('keyword'):
4156 luser = lower(ctx.user())
4156 luser = lower(ctx.user())
4157 ldesc = lower(ctx.description())
4157 ldesc = lower(ctx.description())
4158 lfiles = lower(" ".join(ctx.files()))
4158 lfiles = lower(" ".join(ctx.files()))
4159 for k in [lower(x) for x in opts['keyword']]:
4159 for k in [lower(x) for x in opts['keyword']]:
4160 if (k in luser or k in ldesc or k in lfiles):
4160 if (k in luser or k in ldesc or k in lfiles):
4161 break
4161 break
4162 else:
4162 else:
4163 return
4163 return
4164
4164
4165 copies = None
4165 copies = None
4166 if getrenamed is not None and rev:
4166 if getrenamed is not None and rev:
4167 copies = []
4167 copies = []
4168 for fn in ctx.files():
4168 for fn in ctx.files():
4169 rename = getrenamed(fn, rev)
4169 rename = getrenamed(fn, rev)
4170 if rename:
4170 if rename:
4171 copies.append((fn, rename[0]))
4171 copies.append((fn, rename[0]))
4172
4172
4173 revmatchfn = None
4173 revmatchfn = None
4174 if opts.get('patch') or opts.get('stat'):
4174 if opts.get('patch') or opts.get('stat'):
4175 if opts.get('follow') or opts.get('follow_first'):
4175 if opts.get('follow') or opts.get('follow_first'):
4176 # note: this might be wrong when following through merges
4176 # note: this might be wrong when following through merges
4177 revmatchfn = scmutil.match(repo[None], fns, default='path')
4177 revmatchfn = scmutil.match(repo[None], fns, default='path')
4178 else:
4178 else:
4179 revmatchfn = matchfn
4179 revmatchfn = matchfn
4180
4180
4181 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4181 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4182
4182
4183 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4183 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4184 if count == limit:
4184 if count == limit:
4185 break
4185 break
4186 if displayer.flush(ctx.rev()):
4186 if displayer.flush(ctx.rev()):
4187 count += 1
4187 count += 1
4188 displayer.close()
4188 displayer.close()
4189
4189
4190 @command('manifest',
4190 @command('manifest',
4191 [('r', 'rev', '', _('revision to display'), _('REV')),
4191 [('r', 'rev', '', _('revision to display'), _('REV')),
4192 ('', 'all', False, _("list files from all revisions"))],
4192 ('', 'all', False, _("list files from all revisions"))],
4193 _('[-r REV]'))
4193 _('[-r REV]'))
4194 def manifest(ui, repo, node=None, rev=None, **opts):
4194 def manifest(ui, repo, node=None, rev=None, **opts):
4195 """output the current or given revision of the project manifest
4195 """output the current or given revision of the project manifest
4196
4196
4197 Print a list of version controlled files for the given revision.
4197 Print a list of version controlled files for the given revision.
4198 If no revision is given, the first parent of the working directory
4198 If no revision is given, the first parent of the working directory
4199 is used, or the null revision if no revision is checked out.
4199 is used, or the null revision if no revision is checked out.
4200
4200
4201 With -v, print file permissions, symlink and executable bits.
4201 With -v, print file permissions, symlink and executable bits.
4202 With --debug, print file revision hashes.
4202 With --debug, print file revision hashes.
4203
4203
4204 If option --all is specified, the list of all files from all revisions
4204 If option --all is specified, the list of all files from all revisions
4205 is printed. This includes deleted and renamed files.
4205 is printed. This includes deleted and renamed files.
4206
4206
4207 Returns 0 on success.
4207 Returns 0 on success.
4208 """
4208 """
4209 if opts.get('all'):
4209 if opts.get('all'):
4210 if rev or node:
4210 if rev or node:
4211 raise util.Abort(_("can't specify a revision with --all"))
4211 raise util.Abort(_("can't specify a revision with --all"))
4212
4212
4213 res = []
4213 res = []
4214 prefix = "data/"
4214 prefix = "data/"
4215 suffix = ".i"
4215 suffix = ".i"
4216 plen = len(prefix)
4216 plen = len(prefix)
4217 slen = len(suffix)
4217 slen = len(suffix)
4218 lock = repo.lock()
4218 lock = repo.lock()
4219 try:
4219 try:
4220 for fn, b, size in repo.store.datafiles():
4220 for fn, b, size in repo.store.datafiles():
4221 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4221 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4222 res.append(fn[plen:-slen])
4222 res.append(fn[plen:-slen])
4223 finally:
4223 finally:
4224 lock.release()
4224 lock.release()
4225 for f in res:
4225 for f in res:
4226 ui.write("%s\n" % f)
4226 ui.write("%s\n" % f)
4227 return
4227 return
4228
4228
4229 if rev and node:
4229 if rev and node:
4230 raise util.Abort(_("please specify just one revision"))
4230 raise util.Abort(_("please specify just one revision"))
4231
4231
4232 if not node:
4232 if not node:
4233 node = rev
4233 node = rev
4234
4234
4235 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4235 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4236 ctx = scmutil.revsingle(repo, node)
4236 ctx = scmutil.revsingle(repo, node)
4237 for f in ctx:
4237 for f in ctx:
4238 if ui.debugflag:
4238 if ui.debugflag:
4239 ui.write("%40s " % hex(ctx.manifest()[f]))
4239 ui.write("%40s " % hex(ctx.manifest()[f]))
4240 if ui.verbose:
4240 if ui.verbose:
4241 ui.write(decor[ctx.flags(f)])
4241 ui.write(decor[ctx.flags(f)])
4242 ui.write("%s\n" % f)
4242 ui.write("%s\n" % f)
4243
4243
4244 @command('^merge',
4244 @command('^merge',
4245 [('f', 'force', None, _('force a merge with outstanding changes')),
4245 [('f', 'force', None, _('force a merge with outstanding changes')),
4246 ('r', 'rev', '', _('revision to merge'), _('REV')),
4246 ('r', 'rev', '', _('revision to merge'), _('REV')),
4247 ('P', 'preview', None,
4247 ('P', 'preview', None,
4248 _('review revisions to merge (no merge is performed)'))
4248 _('review revisions to merge (no merge is performed)'))
4249 ] + mergetoolopts,
4249 ] + mergetoolopts,
4250 _('[-P] [-f] [[-r] REV]'))
4250 _('[-P] [-f] [[-r] REV]'))
4251 def merge(ui, repo, node=None, **opts):
4251 def merge(ui, repo, node=None, **opts):
4252 """merge working directory with another revision
4252 """merge working directory with another revision
4253
4253
4254 The current working directory is updated with all changes made in
4254 The current working directory is updated with all changes made in
4255 the requested revision since the last common predecessor revision.
4255 the requested revision since the last common predecessor revision.
4256
4256
4257 Files that changed between either parent are marked as changed for
4257 Files that changed between either parent are marked as changed for
4258 the next commit and a commit must be performed before any further
4258 the next commit and a commit must be performed before any further
4259 updates to the repository are allowed. The next commit will have
4259 updates to the repository are allowed. The next commit will have
4260 two parents.
4260 two parents.
4261
4261
4262 ``--tool`` can be used to specify the merge tool used for file
4262 ``--tool`` can be used to specify the merge tool used for file
4263 merges. It overrides the HGMERGE environment variable and your
4263 merges. It overrides the HGMERGE environment variable and your
4264 configuration files. See :hg:`help merge-tools` for options.
4264 configuration files. See :hg:`help merge-tools` for options.
4265
4265
4266 If no revision is specified, the working directory's parent is a
4266 If no revision is specified, the working directory's parent is a
4267 head revision, and the current branch contains exactly one other
4267 head revision, and the current branch contains exactly one other
4268 head, the other head is merged with by default. Otherwise, an
4268 head, the other head is merged with by default. Otherwise, an
4269 explicit revision with which to merge with must be provided.
4269 explicit revision with which to merge with must be provided.
4270
4270
4271 :hg:`resolve` must be used to resolve unresolved files.
4271 :hg:`resolve` must be used to resolve unresolved files.
4272
4272
4273 To undo an uncommitted merge, use :hg:`update --clean .` which
4273 To undo an uncommitted merge, use :hg:`update --clean .` which
4274 will check out a clean copy of the original merge parent, losing
4274 will check out a clean copy of the original merge parent, losing
4275 all changes.
4275 all changes.
4276
4276
4277 Returns 0 on success, 1 if there are unresolved files.
4277 Returns 0 on success, 1 if there are unresolved files.
4278 """
4278 """
4279
4279
4280 if opts.get('rev') and node:
4280 if opts.get('rev') and node:
4281 raise util.Abort(_("please specify just one revision"))
4281 raise util.Abort(_("please specify just one revision"))
4282 if not node:
4282 if not node:
4283 node = opts.get('rev')
4283 node = opts.get('rev')
4284
4284
4285 if node:
4285 if node:
4286 node = scmutil.revsingle(repo, node).node()
4286 node = scmutil.revsingle(repo, node).node()
4287
4287
4288 if not node and repo._bookmarkcurrent:
4288 if not node and repo._bookmarkcurrent:
4289 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4289 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4290 curhead = repo[repo._bookmarkcurrent]
4290 curhead = repo[repo._bookmarkcurrent]
4291 if len(bmheads) == 2:
4291 if len(bmheads) == 2:
4292 if curhead == bmheads[0]:
4292 if curhead == bmheads[0]:
4293 node = bmheads[1]
4293 node = bmheads[1]
4294 else:
4294 else:
4295 node = bmheads[0]
4295 node = bmheads[0]
4296 elif len(bmheads) > 2:
4296 elif len(bmheads) > 2:
4297 raise util.Abort(_("multiple matching bookmarks to merge - "
4297 raise util.Abort(_("multiple matching bookmarks to merge - "
4298 "please merge with an explicit rev or bookmark"),
4298 "please merge with an explicit rev or bookmark"),
4299 hint=_("run 'hg heads' to see all heads"))
4299 hint=_("run 'hg heads' to see all heads"))
4300 elif len(bmheads) <= 1:
4300 elif len(bmheads) <= 1:
4301 raise util.Abort(_("no matching bookmark to merge - "
4301 raise util.Abort(_("no matching bookmark to merge - "
4302 "please merge with an explicit rev or bookmark"),
4302 "please merge with an explicit rev or bookmark"),
4303 hint=_("run 'hg heads' to see all heads"))
4303 hint=_("run 'hg heads' to see all heads"))
4304
4304
4305 if not node and not repo._bookmarkcurrent:
4305 if not node and not repo._bookmarkcurrent:
4306 branch = repo[None].branch()
4306 branch = repo[None].branch()
4307 bheads = repo.branchheads(branch)
4307 bheads = repo.branchheads(branch)
4308 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4308 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4309
4309
4310 if len(nbhs) > 2:
4310 if len(nbhs) > 2:
4311 raise util.Abort(_("branch '%s' has %d heads - "
4311 raise util.Abort(_("branch '%s' has %d heads - "
4312 "please merge with an explicit rev")
4312 "please merge with an explicit rev")
4313 % (branch, len(bheads)),
4313 % (branch, len(bheads)),
4314 hint=_("run 'hg heads .' to see heads"))
4314 hint=_("run 'hg heads .' to see heads"))
4315
4315
4316 parent = repo.dirstate.p1()
4316 parent = repo.dirstate.p1()
4317 if len(nbhs) <= 1:
4317 if len(nbhs) <= 1:
4318 if len(bheads) > 1:
4318 if len(bheads) > 1:
4319 raise util.Abort(_("heads are bookmarked - "
4319 raise util.Abort(_("heads are bookmarked - "
4320 "please merge with an explicit rev"),
4320 "please merge with an explicit rev"),
4321 hint=_("run 'hg heads' to see all heads"))
4321 hint=_("run 'hg heads' to see all heads"))
4322 if len(repo.heads()) > 1:
4322 if len(repo.heads()) > 1:
4323 raise util.Abort(_("branch '%s' has one head - "
4323 raise util.Abort(_("branch '%s' has one head - "
4324 "please merge with an explicit rev")
4324 "please merge with an explicit rev")
4325 % branch,
4325 % branch,
4326 hint=_("run 'hg heads' to see all heads"))
4326 hint=_("run 'hg heads' to see all heads"))
4327 msg, hint = _('nothing to merge'), None
4327 msg, hint = _('nothing to merge'), None
4328 if parent != repo.lookup(branch):
4328 if parent != repo.lookup(branch):
4329 hint = _("use 'hg update' instead")
4329 hint = _("use 'hg update' instead")
4330 raise util.Abort(msg, hint=hint)
4330 raise util.Abort(msg, hint=hint)
4331
4331
4332 if parent not in bheads:
4332 if parent not in bheads:
4333 raise util.Abort(_('working directory not at a head revision'),
4333 raise util.Abort(_('working directory not at a head revision'),
4334 hint=_("use 'hg update' or merge with an "
4334 hint=_("use 'hg update' or merge with an "
4335 "explicit revision"))
4335 "explicit revision"))
4336 if parent == nbhs[0]:
4336 if parent == nbhs[0]:
4337 node = nbhs[-1]
4337 node = nbhs[-1]
4338 else:
4338 else:
4339 node = nbhs[0]
4339 node = nbhs[0]
4340
4340
4341 if opts.get('preview'):
4341 if opts.get('preview'):
4342 # find nodes that are ancestors of p2 but not of p1
4342 # find nodes that are ancestors of p2 but not of p1
4343 p1 = repo.lookup('.')
4343 p1 = repo.lookup('.')
4344 p2 = repo.lookup(node)
4344 p2 = repo.lookup(node)
4345 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4345 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4346
4346
4347 displayer = cmdutil.show_changeset(ui, repo, opts)
4347 displayer = cmdutil.show_changeset(ui, repo, opts)
4348 for node in nodes:
4348 for node in nodes:
4349 displayer.show(repo[node])
4349 displayer.show(repo[node])
4350 displayer.close()
4350 displayer.close()
4351 return 0
4351 return 0
4352
4352
4353 try:
4353 try:
4354 # ui.forcemerge is an internal variable, do not document
4354 # ui.forcemerge is an internal variable, do not document
4355 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4355 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4356 return hg.merge(repo, node, force=opts.get('force'))
4356 return hg.merge(repo, node, force=opts.get('force'))
4357 finally:
4357 finally:
4358 ui.setconfig('ui', 'forcemerge', '')
4358 ui.setconfig('ui', 'forcemerge', '')
4359
4359
4360 @command('outgoing|out',
4360 @command('outgoing|out',
4361 [('f', 'force', None, _('run even when the destination is unrelated')),
4361 [('f', 'force', None, _('run even when the destination is unrelated')),
4362 ('r', 'rev', [],
4362 ('r', 'rev', [],
4363 _('a changeset intended to be included in the destination'), _('REV')),
4363 _('a changeset intended to be included in the destination'), _('REV')),
4364 ('n', 'newest-first', None, _('show newest record first')),
4364 ('n', 'newest-first', None, _('show newest record first')),
4365 ('B', 'bookmarks', False, _('compare bookmarks')),
4365 ('B', 'bookmarks', False, _('compare bookmarks')),
4366 ('b', 'branch', [], _('a specific branch you would like to push'),
4366 ('b', 'branch', [], _('a specific branch you would like to push'),
4367 _('BRANCH')),
4367 _('BRANCH')),
4368 ] + logopts + remoteopts + subrepoopts,
4368 ] + logopts + remoteopts + subrepoopts,
4369 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4369 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4370 def outgoing(ui, repo, dest=None, **opts):
4370 def outgoing(ui, repo, dest=None, **opts):
4371 """show changesets not found in the destination
4371 """show changesets not found in the destination
4372
4372
4373 Show changesets not found in the specified destination repository
4373 Show changesets not found in the specified destination repository
4374 or the default push location. These are the changesets that would
4374 or the default push location. These are the changesets that would
4375 be pushed if a push was requested.
4375 be pushed if a push was requested.
4376
4376
4377 See pull for details of valid destination formats.
4377 See pull for details of valid destination formats.
4378
4378
4379 Returns 0 if there are outgoing changes, 1 otherwise.
4379 Returns 0 if there are outgoing changes, 1 otherwise.
4380 """
4380 """
4381 if opts.get('graph'):
4381 if opts.get('graph'):
4382 cmdutil.checkunsupportedgraphflags([], opts)
4382 cmdutil.checkunsupportedgraphflags([], opts)
4383 o = hg._outgoing(ui, repo, dest, opts)
4383 o = hg._outgoing(ui, repo, dest, opts)
4384 if o is None:
4384 if o is None:
4385 return
4385 return
4386
4386
4387 revdag = cmdutil.graphrevs(repo, o, opts)
4387 revdag = cmdutil.graphrevs(repo, o, opts)
4388 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4388 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4389 showparents = [ctx.node() for ctx in repo[None].parents()]
4389 showparents = [ctx.node() for ctx in repo[None].parents()]
4390 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4390 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4391 graphmod.asciiedges)
4391 graphmod.asciiedges)
4392 return 0
4392 return 0
4393
4393
4394 if opts.get('bookmarks'):
4394 if opts.get('bookmarks'):
4395 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4395 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4396 dest, branches = hg.parseurl(dest, opts.get('branch'))
4396 dest, branches = hg.parseurl(dest, opts.get('branch'))
4397 other = hg.peer(repo, opts, dest)
4397 other = hg.peer(repo, opts, dest)
4398 if 'bookmarks' not in other.listkeys('namespaces'):
4398 if 'bookmarks' not in other.listkeys('namespaces'):
4399 ui.warn(_("remote doesn't support bookmarks\n"))
4399 ui.warn(_("remote doesn't support bookmarks\n"))
4400 return 0
4400 return 0
4401 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4401 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4402 return bookmarks.diff(ui, other, repo)
4402 return bookmarks.diff(ui, other, repo)
4403
4403
4404 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4404 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4405 try:
4405 try:
4406 return hg.outgoing(ui, repo, dest, opts)
4406 return hg.outgoing(ui, repo, dest, opts)
4407 finally:
4407 finally:
4408 del repo._subtoppath
4408 del repo._subtoppath
4409
4409
4410 @command('parents',
4410 @command('parents',
4411 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4411 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4412 ] + templateopts,
4412 ] + templateopts,
4413 _('[-r REV] [FILE]'))
4413 _('[-r REV] [FILE]'))
4414 def parents(ui, repo, file_=None, **opts):
4414 def parents(ui, repo, file_=None, **opts):
4415 """show the parents of the working directory or revision
4415 """show the parents of the working directory or revision
4416
4416
4417 Print the working directory's parent revisions. If a revision is
4417 Print the working directory's parent revisions. If a revision is
4418 given via -r/--rev, the parent of that revision will be printed.
4418 given via -r/--rev, the parent of that revision will be printed.
4419 If a file argument is given, the revision in which the file was
4419 If a file argument is given, the revision in which the file was
4420 last changed (before the working directory revision or the
4420 last changed (before the working directory revision or the
4421 argument to --rev if given) is printed.
4421 argument to --rev if given) is printed.
4422
4422
4423 Returns 0 on success.
4423 Returns 0 on success.
4424 """
4424 """
4425
4425
4426 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4426 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4427
4427
4428 if file_:
4428 if file_:
4429 m = scmutil.match(ctx, (file_,), opts)
4429 m = scmutil.match(ctx, (file_,), opts)
4430 if m.anypats() or len(m.files()) != 1:
4430 if m.anypats() or len(m.files()) != 1:
4431 raise util.Abort(_('can only specify an explicit filename'))
4431 raise util.Abort(_('can only specify an explicit filename'))
4432 file_ = m.files()[0]
4432 file_ = m.files()[0]
4433 filenodes = []
4433 filenodes = []
4434 for cp in ctx.parents():
4434 for cp in ctx.parents():
4435 if not cp:
4435 if not cp:
4436 continue
4436 continue
4437 try:
4437 try:
4438 filenodes.append(cp.filenode(file_))
4438 filenodes.append(cp.filenode(file_))
4439 except error.LookupError:
4439 except error.LookupError:
4440 pass
4440 pass
4441 if not filenodes:
4441 if not filenodes:
4442 raise util.Abort(_("'%s' not found in manifest!") % file_)
4442 raise util.Abort(_("'%s' not found in manifest!") % file_)
4443 fl = repo.file(file_)
4443 fl = repo.file(file_)
4444 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4444 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4445 else:
4445 else:
4446 p = [cp.node() for cp in ctx.parents()]
4446 p = [cp.node() for cp in ctx.parents()]
4447
4447
4448 displayer = cmdutil.show_changeset(ui, repo, opts)
4448 displayer = cmdutil.show_changeset(ui, repo, opts)
4449 for n in p:
4449 for n in p:
4450 if n != nullid:
4450 if n != nullid:
4451 displayer.show(repo[n])
4451 displayer.show(repo[n])
4452 displayer.close()
4452 displayer.close()
4453
4453
4454 @command('paths', [], _('[NAME]'))
4454 @command('paths', [], _('[NAME]'))
4455 def paths(ui, repo, search=None):
4455 def paths(ui, repo, search=None):
4456 """show aliases for remote repositories
4456 """show aliases for remote repositories
4457
4457
4458 Show definition of symbolic path name NAME. If no name is given,
4458 Show definition of symbolic path name NAME. If no name is given,
4459 show definition of all available names.
4459 show definition of all available names.
4460
4460
4461 Option -q/--quiet suppresses all output when searching for NAME
4461 Option -q/--quiet suppresses all output when searching for NAME
4462 and shows only the path names when listing all definitions.
4462 and shows only the path names when listing all definitions.
4463
4463
4464 Path names are defined in the [paths] section of your
4464 Path names are defined in the [paths] section of your
4465 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4465 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4466 repository, ``.hg/hgrc`` is used, too.
4466 repository, ``.hg/hgrc`` is used, too.
4467
4467
4468 The path names ``default`` and ``default-push`` have a special
4468 The path names ``default`` and ``default-push`` have a special
4469 meaning. When performing a push or pull operation, they are used
4469 meaning. When performing a push or pull operation, they are used
4470 as fallbacks if no location is specified on the command-line.
4470 as fallbacks if no location is specified on the command-line.
4471 When ``default-push`` is set, it will be used for push and
4471 When ``default-push`` is set, it will be used for push and
4472 ``default`` will be used for pull; otherwise ``default`` is used
4472 ``default`` will be used for pull; otherwise ``default`` is used
4473 as the fallback for both. When cloning a repository, the clone
4473 as the fallback for both. When cloning a repository, the clone
4474 source is written as ``default`` in ``.hg/hgrc``. Note that
4474 source is written as ``default`` in ``.hg/hgrc``. Note that
4475 ``default`` and ``default-push`` apply to all inbound (e.g.
4475 ``default`` and ``default-push`` apply to all inbound (e.g.
4476 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4476 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4477 :hg:`bundle`) operations.
4477 :hg:`bundle`) operations.
4478
4478
4479 See :hg:`help urls` for more information.
4479 See :hg:`help urls` for more information.
4480
4480
4481 Returns 0 on success.
4481 Returns 0 on success.
4482 """
4482 """
4483 if search:
4483 if search:
4484 for name, path in ui.configitems("paths"):
4484 for name, path in ui.configitems("paths"):
4485 if name == search:
4485 if name == search:
4486 ui.status("%s\n" % util.hidepassword(path))
4486 ui.status("%s\n" % util.hidepassword(path))
4487 return
4487 return
4488 if not ui.quiet:
4488 if not ui.quiet:
4489 ui.warn(_("not found!\n"))
4489 ui.warn(_("not found!\n"))
4490 return 1
4490 return 1
4491 else:
4491 else:
4492 for name, path in ui.configitems("paths"):
4492 for name, path in ui.configitems("paths"):
4493 if ui.quiet:
4493 if ui.quiet:
4494 ui.write("%s\n" % name)
4494 ui.write("%s\n" % name)
4495 else:
4495 else:
4496 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4496 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4497
4497
4498 @command('^phase',
4498 @command('^phase',
4499 [('p', 'public', False, _('set changeset phase to public')),
4499 [('p', 'public', False, _('set changeset phase to public')),
4500 ('d', 'draft', False, _('set changeset phase to draft')),
4500 ('d', 'draft', False, _('set changeset phase to draft')),
4501 ('s', 'secret', False, _('set changeset phase to secret')),
4501 ('s', 'secret', False, _('set changeset phase to secret')),
4502 ('f', 'force', False, _('allow to move boundary backward')),
4502 ('f', 'force', False, _('allow to move boundary backward')),
4503 ('r', 'rev', [], _('target revision'), _('REV')),
4503 ('r', 'rev', [], _('target revision'), _('REV')),
4504 ],
4504 ],
4505 _('[-p|-d|-s] [-f] [-r] REV...'))
4505 _('[-p|-d|-s] [-f] [-r] REV...'))
4506 def phase(ui, repo, *revs, **opts):
4506 def phase(ui, repo, *revs, **opts):
4507 """set or show the current phase name
4507 """set or show the current phase name
4508
4508
4509 With no argument, show the phase name of specified revisions.
4509 With no argument, show the phase name of specified revisions.
4510
4510
4511 With one of -p/--public, -d/--draft or -s/--secret, change the
4511 With one of -p/--public, -d/--draft or -s/--secret, change the
4512 phase value of the specified revisions.
4512 phase value of the specified revisions.
4513
4513
4514 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4514 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4515 lower phase to an higher phase. Phases are ordered as follows::
4515 lower phase to an higher phase. Phases are ordered as follows::
4516
4516
4517 public < draft < secret
4517 public < draft < secret
4518
4518
4519 Return 0 on success, 1 if no phases were changed or some could not
4519 Return 0 on success, 1 if no phases were changed or some could not
4520 be changed.
4520 be changed.
4521 """
4521 """
4522 # search for a unique phase argument
4522 # search for a unique phase argument
4523 targetphase = None
4523 targetphase = None
4524 for idx, name in enumerate(phases.phasenames):
4524 for idx, name in enumerate(phases.phasenames):
4525 if opts[name]:
4525 if opts[name]:
4526 if targetphase is not None:
4526 if targetphase is not None:
4527 raise util.Abort(_('only one phase can be specified'))
4527 raise util.Abort(_('only one phase can be specified'))
4528 targetphase = idx
4528 targetphase = idx
4529
4529
4530 # look for specified revision
4530 # look for specified revision
4531 revs = list(revs)
4531 revs = list(revs)
4532 revs.extend(opts['rev'])
4532 revs.extend(opts['rev'])
4533 if not revs:
4533 if not revs:
4534 raise util.Abort(_('no revisions specified'))
4534 raise util.Abort(_('no revisions specified'))
4535
4535
4536 revs = scmutil.revrange(repo, revs)
4536 revs = scmutil.revrange(repo, revs)
4537
4537
4538 lock = None
4538 lock = None
4539 ret = 0
4539 ret = 0
4540 if targetphase is None:
4540 if targetphase is None:
4541 # display
4541 # display
4542 for r in revs:
4542 for r in revs:
4543 ctx = repo[r]
4543 ctx = repo[r]
4544 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4544 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4545 else:
4545 else:
4546 lock = repo.lock()
4546 lock = repo.lock()
4547 try:
4547 try:
4548 # set phase
4548 # set phase
4549 if not revs:
4549 if not revs:
4550 raise util.Abort(_('empty revision set'))
4550 raise util.Abort(_('empty revision set'))
4551 nodes = [repo[r].node() for r in revs]
4551 nodes = [repo[r].node() for r in revs]
4552 olddata = repo._phasecache.getphaserevs(repo)[:]
4552 olddata = repo._phasecache.getphaserevs(repo)[:]
4553 phases.advanceboundary(repo, targetphase, nodes)
4553 phases.advanceboundary(repo, targetphase, nodes)
4554 if opts['force']:
4554 if opts['force']:
4555 phases.retractboundary(repo, targetphase, nodes)
4555 phases.retractboundary(repo, targetphase, nodes)
4556 finally:
4556 finally:
4557 lock.release()
4557 lock.release()
4558 newdata = repo._phasecache.getphaserevs(repo)
4558 newdata = repo._phasecache.getphaserevs(repo)
4559 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4559 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4560 rejected = [n for n in nodes
4560 rejected = [n for n in nodes
4561 if newdata[repo[n].rev()] < targetphase]
4561 if newdata[repo[n].rev()] < targetphase]
4562 if rejected:
4562 if rejected:
4563 ui.warn(_('cannot move %i changesets to a more permissive '
4563 ui.warn(_('cannot move %i changesets to a more permissive '
4564 'phase, use --force\n') % len(rejected))
4564 'phase, use --force\n') % len(rejected))
4565 ret = 1
4565 ret = 1
4566 if changes:
4566 if changes:
4567 msg = _('phase changed for %i changesets\n') % changes
4567 msg = _('phase changed for %i changesets\n') % changes
4568 if ret:
4568 if ret:
4569 ui.status(msg)
4569 ui.status(msg)
4570 else:
4570 else:
4571 ui.note(msg)
4571 ui.note(msg)
4572 else:
4572 else:
4573 ui.warn(_('no phases changed\n'))
4573 ui.warn(_('no phases changed\n'))
4574 ret = 1
4574 ret = 1
4575 return ret
4575 return ret
4576
4576
4577 def postincoming(ui, repo, modheads, optupdate, checkout):
4577 def postincoming(ui, repo, modheads, optupdate, checkout):
4578 if modheads == 0:
4578 if modheads == 0:
4579 return
4579 return
4580 if optupdate:
4580 if optupdate:
4581 movemarkfrom = repo['.'].node()
4581 movemarkfrom = repo['.'].node()
4582 try:
4582 try:
4583 ret = hg.update(repo, checkout)
4583 ret = hg.update(repo, checkout)
4584 except util.Abort, inst:
4584 except util.Abort, inst:
4585 ui.warn(_("not updating: %s\n") % str(inst))
4585 ui.warn(_("not updating: %s\n") % str(inst))
4586 return 0
4586 return 0
4587 if not ret and not checkout:
4587 if not ret and not checkout:
4588 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4588 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4589 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4589 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4590 return ret
4590 return ret
4591 if modheads > 1:
4591 if modheads > 1:
4592 currentbranchheads = len(repo.branchheads())
4592 currentbranchheads = len(repo.branchheads())
4593 if currentbranchheads == modheads:
4593 if currentbranchheads == modheads:
4594 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4594 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4595 elif currentbranchheads > 1:
4595 elif currentbranchheads > 1:
4596 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4596 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4597 "merge)\n"))
4597 "merge)\n"))
4598 else:
4598 else:
4599 ui.status(_("(run 'hg heads' to see heads)\n"))
4599 ui.status(_("(run 'hg heads' to see heads)\n"))
4600 else:
4600 else:
4601 ui.status(_("(run 'hg update' to get a working copy)\n"))
4601 ui.status(_("(run 'hg update' to get a working copy)\n"))
4602
4602
4603 @command('^pull',
4603 @command('^pull',
4604 [('u', 'update', None,
4604 [('u', 'update', None,
4605 _('update to new branch head if changesets were pulled')),
4605 _('update to new branch head if changesets were pulled')),
4606 ('f', 'force', None, _('run even when remote repository is unrelated')),
4606 ('f', 'force', None, _('run even when remote repository is unrelated')),
4607 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4607 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4608 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4608 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4609 ('b', 'branch', [], _('a specific branch you would like to pull'),
4609 ('b', 'branch', [], _('a specific branch you would like to pull'),
4610 _('BRANCH')),
4610 _('BRANCH')),
4611 ] + remoteopts,
4611 ] + remoteopts,
4612 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4612 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4613 def pull(ui, repo, source="default", **opts):
4613 def pull(ui, repo, source="default", **opts):
4614 """pull changes from the specified source
4614 """pull changes from the specified source
4615
4615
4616 Pull changes from a remote repository to a local one.
4616 Pull changes from a remote repository to a local one.
4617
4617
4618 This finds all changes from the repository at the specified path
4618 This finds all changes from the repository at the specified path
4619 or URL and adds them to a local repository (the current one unless
4619 or URL and adds them to a local repository (the current one unless
4620 -R is specified). By default, this does not update the copy of the
4620 -R is specified). By default, this does not update the copy of the
4621 project in the working directory.
4621 project in the working directory.
4622
4622
4623 Use :hg:`incoming` if you want to see what would have been added
4623 Use :hg:`incoming` if you want to see what would have been added
4624 by a pull at the time you issued this command. If you then decide
4624 by a pull at the time you issued this command. If you then decide
4625 to add those changes to the repository, you should use :hg:`pull
4625 to add those changes to the repository, you should use :hg:`pull
4626 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4626 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4627
4627
4628 If SOURCE is omitted, the 'default' path will be used.
4628 If SOURCE is omitted, the 'default' path will be used.
4629 See :hg:`help urls` for more information.
4629 See :hg:`help urls` for more information.
4630
4630
4631 Returns 0 on success, 1 if an update had unresolved files.
4631 Returns 0 on success, 1 if an update had unresolved files.
4632 """
4632 """
4633 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4633 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4634 other = hg.peer(repo, opts, source)
4634 other = hg.peer(repo, opts, source)
4635 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4635 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4636 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4636 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4637
4637
4638 if opts.get('bookmark'):
4638 if opts.get('bookmark'):
4639 if not revs:
4639 if not revs:
4640 revs = []
4640 revs = []
4641 rb = other.listkeys('bookmarks')
4641 rb = other.listkeys('bookmarks')
4642 for b in opts['bookmark']:
4642 for b in opts['bookmark']:
4643 if b not in rb:
4643 if b not in rb:
4644 raise util.Abort(_('remote bookmark %s not found!') % b)
4644 raise util.Abort(_('remote bookmark %s not found!') % b)
4645 revs.append(rb[b])
4645 revs.append(rb[b])
4646
4646
4647 if revs:
4647 if revs:
4648 try:
4648 try:
4649 revs = [other.lookup(rev) for rev in revs]
4649 revs = [other.lookup(rev) for rev in revs]
4650 except error.CapabilityError:
4650 except error.CapabilityError:
4651 err = _("other repository doesn't support revision lookup, "
4651 err = _("other repository doesn't support revision lookup, "
4652 "so a rev cannot be specified.")
4652 "so a rev cannot be specified.")
4653 raise util.Abort(err)
4653 raise util.Abort(err)
4654
4654
4655 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4655 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4656 bookmarks.updatefromremote(ui, repo, other, source)
4656 bookmarks.updatefromremote(ui, repo, other, source)
4657 if checkout:
4657 if checkout:
4658 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4658 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4659 repo._subtoppath = source
4659 repo._subtoppath = source
4660 try:
4660 try:
4661 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4661 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4662
4662
4663 finally:
4663 finally:
4664 del repo._subtoppath
4664 del repo._subtoppath
4665
4665
4666 # update specified bookmarks
4666 # update specified bookmarks
4667 if opts.get('bookmark'):
4667 if opts.get('bookmark'):
4668 for b in opts['bookmark']:
4668 for b in opts['bookmark']:
4669 # explicit pull overrides local bookmark if any
4669 # explicit pull overrides local bookmark if any
4670 ui.status(_("importing bookmark %s\n") % b)
4670 ui.status(_("importing bookmark %s\n") % b)
4671 repo._bookmarks[b] = repo[rb[b]].node()
4671 repo._bookmarks[b] = repo[rb[b]].node()
4672 bookmarks.write(repo)
4672 bookmarks.write(repo)
4673
4673
4674 return ret
4674 return ret
4675
4675
4676 @command('^push',
4676 @command('^push',
4677 [('f', 'force', None, _('force push')),
4677 [('f', 'force', None, _('force push')),
4678 ('r', 'rev', [],
4678 ('r', 'rev', [],
4679 _('a changeset intended to be included in the destination'),
4679 _('a changeset intended to be included in the destination'),
4680 _('REV')),
4680 _('REV')),
4681 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4681 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4682 ('b', 'branch', [],
4682 ('b', 'branch', [],
4683 _('a specific branch you would like to push'), _('BRANCH')),
4683 _('a specific branch you would like to push'), _('BRANCH')),
4684 ('', 'new-branch', False, _('allow pushing a new branch')),
4684 ('', 'new-branch', False, _('allow pushing a new branch')),
4685 ] + remoteopts,
4685 ] + remoteopts,
4686 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4686 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4687 def push(ui, repo, dest=None, **opts):
4687 def push(ui, repo, dest=None, **opts):
4688 """push changes to the specified destination
4688 """push changes to the specified destination
4689
4689
4690 Push changesets from the local repository to the specified
4690 Push changesets from the local repository to the specified
4691 destination.
4691 destination.
4692
4692
4693 This operation is symmetrical to pull: it is identical to a pull
4693 This operation is symmetrical to pull: it is identical to a pull
4694 in the destination repository from the current one.
4694 in the destination repository from the current one.
4695
4695
4696 By default, push will not allow creation of new heads at the
4696 By default, push will not allow creation of new heads at the
4697 destination, since multiple heads would make it unclear which head
4697 destination, since multiple heads would make it unclear which head
4698 to use. In this situation, it is recommended to pull and merge
4698 to use. In this situation, it is recommended to pull and merge
4699 before pushing.
4699 before pushing.
4700
4700
4701 Use --new-branch if you want to allow push to create a new named
4701 Use --new-branch if you want to allow push to create a new named
4702 branch that is not present at the destination. This allows you to
4702 branch that is not present at the destination. This allows you to
4703 only create a new branch without forcing other changes.
4703 only create a new branch without forcing other changes.
4704
4704
4705 Use -f/--force to override the default behavior and push all
4705 Use -f/--force to override the default behavior and push all
4706 changesets on all branches.
4706 changesets on all branches.
4707
4707
4708 If -r/--rev is used, the specified revision and all its ancestors
4708 If -r/--rev is used, the specified revision and all its ancestors
4709 will be pushed to the remote repository.
4709 will be pushed to the remote repository.
4710
4710
4711 If -B/--bookmark is used, the specified bookmarked revision, its
4711 If -B/--bookmark is used, the specified bookmarked revision, its
4712 ancestors, and the bookmark will be pushed to the remote
4712 ancestors, and the bookmark will be pushed to the remote
4713 repository.
4713 repository.
4714
4714
4715 Please see :hg:`help urls` for important details about ``ssh://``
4715 Please see :hg:`help urls` for important details about ``ssh://``
4716 URLs. If DESTINATION is omitted, a default path will be used.
4716 URLs. If DESTINATION is omitted, a default path will be used.
4717
4717
4718 Returns 0 if push was successful, 1 if nothing to push.
4718 Returns 0 if push was successful, 1 if nothing to push.
4719 """
4719 """
4720
4720
4721 if opts.get('bookmark'):
4721 if opts.get('bookmark'):
4722 for b in opts['bookmark']:
4722 for b in opts['bookmark']:
4723 # translate -B options to -r so changesets get pushed
4723 # translate -B options to -r so changesets get pushed
4724 if b in repo._bookmarks:
4724 if b in repo._bookmarks:
4725 opts.setdefault('rev', []).append(b)
4725 opts.setdefault('rev', []).append(b)
4726 else:
4726 else:
4727 # if we try to push a deleted bookmark, translate it to null
4727 # if we try to push a deleted bookmark, translate it to null
4728 # this lets simultaneous -r, -b options continue working
4728 # this lets simultaneous -r, -b options continue working
4729 opts.setdefault('rev', []).append("null")
4729 opts.setdefault('rev', []).append("null")
4730
4730
4731 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4731 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4732 dest, branches = hg.parseurl(dest, opts.get('branch'))
4732 dest, branches = hg.parseurl(dest, opts.get('branch'))
4733 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4733 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4734 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4734 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4735 other = hg.peer(repo, opts, dest)
4735 other = hg.peer(repo, opts, dest)
4736 if revs:
4736 if revs:
4737 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4737 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4738
4738
4739 repo._subtoppath = dest
4739 repo._subtoppath = dest
4740 try:
4740 try:
4741 # push subrepos depth-first for coherent ordering
4741 # push subrepos depth-first for coherent ordering
4742 c = repo['']
4742 c = repo['']
4743 subs = c.substate # only repos that are committed
4743 subs = c.substate # only repos that are committed
4744 for s in sorted(subs):
4744 for s in sorted(subs):
4745 if c.sub(s).push(opts) == 0:
4745 if c.sub(s).push(opts) == 0:
4746 return False
4746 return False
4747 finally:
4747 finally:
4748 del repo._subtoppath
4748 del repo._subtoppath
4749 result = repo.push(other, opts.get('force'), revs=revs,
4749 result = repo.push(other, opts.get('force'), revs=revs,
4750 newbranch=opts.get('new_branch'))
4750 newbranch=opts.get('new_branch'))
4751
4751
4752 result = not result
4752 result = not result
4753
4753
4754 if opts.get('bookmark'):
4754 if opts.get('bookmark'):
4755 rb = other.listkeys('bookmarks')
4755 rb = other.listkeys('bookmarks')
4756 for b in opts['bookmark']:
4756 for b in opts['bookmark']:
4757 # explicit push overrides remote bookmark if any
4757 # explicit push overrides remote bookmark if any
4758 if b in repo._bookmarks:
4758 if b in repo._bookmarks:
4759 ui.status(_("exporting bookmark %s\n") % b)
4759 ui.status(_("exporting bookmark %s\n") % b)
4760 new = repo[b].hex()
4760 new = repo[b].hex()
4761 elif b in rb:
4761 elif b in rb:
4762 ui.status(_("deleting remote bookmark %s\n") % b)
4762 ui.status(_("deleting remote bookmark %s\n") % b)
4763 new = '' # delete
4763 new = '' # delete
4764 else:
4764 else:
4765 ui.warn(_('bookmark %s does not exist on the local '
4765 ui.warn(_('bookmark %s does not exist on the local '
4766 'or remote repository!\n') % b)
4766 'or remote repository!\n') % b)
4767 return 2
4767 return 2
4768 old = rb.get(b, '')
4768 old = rb.get(b, '')
4769 r = other.pushkey('bookmarks', b, old, new)
4769 r = other.pushkey('bookmarks', b, old, new)
4770 if not r:
4770 if not r:
4771 ui.warn(_('updating bookmark %s failed!\n') % b)
4771 ui.warn(_('updating bookmark %s failed!\n') % b)
4772 if not result:
4772 if not result:
4773 result = 2
4773 result = 2
4774
4774
4775 return result
4775 return result
4776
4776
4777 @command('recover', [])
4777 @command('recover', [])
4778 def recover(ui, repo):
4778 def recover(ui, repo):
4779 """roll back an interrupted transaction
4779 """roll back an interrupted transaction
4780
4780
4781 Recover from an interrupted commit or pull.
4781 Recover from an interrupted commit or pull.
4782
4782
4783 This command tries to fix the repository status after an
4783 This command tries to fix the repository status after an
4784 interrupted operation. It should only be necessary when Mercurial
4784 interrupted operation. It should only be necessary when Mercurial
4785 suggests it.
4785 suggests it.
4786
4786
4787 Returns 0 if successful, 1 if nothing to recover or verify fails.
4787 Returns 0 if successful, 1 if nothing to recover or verify fails.
4788 """
4788 """
4789 if repo.recover():
4789 if repo.recover():
4790 return hg.verify(repo)
4790 return hg.verify(repo)
4791 return 1
4791 return 1
4792
4792
4793 @command('^remove|rm',
4793 @command('^remove|rm',
4794 [('A', 'after', None, _('record delete for missing files')),
4794 [('A', 'after', None, _('record delete for missing files')),
4795 ('f', 'force', None,
4795 ('f', 'force', None,
4796 _('remove (and delete) file even if added or modified')),
4796 _('remove (and delete) file even if added or modified')),
4797 ] + walkopts,
4797 ] + walkopts,
4798 _('[OPTION]... FILE...'))
4798 _('[OPTION]... FILE...'))
4799 def remove(ui, repo, *pats, **opts):
4799 def remove(ui, repo, *pats, **opts):
4800 """remove the specified files on the next commit
4800 """remove the specified files on the next commit
4801
4801
4802 Schedule the indicated files for removal from the current branch.
4802 Schedule the indicated files for removal from the current branch.
4803
4803
4804 This command schedules the files to be removed at the next commit.
4804 This command schedules the files to be removed at the next commit.
4805 To undo a remove before that, see :hg:`revert`. To undo added
4805 To undo a remove before that, see :hg:`revert`. To undo added
4806 files, see :hg:`forget`.
4806 files, see :hg:`forget`.
4807
4807
4808 .. container:: verbose
4808 .. container:: verbose
4809
4809
4810 -A/--after can be used to remove only files that have already
4810 -A/--after can be used to remove only files that have already
4811 been deleted, -f/--force can be used to force deletion, and -Af
4811 been deleted, -f/--force can be used to force deletion, and -Af
4812 can be used to remove files from the next revision without
4812 can be used to remove files from the next revision without
4813 deleting them from the working directory.
4813 deleting them from the working directory.
4814
4814
4815 The following table details the behavior of remove for different
4815 The following table details the behavior of remove for different
4816 file states (columns) and option combinations (rows). The file
4816 file states (columns) and option combinations (rows). The file
4817 states are Added [A], Clean [C], Modified [M] and Missing [!]
4817 states are Added [A], Clean [C], Modified [M] and Missing [!]
4818 (as reported by :hg:`status`). The actions are Warn, Remove
4818 (as reported by :hg:`status`). The actions are Warn, Remove
4819 (from branch) and Delete (from disk):
4819 (from branch) and Delete (from disk):
4820
4820
4821 ======= == == == ==
4821 ======= == == == ==
4822 A C M !
4822 A C M !
4823 ======= == == == ==
4823 ======= == == == ==
4824 none W RD W R
4824 none W RD W R
4825 -f R RD RD R
4825 -f R RD RD R
4826 -A W W W R
4826 -A W W W R
4827 -Af R R R R
4827 -Af R R R R
4828 ======= == == == ==
4828 ======= == == == ==
4829
4829
4830 Note that remove never deletes files in Added [A] state from the
4830 Note that remove never deletes files in Added [A] state from the
4831 working directory, not even if option --force is specified.
4831 working directory, not even if option --force is specified.
4832
4832
4833 Returns 0 on success, 1 if any warnings encountered.
4833 Returns 0 on success, 1 if any warnings encountered.
4834 """
4834 """
4835
4835
4836 ret = 0
4836 ret = 0
4837 after, force = opts.get('after'), opts.get('force')
4837 after, force = opts.get('after'), opts.get('force')
4838 if not pats and not after:
4838 if not pats and not after:
4839 raise util.Abort(_('no files specified'))
4839 raise util.Abort(_('no files specified'))
4840
4840
4841 m = scmutil.match(repo[None], pats, opts)
4841 m = scmutil.match(repo[None], pats, opts)
4842 s = repo.status(match=m, clean=True)
4842 s = repo.status(match=m, clean=True)
4843 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4843 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4844
4844
4845 # warn about failure to delete explicit files/dirs
4845 # warn about failure to delete explicit files/dirs
4846 wctx = repo[None]
4846 wctx = repo[None]
4847 for f in m.files():
4847 for f in m.files():
4848 if f in repo.dirstate or f in wctx.dirs():
4848 if f in repo.dirstate or f in wctx.dirs():
4849 continue
4849 continue
4850 if os.path.exists(m.rel(f)):
4850 if os.path.exists(m.rel(f)):
4851 if os.path.isdir(m.rel(f)):
4851 if os.path.isdir(m.rel(f)):
4852 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4852 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4853 else:
4853 else:
4854 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4854 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4855 # missing files will generate a warning elsewhere
4855 # missing files will generate a warning elsewhere
4856 ret = 1
4856 ret = 1
4857
4857
4858 if force:
4858 if force:
4859 list = modified + deleted + clean + added
4859 list = modified + deleted + clean + added
4860 elif after:
4860 elif after:
4861 list = deleted
4861 list = deleted
4862 for f in modified + added + clean:
4862 for f in modified + added + clean:
4863 ui.warn(_('not removing %s: file still exists (use -f'
4863 ui.warn(_('not removing %s: file still exists (use -f'
4864 ' to force removal)\n') % m.rel(f))
4864 ' to force removal)\n') % m.rel(f))
4865 ret = 1
4865 ret = 1
4866 else:
4866 else:
4867 list = deleted + clean
4867 list = deleted + clean
4868 for f in modified:
4868 for f in modified:
4869 ui.warn(_('not removing %s: file is modified (use -f'
4869 ui.warn(_('not removing %s: file is modified (use -f'
4870 ' to force removal)\n') % m.rel(f))
4870 ' to force removal)\n') % m.rel(f))
4871 ret = 1
4871 ret = 1
4872 for f in added:
4872 for f in added:
4873 ui.warn(_('not removing %s: file has been marked for add'
4873 ui.warn(_('not removing %s: file has been marked for add'
4874 ' (use forget to undo)\n') % m.rel(f))
4874 ' (use forget to undo)\n') % m.rel(f))
4875 ret = 1
4875 ret = 1
4876
4876
4877 for f in sorted(list):
4877 for f in sorted(list):
4878 if ui.verbose or not m.exact(f):
4878 if ui.verbose or not m.exact(f):
4879 ui.status(_('removing %s\n') % m.rel(f))
4879 ui.status(_('removing %s\n') % m.rel(f))
4880
4880
4881 wlock = repo.wlock()
4881 wlock = repo.wlock()
4882 try:
4882 try:
4883 if not after:
4883 if not after:
4884 for f in list:
4884 for f in list:
4885 if f in added:
4885 if f in added:
4886 continue # we never unlink added files on remove
4886 continue # we never unlink added files on remove
4887 try:
4887 try:
4888 util.unlinkpath(repo.wjoin(f))
4888 util.unlinkpath(repo.wjoin(f))
4889 except OSError, inst:
4889 except OSError, inst:
4890 if inst.errno != errno.ENOENT:
4890 if inst.errno != errno.ENOENT:
4891 raise
4891 raise
4892 repo[None].forget(list)
4892 repo[None].forget(list)
4893 finally:
4893 finally:
4894 wlock.release()
4894 wlock.release()
4895
4895
4896 return ret
4896 return ret
4897
4897
4898 @command('rename|move|mv',
4898 @command('rename|move|mv',
4899 [('A', 'after', None, _('record a rename that has already occurred')),
4899 [('A', 'after', None, _('record a rename that has already occurred')),
4900 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4900 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4901 ] + walkopts + dryrunopts,
4901 ] + walkopts + dryrunopts,
4902 _('[OPTION]... SOURCE... DEST'))
4902 _('[OPTION]... SOURCE... DEST'))
4903 def rename(ui, repo, *pats, **opts):
4903 def rename(ui, repo, *pats, **opts):
4904 """rename files; equivalent of copy + remove
4904 """rename files; equivalent of copy + remove
4905
4905
4906 Mark dest as copies of sources; mark sources for deletion. If dest
4906 Mark dest as copies of sources; mark sources for deletion. If dest
4907 is a directory, copies are put in that directory. If dest is a
4907 is a directory, copies are put in that directory. If dest is a
4908 file, there can only be one source.
4908 file, there can only be one source.
4909
4909
4910 By default, this command copies the contents of files as they
4910 By default, this command copies the contents of files as they
4911 exist in the working directory. If invoked with -A/--after, the
4911 exist in the working directory. If invoked with -A/--after, the
4912 operation is recorded, but no copying is performed.
4912 operation is recorded, but no copying is performed.
4913
4913
4914 This command takes effect at the next commit. To undo a rename
4914 This command takes effect at the next commit. To undo a rename
4915 before that, see :hg:`revert`.
4915 before that, see :hg:`revert`.
4916
4916
4917 Returns 0 on success, 1 if errors are encountered.
4917 Returns 0 on success, 1 if errors are encountered.
4918 """
4918 """
4919 wlock = repo.wlock(False)
4919 wlock = repo.wlock(False)
4920 try:
4920 try:
4921 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4921 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4922 finally:
4922 finally:
4923 wlock.release()
4923 wlock.release()
4924
4924
4925 @command('resolve',
4925 @command('resolve',
4926 [('a', 'all', None, _('select all unresolved files')),
4926 [('a', 'all', None, _('select all unresolved files')),
4927 ('l', 'list', None, _('list state of files needing merge')),
4927 ('l', 'list', None, _('list state of files needing merge')),
4928 ('m', 'mark', None, _('mark files as resolved')),
4928 ('m', 'mark', None, _('mark files as resolved')),
4929 ('u', 'unmark', None, _('mark files as unresolved')),
4929 ('u', 'unmark', None, _('mark files as unresolved')),
4930 ('n', 'no-status', None, _('hide status prefix'))]
4930 ('n', 'no-status', None, _('hide status prefix'))]
4931 + mergetoolopts + walkopts,
4931 + mergetoolopts + walkopts,
4932 _('[OPTION]... [FILE]...'))
4932 _('[OPTION]... [FILE]...'))
4933 def resolve(ui, repo, *pats, **opts):
4933 def resolve(ui, repo, *pats, **opts):
4934 """redo merges or set/view the merge status of files
4934 """redo merges or set/view the merge status of files
4935
4935
4936 Merges with unresolved conflicts are often the result of
4936 Merges with unresolved conflicts are often the result of
4937 non-interactive merging using the ``internal:merge`` configuration
4937 non-interactive merging using the ``internal:merge`` configuration
4938 setting, or a command-line merge tool like ``diff3``. The resolve
4938 setting, or a command-line merge tool like ``diff3``. The resolve
4939 command is used to manage the files involved in a merge, after
4939 command is used to manage the files involved in a merge, after
4940 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4940 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4941 working directory must have two parents). See :hg:`help
4941 working directory must have two parents). See :hg:`help
4942 merge-tools` for information on configuring merge tools.
4942 merge-tools` for information on configuring merge tools.
4943
4943
4944 The resolve command can be used in the following ways:
4944 The resolve command can be used in the following ways:
4945
4945
4946 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4946 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4947 files, discarding any previous merge attempts. Re-merging is not
4947 files, discarding any previous merge attempts. Re-merging is not
4948 performed for files already marked as resolved. Use ``--all/-a``
4948 performed for files already marked as resolved. Use ``--all/-a``
4949 to select all unresolved files. ``--tool`` can be used to specify
4949 to select all unresolved files. ``--tool`` can be used to specify
4950 the merge tool used for the given files. It overrides the HGMERGE
4950 the merge tool used for the given files. It overrides the HGMERGE
4951 environment variable and your configuration files. Previous file
4951 environment variable and your configuration files. Previous file
4952 contents are saved with a ``.orig`` suffix.
4952 contents are saved with a ``.orig`` suffix.
4953
4953
4954 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4954 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4955 (e.g. after having manually fixed-up the files). The default is
4955 (e.g. after having manually fixed-up the files). The default is
4956 to mark all unresolved files.
4956 to mark all unresolved files.
4957
4957
4958 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4958 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4959 default is to mark all resolved files.
4959 default is to mark all resolved files.
4960
4960
4961 - :hg:`resolve -l`: list files which had or still have conflicts.
4961 - :hg:`resolve -l`: list files which had or still have conflicts.
4962 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4962 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4963
4963
4964 Note that Mercurial will not let you commit files with unresolved
4964 Note that Mercurial will not let you commit files with unresolved
4965 merge conflicts. You must use :hg:`resolve -m ...` before you can
4965 merge conflicts. You must use :hg:`resolve -m ...` before you can
4966 commit after a conflicting merge.
4966 commit after a conflicting merge.
4967
4967
4968 Returns 0 on success, 1 if any files fail a resolve attempt.
4968 Returns 0 on success, 1 if any files fail a resolve attempt.
4969 """
4969 """
4970
4970
4971 all, mark, unmark, show, nostatus = \
4971 all, mark, unmark, show, nostatus = \
4972 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4972 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4973
4973
4974 if (show and (mark or unmark)) or (mark and unmark):
4974 if (show and (mark or unmark)) or (mark and unmark):
4975 raise util.Abort(_("too many options specified"))
4975 raise util.Abort(_("too many options specified"))
4976 if pats and all:
4976 if pats and all:
4977 raise util.Abort(_("can't specify --all and patterns"))
4977 raise util.Abort(_("can't specify --all and patterns"))
4978 if not (all or pats or show or mark or unmark):
4978 if not (all or pats or show or mark or unmark):
4979 raise util.Abort(_('no files or directories specified; '
4979 raise util.Abort(_('no files or directories specified; '
4980 'use --all to remerge all files'))
4980 'use --all to remerge all files'))
4981
4981
4982 ms = mergemod.mergestate(repo)
4982 ms = mergemod.mergestate(repo)
4983 m = scmutil.match(repo[None], pats, opts)
4983 m = scmutil.match(repo[None], pats, opts)
4984 ret = 0
4984 ret = 0
4985
4985
4986 for f in ms:
4986 for f in ms:
4987 if m(f):
4987 if m(f):
4988 if show:
4988 if show:
4989 if nostatus:
4989 if nostatus:
4990 ui.write("%s\n" % f)
4990 ui.write("%s\n" % f)
4991 else:
4991 else:
4992 ui.write("%s %s\n" % (ms[f].upper(), f),
4992 ui.write("%s %s\n" % (ms[f].upper(), f),
4993 label='resolve.' +
4993 label='resolve.' +
4994 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4994 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4995 elif mark:
4995 elif mark:
4996 ms.mark(f, "r")
4996 ms.mark(f, "r")
4997 elif unmark:
4997 elif unmark:
4998 ms.mark(f, "u")
4998 ms.mark(f, "u")
4999 else:
4999 else:
5000 wctx = repo[None]
5000 wctx = repo[None]
5001 mctx = wctx.parents()[-1]
5001 mctx = wctx.parents()[-1]
5002
5002
5003 # backup pre-resolve (merge uses .orig for its own purposes)
5003 # backup pre-resolve (merge uses .orig for its own purposes)
5004 a = repo.wjoin(f)
5004 a = repo.wjoin(f)
5005 util.copyfile(a, a + ".resolve")
5005 util.copyfile(a, a + ".resolve")
5006
5006
5007 try:
5007 try:
5008 # resolve file
5008 # resolve file
5009 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5009 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5010 if ms.resolve(f, wctx, mctx):
5010 if ms.resolve(f, wctx, mctx):
5011 ret = 1
5011 ret = 1
5012 finally:
5012 finally:
5013 ui.setconfig('ui', 'forcemerge', '')
5013 ui.setconfig('ui', 'forcemerge', '')
5014 ms.commit()
5014 ms.commit()
5015
5015
5016 # replace filemerge's .orig file with our resolve file
5016 # replace filemerge's .orig file with our resolve file
5017 util.rename(a + ".resolve", a + ".orig")
5017 util.rename(a + ".resolve", a + ".orig")
5018
5018
5019 ms.commit()
5019 ms.commit()
5020 return ret
5020 return ret
5021
5021
5022 @command('revert',
5022 @command('revert',
5023 [('a', 'all', None, _('revert all changes when no arguments given')),
5023 [('a', 'all', None, _('revert all changes when no arguments given')),
5024 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5024 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5025 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5025 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5026 ('C', 'no-backup', None, _('do not save backup copies of files')),
5026 ('C', 'no-backup', None, _('do not save backup copies of files')),
5027 ] + walkopts + dryrunopts,
5027 ] + walkopts + dryrunopts,
5028 _('[OPTION]... [-r REV] [NAME]...'))
5028 _('[OPTION]... [-r REV] [NAME]...'))
5029 def revert(ui, repo, *pats, **opts):
5029 def revert(ui, repo, *pats, **opts):
5030 """restore files to their checkout state
5030 """restore files to their checkout state
5031
5031
5032 .. note::
5032 .. note::
5033
5033
5034 To check out earlier revisions, you should use :hg:`update REV`.
5034 To check out earlier revisions, you should use :hg:`update REV`.
5035 To cancel an uncommitted merge (and lose your changes), use
5035 To cancel an uncommitted merge (and lose your changes), use
5036 :hg:`update --clean .`.
5036 :hg:`update --clean .`.
5037
5037
5038 With no revision specified, revert the specified files or directories
5038 With no revision specified, revert the specified files or directories
5039 to the contents they had in the parent of the working directory.
5039 to the contents they had in the parent of the working directory.
5040 This restores the contents of files to an unmodified
5040 This restores the contents of files to an unmodified
5041 state and unschedules adds, removes, copies, and renames. If the
5041 state and unschedules adds, removes, copies, and renames. If the
5042 working directory has two parents, you must explicitly specify a
5042 working directory has two parents, you must explicitly specify a
5043 revision.
5043 revision.
5044
5044
5045 Using the -r/--rev or -d/--date options, revert the given files or
5045 Using the -r/--rev or -d/--date options, revert the given files or
5046 directories to their states as of a specific revision. Because
5046 directories to their states as of a specific revision. Because
5047 revert does not change the working directory parents, this will
5047 revert does not change the working directory parents, this will
5048 cause these files to appear modified. This can be helpful to "back
5048 cause these files to appear modified. This can be helpful to "back
5049 out" some or all of an earlier change. See :hg:`backout` for a
5049 out" some or all of an earlier change. See :hg:`backout` for a
5050 related method.
5050 related method.
5051
5051
5052 Modified files are saved with a .orig suffix before reverting.
5052 Modified files are saved with a .orig suffix before reverting.
5053 To disable these backups, use --no-backup.
5053 To disable these backups, use --no-backup.
5054
5054
5055 See :hg:`help dates` for a list of formats valid for -d/--date.
5055 See :hg:`help dates` for a list of formats valid for -d/--date.
5056
5056
5057 Returns 0 on success.
5057 Returns 0 on success.
5058 """
5058 """
5059
5059
5060 if opts.get("date"):
5060 if opts.get("date"):
5061 if opts.get("rev"):
5061 if opts.get("rev"):
5062 raise util.Abort(_("you can't specify a revision and a date"))
5062 raise util.Abort(_("you can't specify a revision and a date"))
5063 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5063 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5064
5064
5065 parent, p2 = repo.dirstate.parents()
5065 parent, p2 = repo.dirstate.parents()
5066 if not opts.get('rev') and p2 != nullid:
5066 if not opts.get('rev') and p2 != nullid:
5067 # revert after merge is a trap for new users (issue2915)
5067 # revert after merge is a trap for new users (issue2915)
5068 raise util.Abort(_('uncommitted merge with no revision specified'),
5068 raise util.Abort(_('uncommitted merge with no revision specified'),
5069 hint=_('use "hg update" or see "hg help revert"'))
5069 hint=_('use "hg update" or see "hg help revert"'))
5070
5070
5071 ctx = scmutil.revsingle(repo, opts.get('rev'))
5071 ctx = scmutil.revsingle(repo, opts.get('rev'))
5072
5072
5073 if not pats and not opts.get('all'):
5073 if not pats and not opts.get('all'):
5074 msg = _("no files or directories specified")
5074 msg = _("no files or directories specified")
5075 if p2 != nullid:
5075 if p2 != nullid:
5076 hint = _("uncommitted merge, use --all to discard all changes,"
5076 hint = _("uncommitted merge, use --all to discard all changes,"
5077 " or 'hg update -C .' to abort the merge")
5077 " or 'hg update -C .' to abort the merge")
5078 raise util.Abort(msg, hint=hint)
5078 raise util.Abort(msg, hint=hint)
5079 dirty = util.any(repo.status())
5079 dirty = util.any(repo.status())
5080 node = ctx.node()
5080 node = ctx.node()
5081 if node != parent:
5081 if node != parent:
5082 if dirty:
5082 if dirty:
5083 hint = _("uncommitted changes, use --all to discard all"
5083 hint = _("uncommitted changes, use --all to discard all"
5084 " changes, or 'hg update %s' to update") % ctx.rev()
5084 " changes, or 'hg update %s' to update") % ctx.rev()
5085 else:
5085 else:
5086 hint = _("use --all to revert all files,"
5086 hint = _("use --all to revert all files,"
5087 " or 'hg update %s' to update") % ctx.rev()
5087 " or 'hg update %s' to update") % ctx.rev()
5088 elif dirty:
5088 elif dirty:
5089 hint = _("uncommitted changes, use --all to discard all changes")
5089 hint = _("uncommitted changes, use --all to discard all changes")
5090 else:
5090 else:
5091 hint = _("use --all to revert all files")
5091 hint = _("use --all to revert all files")
5092 raise util.Abort(msg, hint=hint)
5092 raise util.Abort(msg, hint=hint)
5093
5093
5094 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5094 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5095
5095
5096 @command('rollback', dryrunopts +
5096 @command('rollback', dryrunopts +
5097 [('f', 'force', False, _('ignore safety measures'))])
5097 [('f', 'force', False, _('ignore safety measures'))])
5098 def rollback(ui, repo, **opts):
5098 def rollback(ui, repo, **opts):
5099 """roll back the last transaction (dangerous)
5099 """roll back the last transaction (dangerous)
5100
5100
5101 This command should be used with care. There is only one level of
5101 This command should be used with care. There is only one level of
5102 rollback, and there is no way to undo a rollback. It will also
5102 rollback, and there is no way to undo a rollback. It will also
5103 restore the dirstate at the time of the last transaction, losing
5103 restore the dirstate at the time of the last transaction, losing
5104 any dirstate changes since that time. This command does not alter
5104 any dirstate changes since that time. This command does not alter
5105 the working directory.
5105 the working directory.
5106
5106
5107 Transactions are used to encapsulate the effects of all commands
5107 Transactions are used to encapsulate the effects of all commands
5108 that create new changesets or propagate existing changesets into a
5108 that create new changesets or propagate existing changesets into a
5109 repository.
5109 repository.
5110
5110
5111 .. container:: verbose
5111 .. container:: verbose
5112
5112
5113 For example, the following commands are transactional, and their
5113 For example, the following commands are transactional, and their
5114 effects can be rolled back:
5114 effects can be rolled back:
5115
5115
5116 - commit
5116 - commit
5117 - import
5117 - import
5118 - pull
5118 - pull
5119 - push (with this repository as the destination)
5119 - push (with this repository as the destination)
5120 - unbundle
5120 - unbundle
5121
5121
5122 To avoid permanent data loss, rollback will refuse to rollback a
5122 To avoid permanent data loss, rollback will refuse to rollback a
5123 commit transaction if it isn't checked out. Use --force to
5123 commit transaction if it isn't checked out. Use --force to
5124 override this protection.
5124 override this protection.
5125
5125
5126 This command is not intended for use on public repositories. Once
5126 This command is not intended for use on public repositories. Once
5127 changes are visible for pull by other users, rolling a transaction
5127 changes are visible for pull by other users, rolling a transaction
5128 back locally is ineffective (someone else may already have pulled
5128 back locally is ineffective (someone else may already have pulled
5129 the changes). Furthermore, a race is possible with readers of the
5129 the changes). Furthermore, a race is possible with readers of the
5130 repository; for example an in-progress pull from the repository
5130 repository; for example an in-progress pull from the repository
5131 may fail if a rollback is performed.
5131 may fail if a rollback is performed.
5132
5132
5133 Returns 0 on success, 1 if no rollback data is available.
5133 Returns 0 on success, 1 if no rollback data is available.
5134 """
5134 """
5135 return repo.rollback(dryrun=opts.get('dry_run'),
5135 return repo.rollback(dryrun=opts.get('dry_run'),
5136 force=opts.get('force'))
5136 force=opts.get('force'))
5137
5137
5138 @command('root', [])
5138 @command('root', [])
5139 def root(ui, repo):
5139 def root(ui, repo):
5140 """print the root (top) of the current working directory
5140 """print the root (top) of the current working directory
5141
5141
5142 Print the root directory of the current repository.
5142 Print the root directory of the current repository.
5143
5143
5144 Returns 0 on success.
5144 Returns 0 on success.
5145 """
5145 """
5146 ui.write(repo.root + "\n")
5146 ui.write(repo.root + "\n")
5147
5147
5148 @command('^serve',
5148 @command('^serve',
5149 [('A', 'accesslog', '', _('name of access log file to write to'),
5149 [('A', 'accesslog', '', _('name of access log file to write to'),
5150 _('FILE')),
5150 _('FILE')),
5151 ('d', 'daemon', None, _('run server in background')),
5151 ('d', 'daemon', None, _('run server in background')),
5152 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5152 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5153 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5153 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5154 # use string type, then we can check if something was passed
5154 # use string type, then we can check if something was passed
5155 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5155 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5156 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5156 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5157 _('ADDR')),
5157 _('ADDR')),
5158 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5158 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5159 _('PREFIX')),
5159 _('PREFIX')),
5160 ('n', 'name', '',
5160 ('n', 'name', '',
5161 _('name to show in web pages (default: working directory)'), _('NAME')),
5161 _('name to show in web pages (default: working directory)'), _('NAME')),
5162 ('', 'web-conf', '',
5162 ('', 'web-conf', '',
5163 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5163 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5164 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5164 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5165 _('FILE')),
5165 _('FILE')),
5166 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5166 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5167 ('', 'stdio', None, _('for remote clients')),
5167 ('', 'stdio', None, _('for remote clients')),
5168 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5168 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5169 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5169 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5170 ('', 'style', '', _('template style to use'), _('STYLE')),
5170 ('', 'style', '', _('template style to use'), _('STYLE')),
5171 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5171 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5172 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5172 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5173 _('[OPTION]...'))
5173 _('[OPTION]...'))
5174 def serve(ui, repo, **opts):
5174 def serve(ui, repo, **opts):
5175 """start stand-alone webserver
5175 """start stand-alone webserver
5176
5176
5177 Start a local HTTP repository browser and pull server. You can use
5177 Start a local HTTP repository browser and pull server. You can use
5178 this for ad-hoc sharing and browsing of repositories. It is
5178 this for ad-hoc sharing and browsing of repositories. It is
5179 recommended to use a real web server to serve a repository for
5179 recommended to use a real web server to serve a repository for
5180 longer periods of time.
5180 longer periods of time.
5181
5181
5182 Please note that the server does not implement access control.
5182 Please note that the server does not implement access control.
5183 This means that, by default, anybody can read from the server and
5183 This means that, by default, anybody can read from the server and
5184 nobody can write to it by default. Set the ``web.allow_push``
5184 nobody can write to it by default. Set the ``web.allow_push``
5185 option to ``*`` to allow everybody to push to the server. You
5185 option to ``*`` to allow everybody to push to the server. You
5186 should use a real web server if you need to authenticate users.
5186 should use a real web server if you need to authenticate users.
5187
5187
5188 By default, the server logs accesses to stdout and errors to
5188 By default, the server logs accesses to stdout and errors to
5189 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5189 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5190 files.
5190 files.
5191
5191
5192 To have the server choose a free port number to listen on, specify
5192 To have the server choose a free port number to listen on, specify
5193 a port number of 0; in this case, the server will print the port
5193 a port number of 0; in this case, the server will print the port
5194 number it uses.
5194 number it uses.
5195
5195
5196 Returns 0 on success.
5196 Returns 0 on success.
5197 """
5197 """
5198
5198
5199 if opts["stdio"] and opts["cmdserver"]:
5199 if opts["stdio"] and opts["cmdserver"]:
5200 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5200 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5201
5201
5202 def checkrepo():
5202 def checkrepo():
5203 if repo is None:
5203 if repo is None:
5204 raise error.RepoError(_("there is no Mercurial repository here"
5204 raise error.RepoError(_("there is no Mercurial repository here"
5205 " (.hg not found)"))
5205 " (.hg not found)"))
5206
5206
5207 if opts["stdio"]:
5207 if opts["stdio"]:
5208 checkrepo()
5208 checkrepo()
5209 s = sshserver.sshserver(ui, repo)
5209 s = sshserver.sshserver(ui, repo)
5210 s.serve_forever()
5210 s.serve_forever()
5211
5211
5212 if opts["cmdserver"]:
5212 if opts["cmdserver"]:
5213 checkrepo()
5213 checkrepo()
5214 s = commandserver.server(ui, repo, opts["cmdserver"])
5214 s = commandserver.server(ui, repo, opts["cmdserver"])
5215 return s.serve()
5215 return s.serve()
5216
5216
5217 # this way we can check if something was given in the command-line
5217 # this way we can check if something was given in the command-line
5218 if opts.get('port'):
5218 if opts.get('port'):
5219 opts['port'] = util.getport(opts.get('port'))
5219 opts['port'] = util.getport(opts.get('port'))
5220
5220
5221 baseui = repo and repo.baseui or ui
5221 baseui = repo and repo.baseui or ui
5222 optlist = ("name templates style address port prefix ipv6"
5222 optlist = ("name templates style address port prefix ipv6"
5223 " accesslog errorlog certificate encoding")
5223 " accesslog errorlog certificate encoding")
5224 for o in optlist.split():
5224 for o in optlist.split():
5225 val = opts.get(o, '')
5225 val = opts.get(o, '')
5226 if val in (None, ''): # should check against default options instead
5226 if val in (None, ''): # should check against default options instead
5227 continue
5227 continue
5228 baseui.setconfig("web", o, val)
5228 baseui.setconfig("web", o, val)
5229 if repo and repo.ui != baseui:
5229 if repo and repo.ui != baseui:
5230 repo.ui.setconfig("web", o, val)
5230 repo.ui.setconfig("web", o, val)
5231
5231
5232 o = opts.get('web_conf') or opts.get('webdir_conf')
5232 o = opts.get('web_conf') or opts.get('webdir_conf')
5233 if not o:
5233 if not o:
5234 if not repo:
5234 if not repo:
5235 raise error.RepoError(_("there is no Mercurial repository"
5235 raise error.RepoError(_("there is no Mercurial repository"
5236 " here (.hg not found)"))
5236 " here (.hg not found)"))
5237 o = repo.root
5237 o = repo.root
5238
5238
5239 app = hgweb.hgweb(o, baseui=ui)
5239 app = hgweb.hgweb(o, baseui=ui)
5240
5240
5241 class service(object):
5241 class service(object):
5242 def init(self):
5242 def init(self):
5243 util.setsignalhandler()
5243 util.setsignalhandler()
5244 self.httpd = hgweb.server.create_server(ui, app)
5244 self.httpd = hgweb.server.create_server(ui, app)
5245
5245
5246 if opts['port'] and not ui.verbose:
5246 if opts['port'] and not ui.verbose:
5247 return
5247 return
5248
5248
5249 if self.httpd.prefix:
5249 if self.httpd.prefix:
5250 prefix = self.httpd.prefix.strip('/') + '/'
5250 prefix = self.httpd.prefix.strip('/') + '/'
5251 else:
5251 else:
5252 prefix = ''
5252 prefix = ''
5253
5253
5254 port = ':%d' % self.httpd.port
5254 port = ':%d' % self.httpd.port
5255 if port == ':80':
5255 if port == ':80':
5256 port = ''
5256 port = ''
5257
5257
5258 bindaddr = self.httpd.addr
5258 bindaddr = self.httpd.addr
5259 if bindaddr == '0.0.0.0':
5259 if bindaddr == '0.0.0.0':
5260 bindaddr = '*'
5260 bindaddr = '*'
5261 elif ':' in bindaddr: # IPv6
5261 elif ':' in bindaddr: # IPv6
5262 bindaddr = '[%s]' % bindaddr
5262 bindaddr = '[%s]' % bindaddr
5263
5263
5264 fqaddr = self.httpd.fqaddr
5264 fqaddr = self.httpd.fqaddr
5265 if ':' in fqaddr:
5265 if ':' in fqaddr:
5266 fqaddr = '[%s]' % fqaddr
5266 fqaddr = '[%s]' % fqaddr
5267 if opts['port']:
5267 if opts['port']:
5268 write = ui.status
5268 write = ui.status
5269 else:
5269 else:
5270 write = ui.write
5270 write = ui.write
5271 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5271 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5272 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5272 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5273
5273
5274 def run(self):
5274 def run(self):
5275 self.httpd.serve_forever()
5275 self.httpd.serve_forever()
5276
5276
5277 service = service()
5277 service = service()
5278
5278
5279 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5279 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5280
5280
5281 @command('showconfig|debugconfig',
5281 @command('showconfig|debugconfig',
5282 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5282 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5283 _('[-u] [NAME]...'))
5283 _('[-u] [NAME]...'))
5284 def showconfig(ui, repo, *values, **opts):
5284 def showconfig(ui, repo, *values, **opts):
5285 """show combined config settings from all hgrc files
5285 """show combined config settings from all hgrc files
5286
5286
5287 With no arguments, print names and values of all config items.
5287 With no arguments, print names and values of all config items.
5288
5288
5289 With one argument of the form section.name, print just the value
5289 With one argument of the form section.name, print just the value
5290 of that config item.
5290 of that config item.
5291
5291
5292 With multiple arguments, print names and values of all config
5292 With multiple arguments, print names and values of all config
5293 items with matching section names.
5293 items with matching section names.
5294
5294
5295 With --debug, the source (filename and line number) is printed
5295 With --debug, the source (filename and line number) is printed
5296 for each config item.
5296 for each config item.
5297
5297
5298 Returns 0 on success.
5298 Returns 0 on success.
5299 """
5299 """
5300
5300
5301 for f in scmutil.rcpath():
5301 for f in scmutil.rcpath():
5302 ui.debug('read config from: %s\n' % f)
5302 ui.debug('read config from: %s\n' % f)
5303 untrusted = bool(opts.get('untrusted'))
5303 untrusted = bool(opts.get('untrusted'))
5304 if values:
5304 if values:
5305 sections = [v for v in values if '.' not in v]
5305 sections = [v for v in values if '.' not in v]
5306 items = [v for v in values if '.' in v]
5306 items = [v for v in values if '.' in v]
5307 if len(items) > 1 or items and sections:
5307 if len(items) > 1 or items and sections:
5308 raise util.Abort(_('only one config item permitted'))
5308 raise util.Abort(_('only one config item permitted'))
5309 for section, name, value in ui.walkconfig(untrusted=untrusted):
5309 for section, name, value in ui.walkconfig(untrusted=untrusted):
5310 value = str(value).replace('\n', '\\n')
5310 value = str(value).replace('\n', '\\n')
5311 sectname = section + '.' + name
5311 sectname = section + '.' + name
5312 if values:
5312 if values:
5313 for v in values:
5313 for v in values:
5314 if v == section:
5314 if v == section:
5315 ui.debug('%s: ' %
5315 ui.debug('%s: ' %
5316 ui.configsource(section, name, untrusted))
5316 ui.configsource(section, name, untrusted))
5317 ui.write('%s=%s\n' % (sectname, value))
5317 ui.write('%s=%s\n' % (sectname, value))
5318 elif v == sectname:
5318 elif v == sectname:
5319 ui.debug('%s: ' %
5319 ui.debug('%s: ' %
5320 ui.configsource(section, name, untrusted))
5320 ui.configsource(section, name, untrusted))
5321 ui.write(value, '\n')
5321 ui.write(value, '\n')
5322 else:
5322 else:
5323 ui.debug('%s: ' %
5323 ui.debug('%s: ' %
5324 ui.configsource(section, name, untrusted))
5324 ui.configsource(section, name, untrusted))
5325 ui.write('%s=%s\n' % (sectname, value))
5325 ui.write('%s=%s\n' % (sectname, value))
5326
5326
5327 @command('^status|st',
5327 @command('^status|st',
5328 [('A', 'all', None, _('show status of all files')),
5328 [('A', 'all', None, _('show status of all files')),
5329 ('m', 'modified', None, _('show only modified files')),
5329 ('m', 'modified', None, _('show only modified files')),
5330 ('a', 'added', None, _('show only added files')),
5330 ('a', 'added', None, _('show only added files')),
5331 ('r', 'removed', None, _('show only removed files')),
5331 ('r', 'removed', None, _('show only removed files')),
5332 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5332 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5333 ('c', 'clean', None, _('show only files without changes')),
5333 ('c', 'clean', None, _('show only files without changes')),
5334 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5334 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5335 ('i', 'ignored', None, _('show only ignored files')),
5335 ('i', 'ignored', None, _('show only ignored files')),
5336 ('n', 'no-status', None, _('hide status prefix')),
5336 ('n', 'no-status', None, _('hide status prefix')),
5337 ('C', 'copies', None, _('show source of copied files')),
5337 ('C', 'copies', None, _('show source of copied files')),
5338 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5338 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5339 ('', 'rev', [], _('show difference from revision'), _('REV')),
5339 ('', 'rev', [], _('show difference from revision'), _('REV')),
5340 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5340 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5341 ] + walkopts + subrepoopts,
5341 ] + walkopts + subrepoopts,
5342 _('[OPTION]... [FILE]...'))
5342 _('[OPTION]... [FILE]...'))
5343 def status(ui, repo, *pats, **opts):
5343 def status(ui, repo, *pats, **opts):
5344 """show changed files in the working directory
5344 """show changed files in the working directory
5345
5345
5346 Show status of files in the repository. If names are given, only
5346 Show status of files in the repository. If names are given, only
5347 files that match are shown. Files that are clean or ignored or
5347 files that match are shown. Files that are clean or ignored or
5348 the source of a copy/move operation, are not listed unless
5348 the source of a copy/move operation, are not listed unless
5349 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5349 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5350 Unless options described with "show only ..." are given, the
5350 Unless options described with "show only ..." are given, the
5351 options -mardu are used.
5351 options -mardu are used.
5352
5352
5353 Option -q/--quiet hides untracked (unknown and ignored) files
5353 Option -q/--quiet hides untracked (unknown and ignored) files
5354 unless explicitly requested with -u/--unknown or -i/--ignored.
5354 unless explicitly requested with -u/--unknown or -i/--ignored.
5355
5355
5356 .. note::
5356 .. note::
5357 status may appear to disagree with diff if permissions have
5357 status may appear to disagree with diff if permissions have
5358 changed or a merge has occurred. The standard diff format does
5358 changed or a merge has occurred. The standard diff format does
5359 not report permission changes and diff only reports changes
5359 not report permission changes and diff only reports changes
5360 relative to one merge parent.
5360 relative to one merge parent.
5361
5361
5362 If one revision is given, it is used as the base revision.
5362 If one revision is given, it is used as the base revision.
5363 If two revisions are given, the differences between them are
5363 If two revisions are given, the differences between them are
5364 shown. The --change option can also be used as a shortcut to list
5364 shown. The --change option can also be used as a shortcut to list
5365 the changed files of a revision from its first parent.
5365 the changed files of a revision from its first parent.
5366
5366
5367 The codes used to show the status of files are::
5367 The codes used to show the status of files are::
5368
5368
5369 M = modified
5369 M = modified
5370 A = added
5370 A = added
5371 R = removed
5371 R = removed
5372 C = clean
5372 C = clean
5373 ! = missing (deleted by non-hg command, but still tracked)
5373 ! = missing (deleted by non-hg command, but still tracked)
5374 ? = not tracked
5374 ? = not tracked
5375 I = ignored
5375 I = ignored
5376 = origin of the previous file listed as A (added)
5376 = origin of the previous file listed as A (added)
5377
5377
5378 .. container:: verbose
5378 .. container:: verbose
5379
5379
5380 Examples:
5380 Examples:
5381
5381
5382 - show changes in the working directory relative to a
5382 - show changes in the working directory relative to a
5383 changeset::
5383 changeset::
5384
5384
5385 hg status --rev 9353
5385 hg status --rev 9353
5386
5386
5387 - show all changes including copies in an existing changeset::
5387 - show all changes including copies in an existing changeset::
5388
5388
5389 hg status --copies --change 9353
5389 hg status --copies --change 9353
5390
5390
5391 - get a NUL separated list of added files, suitable for xargs::
5391 - get a NUL separated list of added files, suitable for xargs::
5392
5392
5393 hg status -an0
5393 hg status -an0
5394
5394
5395 Returns 0 on success.
5395 Returns 0 on success.
5396 """
5396 """
5397
5397
5398 revs = opts.get('rev')
5398 revs = opts.get('rev')
5399 change = opts.get('change')
5399 change = opts.get('change')
5400
5400
5401 if revs and change:
5401 if revs and change:
5402 msg = _('cannot specify --rev and --change at the same time')
5402 msg = _('cannot specify --rev and --change at the same time')
5403 raise util.Abort(msg)
5403 raise util.Abort(msg)
5404 elif change:
5404 elif change:
5405 node2 = scmutil.revsingle(repo, change, None).node()
5405 node2 = scmutil.revsingle(repo, change, None).node()
5406 node1 = repo[node2].p1().node()
5406 node1 = repo[node2].p1().node()
5407 else:
5407 else:
5408 node1, node2 = scmutil.revpair(repo, revs)
5408 node1, node2 = scmutil.revpair(repo, revs)
5409
5409
5410 cwd = (pats and repo.getcwd()) or ''
5410 cwd = (pats and repo.getcwd()) or ''
5411 end = opts.get('print0') and '\0' or '\n'
5411 end = opts.get('print0') and '\0' or '\n'
5412 copy = {}
5412 copy = {}
5413 states = 'modified added removed deleted unknown ignored clean'.split()
5413 states = 'modified added removed deleted unknown ignored clean'.split()
5414 show = [k for k in states if opts.get(k)]
5414 show = [k for k in states if opts.get(k)]
5415 if opts.get('all'):
5415 if opts.get('all'):
5416 show += ui.quiet and (states[:4] + ['clean']) or states
5416 show += ui.quiet and (states[:4] + ['clean']) or states
5417 if not show:
5417 if not show:
5418 show = ui.quiet and states[:4] or states[:5]
5418 show = ui.quiet and states[:4] or states[:5]
5419
5419
5420 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5420 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5421 'ignored' in show, 'clean' in show, 'unknown' in show,
5421 'ignored' in show, 'clean' in show, 'unknown' in show,
5422 opts.get('subrepos'))
5422 opts.get('subrepos'))
5423 changestates = zip(states, 'MAR!?IC', stat)
5423 changestates = zip(states, 'MAR!?IC', stat)
5424
5424
5425 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5425 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5426 copy = copies.pathcopies(repo[node1], repo[node2])
5426 copy = copies.pathcopies(repo[node1], repo[node2])
5427
5427
5428 fm = ui.formatter('status', opts)
5428 fm = ui.formatter('status', opts)
5429 format = '%s %s' + end
5429 format = '%s %s' + end
5430 if opts.get('no_status'):
5430 if opts.get('no_status'):
5431 format = '%.0s%s' + end
5431 format = '%.0s%s' + end
5432
5432
5433 for state, char, files in changestates:
5433 for state, char, files in changestates:
5434 if state in show:
5434 if state in show:
5435 label = 'status.' + state
5435 label = 'status.' + state
5436 for f in files:
5436 for f in files:
5437 fm.startitem()
5437 fm.startitem()
5438 fm.write("status path", format, char,
5438 fm.write("status path", format, char,
5439 repo.pathto(f, cwd), label=label)
5439 repo.pathto(f, cwd), label=label)
5440 if f in copy:
5440 if f in copy:
5441 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5441 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5442 label='status.copied')
5442 label='status.copied')
5443 fm.end()
5443 fm.end()
5444
5444
5445 @command('^summary|sum',
5445 @command('^summary|sum',
5446 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5446 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5447 def summary(ui, repo, **opts):
5447 def summary(ui, repo, **opts):
5448 """summarize working directory state
5448 """summarize working directory state
5449
5449
5450 This generates a brief summary of the working directory state,
5450 This generates a brief summary of the working directory state,
5451 including parents, branch, commit status, and available updates.
5451 including parents, branch, commit status, and available updates.
5452
5452
5453 With the --remote option, this will check the default paths for
5453 With the --remote option, this will check the default paths for
5454 incoming and outgoing changes. This can be time-consuming.
5454 incoming and outgoing changes. This can be time-consuming.
5455
5455
5456 Returns 0 on success.
5456 Returns 0 on success.
5457 """
5457 """
5458
5458
5459 ctx = repo[None]
5459 ctx = repo[None]
5460 parents = ctx.parents()
5460 parents = ctx.parents()
5461 pnode = parents[0].node()
5461 pnode = parents[0].node()
5462 marks = []
5462 marks = []
5463
5463
5464 for p in parents:
5464 for p in parents:
5465 # label with log.changeset (instead of log.parent) since this
5465 # label with log.changeset (instead of log.parent) since this
5466 # shows a working directory parent *changeset*:
5466 # shows a working directory parent *changeset*:
5467 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5467 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5468 label='log.changeset changeset.%s' % p.phasestr())
5468 label='log.changeset changeset.%s' % p.phasestr())
5469 ui.write(' '.join(p.tags()), label='log.tag')
5469 ui.write(' '.join(p.tags()), label='log.tag')
5470 if p.bookmarks():
5470 if p.bookmarks():
5471 marks.extend(p.bookmarks())
5471 marks.extend(p.bookmarks())
5472 if p.rev() == -1:
5472 if p.rev() == -1:
5473 if not len(repo):
5473 if not len(repo):
5474 ui.write(_(' (empty repository)'))
5474 ui.write(_(' (empty repository)'))
5475 else:
5475 else:
5476 ui.write(_(' (no revision checked out)'))
5476 ui.write(_(' (no revision checked out)'))
5477 ui.write('\n')
5477 ui.write('\n')
5478 if p.description():
5478 if p.description():
5479 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5479 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5480 label='log.summary')
5480 label='log.summary')
5481
5481
5482 branch = ctx.branch()
5482 branch = ctx.branch()
5483 bheads = repo.branchheads(branch)
5483 bheads = repo.branchheads(branch)
5484 m = _('branch: %s\n') % branch
5484 m = _('branch: %s\n') % branch
5485 if branch != 'default':
5485 if branch != 'default':
5486 ui.write(m, label='log.branch')
5486 ui.write(m, label='log.branch')
5487 else:
5487 else:
5488 ui.status(m, label='log.branch')
5488 ui.status(m, label='log.branch')
5489
5489
5490 if marks:
5490 if marks:
5491 current = repo._bookmarkcurrent
5491 current = repo._bookmarkcurrent
5492 ui.write(_('bookmarks:'), label='log.bookmark')
5492 ui.write(_('bookmarks:'), label='log.bookmark')
5493 if current is not None:
5493 if current is not None:
5494 try:
5494 try:
5495 marks.remove(current)
5495 marks.remove(current)
5496 ui.write(' *' + current, label='bookmarks.current')
5496 ui.write(' *' + current, label='bookmarks.current')
5497 except ValueError:
5497 except ValueError:
5498 # current bookmark not in parent ctx marks
5498 # current bookmark not in parent ctx marks
5499 pass
5499 pass
5500 for m in marks:
5500 for m in marks:
5501 ui.write(' ' + m, label='log.bookmark')
5501 ui.write(' ' + m, label='log.bookmark')
5502 ui.write('\n', label='log.bookmark')
5502 ui.write('\n', label='log.bookmark')
5503
5503
5504 st = list(repo.status(unknown=True))[:6]
5504 st = list(repo.status(unknown=True))[:6]
5505
5505
5506 c = repo.dirstate.copies()
5506 c = repo.dirstate.copies()
5507 copied, renamed = [], []
5507 copied, renamed = [], []
5508 for d, s in c.iteritems():
5508 for d, s in c.iteritems():
5509 if s in st[2]:
5509 if s in st[2]:
5510 st[2].remove(s)
5510 st[2].remove(s)
5511 renamed.append(d)
5511 renamed.append(d)
5512 else:
5512 else:
5513 copied.append(d)
5513 copied.append(d)
5514 if d in st[1]:
5514 if d in st[1]:
5515 st[1].remove(d)
5515 st[1].remove(d)
5516 st.insert(3, renamed)
5516 st.insert(3, renamed)
5517 st.insert(4, copied)
5517 st.insert(4, copied)
5518
5518
5519 ms = mergemod.mergestate(repo)
5519 ms = mergemod.mergestate(repo)
5520 st.append([f for f in ms if ms[f] == 'u'])
5520 st.append([f for f in ms if ms[f] == 'u'])
5521
5521
5522 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5522 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5523 st.append(subs)
5523 st.append(subs)
5524
5524
5525 labels = [ui.label(_('%d modified'), 'status.modified'),
5525 labels = [ui.label(_('%d modified'), 'status.modified'),
5526 ui.label(_('%d added'), 'status.added'),
5526 ui.label(_('%d added'), 'status.added'),
5527 ui.label(_('%d removed'), 'status.removed'),
5527 ui.label(_('%d removed'), 'status.removed'),
5528 ui.label(_('%d renamed'), 'status.copied'),
5528 ui.label(_('%d renamed'), 'status.copied'),
5529 ui.label(_('%d copied'), 'status.copied'),
5529 ui.label(_('%d copied'), 'status.copied'),
5530 ui.label(_('%d deleted'), 'status.deleted'),
5530 ui.label(_('%d deleted'), 'status.deleted'),
5531 ui.label(_('%d unknown'), 'status.unknown'),
5531 ui.label(_('%d unknown'), 'status.unknown'),
5532 ui.label(_('%d ignored'), 'status.ignored'),
5532 ui.label(_('%d ignored'), 'status.ignored'),
5533 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5533 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5534 ui.label(_('%d subrepos'), 'status.modified')]
5534 ui.label(_('%d subrepos'), 'status.modified')]
5535 t = []
5535 t = []
5536 for s, l in zip(st, labels):
5536 for s, l in zip(st, labels):
5537 if s:
5537 if s:
5538 t.append(l % len(s))
5538 t.append(l % len(s))
5539
5539
5540 t = ', '.join(t)
5540 t = ', '.join(t)
5541 cleanworkdir = False
5541 cleanworkdir = False
5542
5542
5543 if len(parents) > 1:
5543 if len(parents) > 1:
5544 t += _(' (merge)')
5544 t += _(' (merge)')
5545 elif branch != parents[0].branch():
5545 elif branch != parents[0].branch():
5546 t += _(' (new branch)')
5546 t += _(' (new branch)')
5547 elif (parents[0].closesbranch() and
5547 elif (parents[0].closesbranch() and
5548 pnode in repo.branchheads(branch, closed=True)):
5548 pnode in repo.branchheads(branch, closed=True)):
5549 t += _(' (head closed)')
5549 t += _(' (head closed)')
5550 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5550 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5551 t += _(' (clean)')
5551 t += _(' (clean)')
5552 cleanworkdir = True
5552 cleanworkdir = True
5553 elif pnode not in bheads:
5553 elif pnode not in bheads:
5554 t += _(' (new branch head)')
5554 t += _(' (new branch head)')
5555
5555
5556 if cleanworkdir:
5556 if cleanworkdir:
5557 ui.status(_('commit: %s\n') % t.strip())
5557 ui.status(_('commit: %s\n') % t.strip())
5558 else:
5558 else:
5559 ui.write(_('commit: %s\n') % t.strip())
5559 ui.write(_('commit: %s\n') % t.strip())
5560
5560
5561 # all ancestors of branch heads - all ancestors of parent = new csets
5561 # all ancestors of branch heads - all ancestors of parent = new csets
5562 new = [0] * len(repo)
5562 new = [0] * len(repo)
5563 cl = repo.changelog
5563 cl = repo.changelog
5564 for a in [cl.rev(n) for n in bheads]:
5564 for a in [cl.rev(n) for n in bheads]:
5565 new[a] = 1
5565 new[a] = 1
5566 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5566 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5567 new[a] = 1
5567 new[a] = 1
5568 for a in [p.rev() for p in parents]:
5568 for a in [p.rev() for p in parents]:
5569 if a >= 0:
5569 if a >= 0:
5570 new[a] = 0
5570 new[a] = 0
5571 for a in cl.ancestors([p.rev() for p in parents]):
5571 for a in cl.ancestors([p.rev() for p in parents]):
5572 new[a] = 0
5572 new[a] = 0
5573 new = sum(new)
5573 new = sum(new)
5574
5574
5575 if new == 0:
5575 if new == 0:
5576 ui.status(_('update: (current)\n'))
5576 ui.status(_('update: (current)\n'))
5577 elif pnode not in bheads:
5577 elif pnode not in bheads:
5578 ui.write(_('update: %d new changesets (update)\n') % new)
5578 ui.write(_('update: %d new changesets (update)\n') % new)
5579 else:
5579 else:
5580 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5580 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5581 (new, len(bheads)))
5581 (new, len(bheads)))
5582
5582
5583 if opts.get('remote'):
5583 if opts.get('remote'):
5584 t = []
5584 t = []
5585 source, branches = hg.parseurl(ui.expandpath('default'))
5585 source, branches = hg.parseurl(ui.expandpath('default'))
5586 other = hg.peer(repo, {}, source)
5586 other = hg.peer(repo, {}, source)
5587 revs, checkout = hg.addbranchrevs(repo, other, branches,
5587 revs, checkout = hg.addbranchrevs(repo, other, branches,
5588 opts.get('rev'))
5588 opts.get('rev'))
5589 ui.debug('comparing with %s\n' % util.hidepassword(source))
5589 ui.debug('comparing with %s\n' % util.hidepassword(source))
5590 repo.ui.pushbuffer()
5590 repo.ui.pushbuffer()
5591 commoninc = discovery.findcommonincoming(repo, other)
5591 commoninc = discovery.findcommonincoming(repo, other)
5592 _common, incoming, _rheads = commoninc
5592 _common, incoming, _rheads = commoninc
5593 repo.ui.popbuffer()
5593 repo.ui.popbuffer()
5594 if incoming:
5594 if incoming:
5595 t.append(_('1 or more incoming'))
5595 t.append(_('1 or more incoming'))
5596
5596
5597 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5597 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5598 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5598 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5599 if source != dest:
5599 if source != dest:
5600 other = hg.peer(repo, {}, dest)
5600 other = hg.peer(repo, {}, dest)
5601 commoninc = None
5601 commoninc = None
5602 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5602 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5603 repo.ui.pushbuffer()
5603 repo.ui.pushbuffer()
5604 outgoing = discovery.findcommonoutgoing(repo, other,
5604 outgoing = discovery.findcommonoutgoing(repo, other,
5605 commoninc=commoninc)
5605 commoninc=commoninc)
5606 repo.ui.popbuffer()
5606 repo.ui.popbuffer()
5607 o = outgoing.missing
5607 o = outgoing.missing
5608 if o:
5608 if o:
5609 t.append(_('%d outgoing') % len(o))
5609 t.append(_('%d outgoing') % len(o))
5610 if 'bookmarks' in other.listkeys('namespaces'):
5610 if 'bookmarks' in other.listkeys('namespaces'):
5611 lmarks = repo.listkeys('bookmarks')
5611 lmarks = repo.listkeys('bookmarks')
5612 rmarks = other.listkeys('bookmarks')
5612 rmarks = other.listkeys('bookmarks')
5613 diff = set(rmarks) - set(lmarks)
5613 diff = set(rmarks) - set(lmarks)
5614 if len(diff) > 0:
5614 if len(diff) > 0:
5615 t.append(_('%d incoming bookmarks') % len(diff))
5615 t.append(_('%d incoming bookmarks') % len(diff))
5616 diff = set(lmarks) - set(rmarks)
5616 diff = set(lmarks) - set(rmarks)
5617 if len(diff) > 0:
5617 if len(diff) > 0:
5618 t.append(_('%d outgoing bookmarks') % len(diff))
5618 t.append(_('%d outgoing bookmarks') % len(diff))
5619
5619
5620 if t:
5620 if t:
5621 ui.write(_('remote: %s\n') % (', '.join(t)))
5621 ui.write(_('remote: %s\n') % (', '.join(t)))
5622 else:
5622 else:
5623 ui.status(_('remote: (synced)\n'))
5623 ui.status(_('remote: (synced)\n'))
5624
5624
5625 @command('tag',
5625 @command('tag',
5626 [('f', 'force', None, _('force tag')),
5626 [('f', 'force', None, _('force tag')),
5627 ('l', 'local', None, _('make the tag local')),
5627 ('l', 'local', None, _('make the tag local')),
5628 ('r', 'rev', '', _('revision to tag'), _('REV')),
5628 ('r', 'rev', '', _('revision to tag'), _('REV')),
5629 ('', 'remove', None, _('remove a tag')),
5629 ('', 'remove', None, _('remove a tag')),
5630 # -l/--local is already there, commitopts cannot be used
5630 # -l/--local is already there, commitopts cannot be used
5631 ('e', 'edit', None, _('edit commit message')),
5631 ('e', 'edit', None, _('edit commit message')),
5632 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5632 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5633 ] + commitopts2,
5633 ] + commitopts2,
5634 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5634 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5635 def tag(ui, repo, name1, *names, **opts):
5635 def tag(ui, repo, name1, *names, **opts):
5636 """add one or more tags for the current or given revision
5636 """add one or more tags for the current or given revision
5637
5637
5638 Name a particular revision using <name>.
5638 Name a particular revision using <name>.
5639
5639
5640 Tags are used to name particular revisions of the repository and are
5640 Tags are used to name particular revisions of the repository and are
5641 very useful to compare different revisions, to go back to significant
5641 very useful to compare different revisions, to go back to significant
5642 earlier versions or to mark branch points as releases, etc. Changing
5642 earlier versions or to mark branch points as releases, etc. Changing
5643 an existing tag is normally disallowed; use -f/--force to override.
5643 an existing tag is normally disallowed; use -f/--force to override.
5644
5644
5645 If no revision is given, the parent of the working directory is
5645 If no revision is given, the parent of the working directory is
5646 used, or tip if no revision is checked out.
5646 used, or tip if no revision is checked out.
5647
5647
5648 To facilitate version control, distribution, and merging of tags,
5648 To facilitate version control, distribution, and merging of tags,
5649 they are stored as a file named ".hgtags" which is managed similarly
5649 they are stored as a file named ".hgtags" which is managed similarly
5650 to other project files and can be hand-edited if necessary. This
5650 to other project files and can be hand-edited if necessary. This
5651 also means that tagging creates a new commit. The file
5651 also means that tagging creates a new commit. The file
5652 ".hg/localtags" is used for local tags (not shared among
5652 ".hg/localtags" is used for local tags (not shared among
5653 repositories).
5653 repositories).
5654
5654
5655 Tag commits are usually made at the head of a branch. If the parent
5655 Tag commits are usually made at the head of a branch. If the parent
5656 of the working directory is not a branch head, :hg:`tag` aborts; use
5656 of the working directory is not a branch head, :hg:`tag` aborts; use
5657 -f/--force to force the tag commit to be based on a non-head
5657 -f/--force to force the tag commit to be based on a non-head
5658 changeset.
5658 changeset.
5659
5659
5660 See :hg:`help dates` for a list of formats valid for -d/--date.
5660 See :hg:`help dates` for a list of formats valid for -d/--date.
5661
5661
5662 Since tag names have priority over branch names during revision
5662 Since tag names have priority over branch names during revision
5663 lookup, using an existing branch name as a tag name is discouraged.
5663 lookup, using an existing branch name as a tag name is discouraged.
5664
5664
5665 Returns 0 on success.
5665 Returns 0 on success.
5666 """
5666 """
5667 wlock = lock = None
5667 wlock = lock = None
5668 try:
5668 try:
5669 wlock = repo.wlock()
5669 wlock = repo.wlock()
5670 lock = repo.lock()
5670 lock = repo.lock()
5671 rev_ = "."
5671 rev_ = "."
5672 names = [t.strip() for t in (name1,) + names]
5672 names = [t.strip() for t in (name1,) + names]
5673 if len(names) != len(set(names)):
5673 if len(names) != len(set(names)):
5674 raise util.Abort(_('tag names must be unique'))
5674 raise util.Abort(_('tag names must be unique'))
5675 for n in names:
5675 for n in names:
5676 scmutil.checknewlabel(repo, n, 'tag')
5676 scmutil.checknewlabel(repo, n, 'tag')
5677 if not n:
5677 if not n:
5678 raise util.Abort(_('tag names cannot consist entirely of '
5678 raise util.Abort(_('tag names cannot consist entirely of '
5679 'whitespace'))
5679 'whitespace'))
5680 if opts.get('rev') and opts.get('remove'):
5680 if opts.get('rev') and opts.get('remove'):
5681 raise util.Abort(_("--rev and --remove are incompatible"))
5681 raise util.Abort(_("--rev and --remove are incompatible"))
5682 if opts.get('rev'):
5682 if opts.get('rev'):
5683 rev_ = opts['rev']
5683 rev_ = opts['rev']
5684 message = opts.get('message')
5684 message = opts.get('message')
5685 if opts.get('remove'):
5685 if opts.get('remove'):
5686 expectedtype = opts.get('local') and 'local' or 'global'
5686 expectedtype = opts.get('local') and 'local' or 'global'
5687 for n in names:
5687 for n in names:
5688 if not repo.tagtype(n):
5688 if not repo.tagtype(n):
5689 raise util.Abort(_("tag '%s' does not exist") % n)
5689 raise util.Abort(_("tag '%s' does not exist") % n)
5690 if repo.tagtype(n) != expectedtype:
5690 if repo.tagtype(n) != expectedtype:
5691 if expectedtype == 'global':
5691 if expectedtype == 'global':
5692 raise util.Abort(_("tag '%s' is not a global tag") % n)
5692 raise util.Abort(_("tag '%s' is not a global tag") % n)
5693 else:
5693 else:
5694 raise util.Abort(_("tag '%s' is not a local tag") % n)
5694 raise util.Abort(_("tag '%s' is not a local tag") % n)
5695 rev_ = nullid
5695 rev_ = nullid
5696 if not message:
5696 if not message:
5697 # we don't translate commit messages
5697 # we don't translate commit messages
5698 message = 'Removed tag %s' % ', '.join(names)
5698 message = 'Removed tag %s' % ', '.join(names)
5699 elif not opts.get('force'):
5699 elif not opts.get('force'):
5700 for n in names:
5700 for n in names:
5701 if n in repo.tags():
5701 if n in repo.tags():
5702 raise util.Abort(_("tag '%s' already exists "
5702 raise util.Abort(_("tag '%s' already exists "
5703 "(use -f to force)") % n)
5703 "(use -f to force)") % n)
5704 if not opts.get('local'):
5704 if not opts.get('local'):
5705 p1, p2 = repo.dirstate.parents()
5705 p1, p2 = repo.dirstate.parents()
5706 if p2 != nullid:
5706 if p2 != nullid:
5707 raise util.Abort(_('uncommitted merge'))
5707 raise util.Abort(_('uncommitted merge'))
5708 bheads = repo.branchheads()
5708 bheads = repo.branchheads()
5709 if not opts.get('force') and bheads and p1 not in bheads:
5709 if not opts.get('force') and bheads and p1 not in bheads:
5710 raise util.Abort(_('not at a branch head (use -f to force)'))
5710 raise util.Abort(_('not at a branch head (use -f to force)'))
5711 r = scmutil.revsingle(repo, rev_).node()
5711 r = scmutil.revsingle(repo, rev_).node()
5712
5712
5713 if not message:
5713 if not message:
5714 # we don't translate commit messages
5714 # we don't translate commit messages
5715 message = ('Added tag %s for changeset %s' %
5715 message = ('Added tag %s for changeset %s' %
5716 (', '.join(names), short(r)))
5716 (', '.join(names), short(r)))
5717
5717
5718 date = opts.get('date')
5718 date = opts.get('date')
5719 if date:
5719 if date:
5720 date = util.parsedate(date)
5720 date = util.parsedate(date)
5721
5721
5722 if opts.get('edit'):
5722 if opts.get('edit'):
5723 message = ui.edit(message, ui.username())
5723 message = ui.edit(message, ui.username())
5724
5724
5725 # don't allow tagging the null rev
5725 # don't allow tagging the null rev
5726 if (not opts.get('remove') and
5726 if (not opts.get('remove') and
5727 scmutil.revsingle(repo, rev_).rev() == nullrev):
5727 scmutil.revsingle(repo, rev_).rev() == nullrev):
5728 raise util.Abort(_("null revision specified"))
5728 raise util.Abort(_("null revision specified"))
5729
5729
5730 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5730 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5731 finally:
5731 finally:
5732 release(lock, wlock)
5732 release(lock, wlock)
5733
5733
5734 @command('tags', [], '')
5734 @command('tags', [], '')
5735 def tags(ui, repo):
5735 def tags(ui, repo):
5736 """list repository tags
5736 """list repository tags
5737
5737
5738 This lists both regular and local tags. When the -v/--verbose
5738 This lists both regular and local tags. When the -v/--verbose
5739 switch is used, a third column "local" is printed for local tags.
5739 switch is used, a third column "local" is printed for local tags.
5740
5740
5741 Returns 0 on success.
5741 Returns 0 on success.
5742 """
5742 """
5743
5743
5744 hexfunc = ui.debugflag and hex or short
5744 hexfunc = ui.debugflag and hex or short
5745 tagtype = ""
5745 tagtype = ""
5746
5746
5747 for t, n in reversed(repo.tagslist()):
5747 for t, n in reversed(repo.tagslist()):
5748 if ui.quiet:
5748 if ui.quiet:
5749 ui.write("%s\n" % t, label='tags.normal')
5749 ui.write("%s\n" % t, label='tags.normal')
5750 continue
5750 continue
5751
5751
5752 hn = hexfunc(n)
5752 hn = hexfunc(n)
5753 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5753 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5754 rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr())
5754 rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr())
5755 spaces = " " * (30 - encoding.colwidth(t))
5755 spaces = " " * (30 - encoding.colwidth(t))
5756
5756
5757 tag = ui.label(t, 'tags.normal')
5757 tag = ui.label(t, 'tags.normal')
5758 if ui.verbose:
5758 if ui.verbose:
5759 if repo.tagtype(t) == 'local':
5759 if repo.tagtype(t) == 'local':
5760 tagtype = " local"
5760 tagtype = " local"
5761 tag = ui.label(t, 'tags.local')
5761 tag = ui.label(t, 'tags.local')
5762 else:
5762 else:
5763 tagtype = ""
5763 tagtype = ""
5764 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5764 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5765
5765
5766 @command('tip',
5766 @command('tip',
5767 [('p', 'patch', None, _('show patch')),
5767 [('p', 'patch', None, _('show patch')),
5768 ('g', 'git', None, _('use git extended diff format')),
5768 ('g', 'git', None, _('use git extended diff format')),
5769 ] + templateopts,
5769 ] + templateopts,
5770 _('[-p] [-g]'))
5770 _('[-p] [-g]'))
5771 def tip(ui, repo, **opts):
5771 def tip(ui, repo, **opts):
5772 """show the tip revision
5772 """show the tip revision
5773
5773
5774 The tip revision (usually just called the tip) is the changeset
5774 The tip revision (usually just called the tip) is the changeset
5775 most recently added to the repository (and therefore the most
5775 most recently added to the repository (and therefore the most
5776 recently changed head).
5776 recently changed head).
5777
5777
5778 If you have just made a commit, that commit will be the tip. If
5778 If you have just made a commit, that commit will be the tip. If
5779 you have just pulled changes from another repository, the tip of
5779 you have just pulled changes from another repository, the tip of
5780 that repository becomes the current tip. The "tip" tag is special
5780 that repository becomes the current tip. The "tip" tag is special
5781 and cannot be renamed or assigned to a different changeset.
5781 and cannot be renamed or assigned to a different changeset.
5782
5782
5783 Returns 0 on success.
5783 Returns 0 on success.
5784 """
5784 """
5785 displayer = cmdutil.show_changeset(ui, repo, opts)
5785 displayer = cmdutil.show_changeset(ui, repo, opts)
5786 displayer.show(repo[len(repo) - 1])
5786 displayer.show(repo[len(repo) - 1])
5787 displayer.close()
5787 displayer.close()
5788
5788
5789 @command('unbundle',
5789 @command('unbundle',
5790 [('u', 'update', None,
5790 [('u', 'update', None,
5791 _('update to new branch head if changesets were unbundled'))],
5791 _('update to new branch head if changesets were unbundled'))],
5792 _('[-u] FILE...'))
5792 _('[-u] FILE...'))
5793 def unbundle(ui, repo, fname1, *fnames, **opts):
5793 def unbundle(ui, repo, fname1, *fnames, **opts):
5794 """apply one or more changegroup files
5794 """apply one or more changegroup files
5795
5795
5796 Apply one or more compressed changegroup files generated by the
5796 Apply one or more compressed changegroup files generated by the
5797 bundle command.
5797 bundle command.
5798
5798
5799 Returns 0 on success, 1 if an update has unresolved files.
5799 Returns 0 on success, 1 if an update has unresolved files.
5800 """
5800 """
5801 fnames = (fname1,) + fnames
5801 fnames = (fname1,) + fnames
5802
5802
5803 lock = repo.lock()
5803 lock = repo.lock()
5804 wc = repo['.']
5804 wc = repo['.']
5805 try:
5805 try:
5806 for fname in fnames:
5806 for fname in fnames:
5807 f = url.open(ui, fname)
5807 f = url.open(ui, fname)
5808 gen = changegroup.readbundle(f, fname)
5808 gen = changegroup.readbundle(f, fname)
5809 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5809 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5810 finally:
5810 finally:
5811 lock.release()
5811 lock.release()
5812 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5812 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5813 return postincoming(ui, repo, modheads, opts.get('update'), None)
5813 return postincoming(ui, repo, modheads, opts.get('update'), None)
5814
5814
5815 @command('^update|up|checkout|co',
5815 @command('^update|up|checkout|co',
5816 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5816 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5817 ('c', 'check', None,
5817 ('c', 'check', None,
5818 _('update across branches if no uncommitted changes')),
5818 _('update across branches if no uncommitted changes')),
5819 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5819 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5820 ('r', 'rev', '', _('revision'), _('REV'))],
5820 ('r', 'rev', '', _('revision'), _('REV'))],
5821 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5821 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5822 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5822 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5823 """update working directory (or switch revisions)
5823 """update working directory (or switch revisions)
5824
5824
5825 Update the repository's working directory to the specified
5825 Update the repository's working directory to the specified
5826 changeset. If no changeset is specified, update to the tip of the
5826 changeset. If no changeset is specified, update to the tip of the
5827 current named branch and move the current bookmark (see :hg:`help
5827 current named branch and move the current bookmark (see :hg:`help
5828 bookmarks`).
5828 bookmarks`).
5829
5829
5830 Update sets the working directory's parent revision to the specified
5830 Update sets the working directory's parent revision to the specified
5831 changeset (see :hg:`help parents`).
5831 changeset (see :hg:`help parents`).
5832
5832
5833 If the changeset is not a descendant or ancestor of the working
5833 If the changeset is not a descendant or ancestor of the working
5834 directory's parent, the update is aborted. With the -c/--check
5834 directory's parent, the update is aborted. With the -c/--check
5835 option, the working directory is checked for uncommitted changes; if
5835 option, the working directory is checked for uncommitted changes; if
5836 none are found, the working directory is updated to the specified
5836 none are found, the working directory is updated to the specified
5837 changeset.
5837 changeset.
5838
5838
5839 .. container:: verbose
5839 .. container:: verbose
5840
5840
5841 The following rules apply when the working directory contains
5841 The following rules apply when the working directory contains
5842 uncommitted changes:
5842 uncommitted changes:
5843
5843
5844 1. If neither -c/--check nor -C/--clean is specified, and if
5844 1. If neither -c/--check nor -C/--clean is specified, and if
5845 the requested changeset is an ancestor or descendant of
5845 the requested changeset is an ancestor or descendant of
5846 the working directory's parent, the uncommitted changes
5846 the working directory's parent, the uncommitted changes
5847 are merged into the requested changeset and the merged
5847 are merged into the requested changeset and the merged
5848 result is left uncommitted. If the requested changeset is
5848 result is left uncommitted. If the requested changeset is
5849 not an ancestor or descendant (that is, it is on another
5849 not an ancestor or descendant (that is, it is on another
5850 branch), the update is aborted and the uncommitted changes
5850 branch), the update is aborted and the uncommitted changes
5851 are preserved.
5851 are preserved.
5852
5852
5853 2. With the -c/--check option, the update is aborted and the
5853 2. With the -c/--check option, the update is aborted and the
5854 uncommitted changes are preserved.
5854 uncommitted changes are preserved.
5855
5855
5856 3. With the -C/--clean option, uncommitted changes are discarded and
5856 3. With the -C/--clean option, uncommitted changes are discarded and
5857 the working directory is updated to the requested changeset.
5857 the working directory is updated to the requested changeset.
5858
5858
5859 To cancel an uncommitted merge (and lose your changes), use
5859 To cancel an uncommitted merge (and lose your changes), use
5860 :hg:`update --clean .`.
5860 :hg:`update --clean .`.
5861
5861
5862 Use null as the changeset to remove the working directory (like
5862 Use null as the changeset to remove the working directory (like
5863 :hg:`clone -U`).
5863 :hg:`clone -U`).
5864
5864
5865 If you want to revert just one file to an older revision, use
5865 If you want to revert just one file to an older revision, use
5866 :hg:`revert [-r REV] NAME`.
5866 :hg:`revert [-r REV] NAME`.
5867
5867
5868 See :hg:`help dates` for a list of formats valid for -d/--date.
5868 See :hg:`help dates` for a list of formats valid for -d/--date.
5869
5869
5870 Returns 0 on success, 1 if there are unresolved files.
5870 Returns 0 on success, 1 if there are unresolved files.
5871 """
5871 """
5872 if rev and node:
5872 if rev and node:
5873 raise util.Abort(_("please specify just one revision"))
5873 raise util.Abort(_("please specify just one revision"))
5874
5874
5875 if rev is None or rev == '':
5875 if rev is None or rev == '':
5876 rev = node
5876 rev = node
5877
5877
5878 # with no argument, we also move the current bookmark, if any
5878 # with no argument, we also move the current bookmark, if any
5879 movemarkfrom = None
5879 movemarkfrom = None
5880 if rev is None:
5880 if rev is None:
5881 movemarkfrom = repo['.'].node()
5881 movemarkfrom = repo['.'].node()
5882
5882
5883 # if we defined a bookmark, we have to remember the original bookmark name
5883 # if we defined a bookmark, we have to remember the original bookmark name
5884 brev = rev
5884 brev = rev
5885 rev = scmutil.revsingle(repo, rev, rev).rev()
5885 rev = scmutil.revsingle(repo, rev, rev).rev()
5886
5886
5887 if check and clean:
5887 if check and clean:
5888 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5888 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5889
5889
5890 if date:
5890 if date:
5891 if rev is not None:
5891 if rev is not None:
5892 raise util.Abort(_("you can't specify a revision and a date"))
5892 raise util.Abort(_("you can't specify a revision and a date"))
5893 rev = cmdutil.finddate(ui, repo, date)
5893 rev = cmdutil.finddate(ui, repo, date)
5894
5894
5895 if check:
5895 if check:
5896 c = repo[None]
5896 c = repo[None]
5897 if c.dirty(merge=False, branch=False, missing=True):
5897 if c.dirty(merge=False, branch=False, missing=True):
5898 raise util.Abort(_("uncommitted local changes"))
5898 raise util.Abort(_("uncommitted local changes"))
5899 if rev is None:
5899 if rev is None:
5900 rev = repo[repo[None].branch()].rev()
5900 rev = repo[repo[None].branch()].rev()
5901 mergemod._checkunknown(repo, repo[None], repo[rev])
5901 mergemod._checkunknown(repo, repo[None], repo[rev])
5902
5902
5903 if clean:
5903 if clean:
5904 ret = hg.clean(repo, rev)
5904 ret = hg.clean(repo, rev)
5905 else:
5905 else:
5906 ret = hg.update(repo, rev)
5906 ret = hg.update(repo, rev)
5907
5907
5908 if not ret and movemarkfrom:
5908 if not ret and movemarkfrom:
5909 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5909 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5910 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5910 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5911 elif brev in repo._bookmarks:
5911 elif brev in repo._bookmarks:
5912 bookmarks.setcurrent(repo, brev)
5912 bookmarks.setcurrent(repo, brev)
5913 elif brev:
5913 elif brev:
5914 bookmarks.unsetcurrent(repo)
5914 bookmarks.unsetcurrent(repo)
5915
5915
5916 return ret
5916 return ret
5917
5917
5918 @command('verify', [])
5918 @command('verify', [])
5919 def verify(ui, repo):
5919 def verify(ui, repo):
5920 """verify the integrity of the repository
5920 """verify the integrity of the repository
5921
5921
5922 Verify the integrity of the current repository.
5922 Verify the integrity of the current repository.
5923
5923
5924 This will perform an extensive check of the repository's
5924 This will perform an extensive check of the repository's
5925 integrity, validating the hashes and checksums of each entry in
5925 integrity, validating the hashes and checksums of each entry in
5926 the changelog, manifest, and tracked files, as well as the
5926 the changelog, manifest, and tracked files, as well as the
5927 integrity of their crosslinks and indices.
5927 integrity of their crosslinks and indices.
5928
5928
5929 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5929 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5930 for more information about recovery from corruption of the
5930 for more information about recovery from corruption of the
5931 repository.
5931 repository.
5932
5932
5933 Returns 0 on success, 1 if errors are encountered.
5933 Returns 0 on success, 1 if errors are encountered.
5934 """
5934 """
5935 return hg.verify(repo)
5935 return hg.verify(repo)
5936
5936
5937 @command('version', [])
5937 @command('version', [])
5938 def version_(ui):
5938 def version_(ui):
5939 """output version and copyright information"""
5939 """output version and copyright information"""
5940 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5940 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5941 % util.version())
5941 % util.version())
5942 ui.status(_(
5942 ui.status(_(
5943 "(see http://mercurial.selenic.com for more information)\n"
5943 "(see http://mercurial.selenic.com for more information)\n"
5944 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5944 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5945 "This is free software; see the source for copying conditions. "
5945 "This is free software; see the source for copying conditions. "
5946 "There is NO\nwarranty; "
5946 "There is NO\nwarranty; "
5947 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5947 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5948 ))
5948 ))
5949
5949
5950 norepo = ("clone init version help debugcommands debugcomplete"
5950 norepo = ("clone init version help debugcommands debugcomplete"
5951 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5951 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5952 " debugknown debuggetbundle debugbundle")
5952 " debugknown debuggetbundle debugbundle")
5953 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5953 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5954 " debugdata debugindex debugindexdot debugrevlog")
5954 " debugdata debugindex debugindexdot debugrevlog")
5955 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5955 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5956 " remove resolve status debugwalk")
5956 " remove resolve status debugwalk")
@@ -1,617 +1,618 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 from node import hex, nullid
11 from node import hex, nullid
12 import localrepo, bundlerepo, httppeer, sshpeer, statichttprepo, bookmarks
12 import localrepo, bundlerepo, httppeer, sshpeer, statichttprepo, bookmarks
13 import lock, util, extensions, error, node, scmutil, phases
13 import lock, util, extensions, error, node, scmutil, phases
14 import cmdutil, discovery
14 import cmdutil, discovery
15 import merge as mergemod
15 import merge as mergemod
16 import verify as verifymod
16 import verify as verifymod
17 import errno, os, shutil
17 import errno, os, shutil
18
18
19 def _local(path):
19 def _local(path):
20 path = util.expandpath(util.urllocalpath(path))
20 path = util.expandpath(util.urllocalpath(path))
21 return (os.path.isfile(path) and bundlerepo or localrepo)
21 return (os.path.isfile(path) and bundlerepo or localrepo)
22
22
23 def addbranchrevs(lrepo, other, branches, revs):
23 def addbranchrevs(lrepo, other, branches, revs):
24 peer = other.peer() # a courtesy to callers using a localrepo for other
24 peer = other.peer() # a courtesy to callers using a localrepo for other
25 hashbranch, branches = branches
25 hashbranch, branches = branches
26 if not hashbranch and not branches:
26 if not hashbranch and not branches:
27 return revs or None, revs and revs[0] or None
27 return revs or None, revs and revs[0] or None
28 revs = revs and list(revs) or []
28 revs = revs and list(revs) or []
29 if not peer.capable('branchmap'):
29 if not peer.capable('branchmap'):
30 if branches:
30 if branches:
31 raise util.Abort(_("remote branch lookup not supported"))
31 raise util.Abort(_("remote branch lookup not supported"))
32 revs.append(hashbranch)
32 revs.append(hashbranch)
33 return revs, revs[0]
33 return revs, revs[0]
34 branchmap = peer.branchmap()
34 branchmap = peer.branchmap()
35
35
36 def primary(branch):
36 def primary(branch):
37 if branch == '.':
37 if branch == '.':
38 if not lrepo:
38 if not lrepo:
39 raise util.Abort(_("dirstate branch not accessible"))
39 raise util.Abort(_("dirstate branch not accessible"))
40 branch = lrepo.dirstate.branch()
40 branch = lrepo.dirstate.branch()
41 if branch in branchmap:
41 if branch in branchmap:
42 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
42 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
43 return True
43 return True
44 else:
44 else:
45 return False
45 return False
46
46
47 for branch in branches:
47 for branch in branches:
48 if not primary(branch):
48 if not primary(branch):
49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
50 if hashbranch:
50 if hashbranch:
51 if not primary(hashbranch):
51 if not primary(hashbranch):
52 revs.append(hashbranch)
52 revs.append(hashbranch)
53 return revs, revs[0]
53 return revs, revs[0]
54
54
55 def parseurl(path, branches=None):
55 def parseurl(path, branches=None):
56 '''parse url#branch, returning (url, (branch, branches))'''
56 '''parse url#branch, returning (url, (branch, branches))'''
57
57
58 u = util.url(path)
58 u = util.url(path)
59 branch = None
59 branch = None
60 if u.fragment:
60 if u.fragment:
61 branch = u.fragment
61 branch = u.fragment
62 u.fragment = None
62 u.fragment = None
63 return str(u), (branch, branches or [])
63 return str(u), (branch, branches or [])
64
64
65 schemes = {
65 schemes = {
66 'bundle': bundlerepo,
66 'bundle': bundlerepo,
67 'file': _local,
67 'file': _local,
68 'http': httppeer,
68 'http': httppeer,
69 'https': httppeer,
69 'https': httppeer,
70 'ssh': sshpeer,
70 'ssh': sshpeer,
71 'static-http': statichttprepo,
71 'static-http': statichttprepo,
72 }
72 }
73
73
74 def _peerlookup(path):
74 def _peerlookup(path):
75 u = util.url(path)
75 u = util.url(path)
76 scheme = u.scheme or 'file'
76 scheme = u.scheme or 'file'
77 thing = schemes.get(scheme) or schemes['file']
77 thing = schemes.get(scheme) or schemes['file']
78 try:
78 try:
79 return thing(path)
79 return thing(path)
80 except TypeError:
80 except TypeError:
81 return thing
81 return thing
82
82
83 def islocal(repo):
83 def islocal(repo):
84 '''return true if repo or path is local'''
84 '''return true if repo or path is local'''
85 if isinstance(repo, str):
85 if isinstance(repo, str):
86 try:
86 try:
87 return _peerlookup(repo).islocal(repo)
87 return _peerlookup(repo).islocal(repo)
88 except AttributeError:
88 except AttributeError:
89 return False
89 return False
90 return repo.local()
90 return repo.local()
91
91
92 def _peerorrepo(ui, path, create=False):
92 def _peerorrepo(ui, path, create=False):
93 """return a repository object for the specified path"""
93 """return a repository object for the specified path"""
94 obj = _peerlookup(path).instance(ui, path, create)
94 obj = _peerlookup(path).instance(ui, path, create)
95 ui = getattr(obj, "ui", ui)
95 ui = getattr(obj, "ui", ui)
96 for name, module in extensions.extensions():
96 for name, module in extensions.extensions():
97 hook = getattr(module, 'reposetup', None)
97 hook = getattr(module, 'reposetup', None)
98 if hook:
98 if hook:
99 hook(ui, obj)
99 hook(ui, obj)
100 return obj
100 return obj
101
101
102 def repository(ui, path='', create=False):
102 def repository(ui, path='', create=False):
103 """return a repository object for the specified path"""
103 """return a repository object for the specified path"""
104 peer = _peerorrepo(ui, path, create)
104 peer = _peerorrepo(ui, path, create)
105 repo = peer.local()
105 repo = peer.local()
106 if not repo:
106 if not repo:
107 raise util.Abort(_("repository '%s' is not local") %
107 raise util.Abort(_("repository '%s' is not local") %
108 (path or peer.url()))
108 (path or peer.url()))
109 return repo
109 return repo
110
110
111 def peer(uiorrepo, opts, path, create=False):
111 def peer(uiorrepo, opts, path, create=False):
112 '''return a repository peer for the specified path'''
112 '''return a repository peer for the specified path'''
113 rui = remoteui(uiorrepo, opts)
113 rui = remoteui(uiorrepo, opts)
114 return _peerorrepo(rui, path, create).peer()
114 return _peerorrepo(rui, path, create).peer()
115
115
116 def defaultdest(source):
116 def defaultdest(source):
117 '''return default destination of clone if none is given'''
117 '''return default destination of clone if none is given'''
118 return os.path.basename(os.path.normpath(util.url(source).path))
118 return os.path.basename(os.path.normpath(util.url(source).path))
119
119
120 def share(ui, source, dest=None, update=True):
120 def share(ui, source, dest=None, update=True):
121 '''create a shared repository'''
121 '''create a shared repository'''
122
122
123 if not islocal(source):
123 if not islocal(source):
124 raise util.Abort(_('can only share local repositories'))
124 raise util.Abort(_('can only share local repositories'))
125
125
126 if not dest:
126 if not dest:
127 dest = defaultdest(source)
127 dest = defaultdest(source)
128 else:
128 else:
129 dest = ui.expandpath(dest)
129 dest = ui.expandpath(dest)
130
130
131 if isinstance(source, str):
131 if isinstance(source, str):
132 origsource = ui.expandpath(source)
132 origsource = ui.expandpath(source)
133 source, branches = parseurl(origsource)
133 source, branches = parseurl(origsource)
134 srcrepo = repository(ui, source)
134 srcrepo = repository(ui, source)
135 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
135 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
136 else:
136 else:
137 srcrepo = source.local()
137 srcrepo = source.local()
138 origsource = source = srcrepo.url()
138 origsource = source = srcrepo.url()
139 checkout = None
139 checkout = None
140
140
141 sharedpath = srcrepo.sharedpath # if our source is already sharing
141 sharedpath = srcrepo.sharedpath # if our source is already sharing
142
142
143 root = os.path.realpath(dest)
143 root = os.path.realpath(dest)
144 roothg = os.path.join(root, '.hg')
144 roothg = os.path.join(root, '.hg')
145
145
146 if os.path.exists(roothg):
146 if os.path.exists(roothg):
147 raise util.Abort(_('destination already exists'))
147 raise util.Abort(_('destination already exists'))
148
148
149 if not os.path.isdir(root):
149 if not os.path.isdir(root):
150 os.mkdir(root)
150 os.mkdir(root)
151 util.makedir(roothg, notindexed=True)
151 util.makedir(roothg, notindexed=True)
152
152
153 requirements = ''
153 requirements = ''
154 try:
154 try:
155 requirements = srcrepo.opener.read('requires')
155 requirements = srcrepo.opener.read('requires')
156 except IOError, inst:
156 except IOError, inst:
157 if inst.errno != errno.ENOENT:
157 if inst.errno != errno.ENOENT:
158 raise
158 raise
159
159
160 requirements += 'shared\n'
160 requirements += 'shared\n'
161 util.writefile(os.path.join(roothg, 'requires'), requirements)
161 util.writefile(os.path.join(roothg, 'requires'), requirements)
162 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
162 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
163
163
164 r = repository(ui, root)
164 r = repository(ui, root)
165
165
166 default = srcrepo.ui.config('paths', 'default')
166 default = srcrepo.ui.config('paths', 'default')
167 if default:
167 if default:
168 fp = r.opener("hgrc", "w", text=True)
168 fp = r.opener("hgrc", "w", text=True)
169 fp.write("[paths]\n")
169 fp.write("[paths]\n")
170 fp.write("default = %s\n" % default)
170 fp.write("default = %s\n" % default)
171 fp.close()
171 fp.close()
172
172
173 if update:
173 if update:
174 r.ui.status(_("updating working directory\n"))
174 r.ui.status(_("updating working directory\n"))
175 if update is not True:
175 if update is not True:
176 checkout = update
176 checkout = update
177 for test in (checkout, 'default', 'tip'):
177 for test in (checkout, 'default', 'tip'):
178 if test is None:
178 if test is None:
179 continue
179 continue
180 try:
180 try:
181 uprev = r.lookup(test)
181 uprev = r.lookup(test)
182 break
182 break
183 except error.RepoLookupError:
183 except error.RepoLookupError:
184 continue
184 continue
185 _update(r, uprev)
185 _update(r, uprev)
186
186
187 def copystore(ui, srcrepo, destpath):
187 def copystore(ui, srcrepo, destpath):
188 '''copy files from store of srcrepo in destpath
188 '''copy files from store of srcrepo in destpath
189
189
190 returns destlock
190 returns destlock
191 '''
191 '''
192 destlock = None
192 destlock = None
193 try:
193 try:
194 hardlink = None
194 hardlink = None
195 num = 0
195 num = 0
196 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
196 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
197 for f in srcrepo.store.copylist():
197 for f in srcrepo.store.copylist():
198 if srcpublishing and f.endswith('phaseroots'):
198 if srcpublishing and f.endswith('phaseroots'):
199 continue
199 continue
200 src = os.path.join(srcrepo.sharedpath, f)
200 src = os.path.join(srcrepo.sharedpath, f)
201 dst = os.path.join(destpath, f)
201 dst = os.path.join(destpath, f)
202 dstbase = os.path.dirname(dst)
202 dstbase = os.path.dirname(dst)
203 if dstbase and not os.path.exists(dstbase):
203 if dstbase and not os.path.exists(dstbase):
204 os.mkdir(dstbase)
204 os.mkdir(dstbase)
205 if os.path.exists(src):
205 if os.path.exists(src):
206 if dst.endswith('data'):
206 if dst.endswith('data'):
207 # lock to avoid premature writing to the target
207 # lock to avoid premature writing to the target
208 destlock = lock.lock(os.path.join(dstbase, "lock"))
208 destlock = lock.lock(os.path.join(dstbase, "lock"))
209 hardlink, n = util.copyfiles(src, dst, hardlink)
209 hardlink, n = util.copyfiles(src, dst, hardlink)
210 num += n
210 num += n
211 if hardlink:
211 if hardlink:
212 ui.debug("linked %d files\n" % num)
212 ui.debug("linked %d files\n" % num)
213 else:
213 else:
214 ui.debug("copied %d files\n" % num)
214 ui.debug("copied %d files\n" % num)
215 return destlock
215 return destlock
216 except: # re-raises
216 except: # re-raises
217 release(destlock)
217 release(destlock)
218 raise
218 raise
219
219
220 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
220 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
221 update=True, stream=False, branch=None):
221 update=True, stream=False, branch=None):
222 """Make a copy of an existing repository.
222 """Make a copy of an existing repository.
223
223
224 Create a copy of an existing repository in a new directory. The
224 Create a copy of an existing repository in a new directory. The
225 source and destination are URLs, as passed to the repository
225 source and destination are URLs, as passed to the repository
226 function. Returns a pair of repository peers, the source and
226 function. Returns a pair of repository peers, the source and
227 newly created destination.
227 newly created destination.
228
228
229 The location of the source is added to the new repository's
229 The location of the source is added to the new repository's
230 .hg/hgrc file, as the default to be used for future pulls and
230 .hg/hgrc file, as the default to be used for future pulls and
231 pushes.
231 pushes.
232
232
233 If an exception is raised, the partly cloned/updated destination
233 If an exception is raised, the partly cloned/updated destination
234 repository will be deleted.
234 repository will be deleted.
235
235
236 Arguments:
236 Arguments:
237
237
238 source: repository object or URL
238 source: repository object or URL
239
239
240 dest: URL of destination repository to create (defaults to base
240 dest: URL of destination repository to create (defaults to base
241 name of source repository)
241 name of source repository)
242
242
243 pull: always pull from source repository, even in local case
243 pull: always pull from source repository, even in local case
244
244
245 stream: stream raw data uncompressed from repository (fast over
245 stream: stream raw data uncompressed from repository (fast over
246 LAN, slow over WAN)
246 LAN, slow over WAN)
247
247
248 rev: revision to clone up to (implies pull=True)
248 rev: revision to clone up to (implies pull=True)
249
249
250 update: update working directory after clone completes, if
250 update: update working directory after clone completes, if
251 destination is local repository (True means update to default rev,
251 destination is local repository (True means update to default rev,
252 anything else is treated as a revision)
252 anything else is treated as a revision)
253
253
254 branch: branches to clone
254 branch: branches to clone
255 """
255 """
256
256
257 if isinstance(source, str):
257 if isinstance(source, str):
258 origsource = ui.expandpath(source)
258 origsource = ui.expandpath(source)
259 source, branch = parseurl(origsource, branch)
259 source, branch = parseurl(origsource, branch)
260 srcpeer = peer(ui, peeropts, source)
260 srcpeer = peer(ui, peeropts, source)
261 else:
261 else:
262 srcpeer = source.peer() # in case we were called with a localrepo
262 srcpeer = source.peer() # in case we were called with a localrepo
263 branch = (None, branch or [])
263 branch = (None, branch or [])
264 origsource = source = srcpeer.url()
264 origsource = source = srcpeer.url()
265 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
265 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
266
266
267 if dest is None:
267 if dest is None:
268 dest = defaultdest(source)
268 dest = defaultdest(source)
269 ui.status(_("destination directory: %s\n") % dest)
269 ui.status(_("destination directory: %s\n") % dest)
270 else:
270 else:
271 dest = ui.expandpath(dest)
271 dest = ui.expandpath(dest)
272
272
273 dest = util.urllocalpath(dest)
273 dest = util.urllocalpath(dest)
274 source = util.urllocalpath(source)
274 source = util.urllocalpath(source)
275
275
276 if not dest:
276 if not dest:
277 raise util.Abort(_("empty destination path is not valid"))
277 raise util.Abort(_("empty destination path is not valid"))
278 if os.path.exists(dest):
278 if os.path.exists(dest):
279 if not os.path.isdir(dest):
279 if not os.path.isdir(dest):
280 raise util.Abort(_("destination '%s' already exists") % dest)
280 raise util.Abort(_("destination '%s' already exists") % dest)
281 elif os.listdir(dest):
281 elif os.listdir(dest):
282 raise util.Abort(_("destination '%s' is not empty") % dest)
282 raise util.Abort(_("destination '%s' is not empty") % dest)
283
283
284 class DirCleanup(object):
284 class DirCleanup(object):
285 def __init__(self, dir_):
285 def __init__(self, dir_):
286 self.rmtree = shutil.rmtree
286 self.rmtree = shutil.rmtree
287 self.dir_ = dir_
287 self.dir_ = dir_
288 def close(self):
288 def close(self):
289 self.dir_ = None
289 self.dir_ = None
290 def cleanup(self):
290 def cleanup(self):
291 if self.dir_:
291 if self.dir_:
292 self.rmtree(self.dir_, True)
292 self.rmtree(self.dir_, True)
293
293
294 srclock = destlock = dircleanup = None
294 srclock = destlock = dircleanup = None
295 srcrepo = srcpeer.local()
295 srcrepo = srcpeer.local()
296 try:
296 try:
297 abspath = origsource
297 abspath = origsource
298 if islocal(origsource):
298 if islocal(origsource):
299 abspath = os.path.abspath(util.urllocalpath(origsource))
299 abspath = os.path.abspath(util.urllocalpath(origsource))
300
300
301 if islocal(dest):
301 if islocal(dest):
302 dircleanup = DirCleanup(dest)
302 dircleanup = DirCleanup(dest)
303
303
304 copy = False
304 copy = False
305 if (srcrepo and srcrepo.cancopy() and islocal(dest)
305 if (srcrepo and srcrepo.cancopy() and islocal(dest)
306 and not phases.hassecret(srcrepo)):
306 and not phases.hassecret(srcrepo)):
307 copy = not pull and not rev
307 copy = not pull and not rev
308
308
309 if copy:
309 if copy:
310 try:
310 try:
311 # we use a lock here because if we race with commit, we
311 # we use a lock here because if we race with commit, we
312 # can end up with extra data in the cloned revlogs that's
312 # can end up with extra data in the cloned revlogs that's
313 # not pointed to by changesets, thus causing verify to
313 # not pointed to by changesets, thus causing verify to
314 # fail
314 # fail
315 srclock = srcrepo.lock(wait=False)
315 srclock = srcrepo.lock(wait=False)
316 except error.LockError:
316 except error.LockError:
317 copy = False
317 copy = False
318
318
319 if copy:
319 if copy:
320 srcrepo.hook('preoutgoing', throw=True, source='clone')
320 srcrepo.hook('preoutgoing', throw=True, source='clone')
321 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
321 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
322 if not os.path.exists(dest):
322 if not os.path.exists(dest):
323 os.mkdir(dest)
323 os.mkdir(dest)
324 else:
324 else:
325 # only clean up directories we create ourselves
325 # only clean up directories we create ourselves
326 dircleanup.dir_ = hgdir
326 dircleanup.dir_ = hgdir
327 try:
327 try:
328 destpath = hgdir
328 destpath = hgdir
329 util.makedir(destpath, notindexed=True)
329 util.makedir(destpath, notindexed=True)
330 except OSError, inst:
330 except OSError, inst:
331 if inst.errno == errno.EEXIST:
331 if inst.errno == errno.EEXIST:
332 dircleanup.close()
332 dircleanup.close()
333 raise util.Abort(_("destination '%s' already exists")
333 raise util.Abort(_("destination '%s' already exists")
334 % dest)
334 % dest)
335 raise
335 raise
336
336
337 destlock = copystore(ui, srcrepo, destpath)
337 destlock = copystore(ui, srcrepo, destpath)
338
338
339 # Recomputing branch cache might be slow on big repos,
339 # Recomputing branch cache might be slow on big repos,
340 # so just copy it
340 # so just copy it
341 dstcachedir = os.path.join(destpath, 'cache')
341 dstcachedir = os.path.join(destpath, 'cache')
342 srcbranchcache = srcrepo.sjoin('cache/branchheads')
342 srcbranchcache = srcrepo.sjoin('cache/branchheads')
343 dstbranchcache = os.path.join(dstcachedir, 'branchheads')
343 dstbranchcache = os.path.join(dstcachedir, 'branchheads')
344 if os.path.exists(srcbranchcache):
344 if os.path.exists(srcbranchcache):
345 if not os.path.exists(dstcachedir):
345 if not os.path.exists(dstcachedir):
346 os.mkdir(dstcachedir)
346 os.mkdir(dstcachedir)
347 util.copyfile(srcbranchcache, dstbranchcache)
347 util.copyfile(srcbranchcache, dstbranchcache)
348
348
349 # we need to re-init the repo after manually copying the data
349 # we need to re-init the repo after manually copying the data
350 # into it
350 # into it
351 destpeer = peer(srcrepo, peeropts, dest)
351 destpeer = peer(srcrepo, peeropts, dest)
352 srcrepo.hook('outgoing', source='clone',
352 srcrepo.hook('outgoing', source='clone',
353 node=node.hex(node.nullid))
353 node=node.hex(node.nullid))
354 else:
354 else:
355 try:
355 try:
356 destpeer = peer(ui, peeropts, dest, create=True)
356 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
357 # only pass ui when no srcrepo
357 except OSError, inst:
358 except OSError, inst:
358 if inst.errno == errno.EEXIST:
359 if inst.errno == errno.EEXIST:
359 dircleanup.close()
360 dircleanup.close()
360 raise util.Abort(_("destination '%s' already exists")
361 raise util.Abort(_("destination '%s' already exists")
361 % dest)
362 % dest)
362 raise
363 raise
363
364
364 revs = None
365 revs = None
365 if rev:
366 if rev:
366 if not srcpeer.capable('lookup'):
367 if not srcpeer.capable('lookup'):
367 raise util.Abort(_("src repository does not support "
368 raise util.Abort(_("src repository does not support "
368 "revision lookup and so doesn't "
369 "revision lookup and so doesn't "
369 "support clone by revision"))
370 "support clone by revision"))
370 revs = [srcpeer.lookup(r) for r in rev]
371 revs = [srcpeer.lookup(r) for r in rev]
371 checkout = revs[0]
372 checkout = revs[0]
372 if destpeer.local():
373 if destpeer.local():
373 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
374 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
374 elif srcrepo:
375 elif srcrepo:
375 srcrepo.push(destpeer, revs=revs)
376 srcrepo.push(destpeer, revs=revs)
376 else:
377 else:
377 raise util.Abort(_("clone from remote to remote not supported"))
378 raise util.Abort(_("clone from remote to remote not supported"))
378
379
379 if dircleanup:
380 if dircleanup:
380 dircleanup.close()
381 dircleanup.close()
381
382
382 # clone all bookmarks except divergent ones
383 # clone all bookmarks except divergent ones
383 destrepo = destpeer.local()
384 destrepo = destpeer.local()
384 if destrepo and srcpeer.capable("pushkey"):
385 if destrepo and srcpeer.capable("pushkey"):
385 rb = srcpeer.listkeys('bookmarks')
386 rb = srcpeer.listkeys('bookmarks')
386 for k, n in rb.iteritems():
387 for k, n in rb.iteritems():
387 try:
388 try:
388 m = destrepo.lookup(n)
389 m = destrepo.lookup(n)
389 destrepo._bookmarks[k] = m
390 destrepo._bookmarks[k] = m
390 except error.RepoLookupError:
391 except error.RepoLookupError:
391 pass
392 pass
392 if rb:
393 if rb:
393 bookmarks.write(destrepo)
394 bookmarks.write(destrepo)
394 elif srcrepo and destpeer.capable("pushkey"):
395 elif srcrepo and destpeer.capable("pushkey"):
395 for k, n in srcrepo._bookmarks.iteritems():
396 for k, n in srcrepo._bookmarks.iteritems():
396 destpeer.pushkey('bookmarks', k, '', hex(n))
397 destpeer.pushkey('bookmarks', k, '', hex(n))
397
398
398 if destrepo:
399 if destrepo:
399 fp = destrepo.opener("hgrc", "w", text=True)
400 fp = destrepo.opener("hgrc", "w", text=True)
400 fp.write("[paths]\n")
401 fp.write("[paths]\n")
401 u = util.url(abspath)
402 u = util.url(abspath)
402 u.passwd = None
403 u.passwd = None
403 defaulturl = str(u)
404 defaulturl = str(u)
404 fp.write("default = %s\n" % defaulturl)
405 fp.write("default = %s\n" % defaulturl)
405 fp.close()
406 fp.close()
406
407
407 destrepo.ui.setconfig('paths', 'default', defaulturl)
408 destrepo.ui.setconfig('paths', 'default', defaulturl)
408
409
409 if update:
410 if update:
410 if update is not True:
411 if update is not True:
411 checkout = srcpeer.lookup(update)
412 checkout = srcpeer.lookup(update)
412 uprev = None
413 uprev = None
413 if checkout is not None:
414 if checkout is not None:
414 try:
415 try:
415 uprev = destrepo.lookup(checkout)
416 uprev = destrepo.lookup(checkout)
416 except error.RepoLookupError:
417 except error.RepoLookupError:
417 pass
418 pass
418 if uprev is None:
419 if uprev is None:
419 try:
420 try:
420 uprev = destrepo._bookmarks['@']
421 uprev = destrepo._bookmarks['@']
421 update = '@'
422 update = '@'
422 except KeyError:
423 except KeyError:
423 try:
424 try:
424 uprev = destrepo.branchtip('default')
425 uprev = destrepo.branchtip('default')
425 except error.RepoLookupError:
426 except error.RepoLookupError:
426 uprev = destrepo.lookup('tip')
427 uprev = destrepo.lookup('tip')
427 bn = destrepo[uprev].branch()
428 bn = destrepo[uprev].branch()
428 destrepo.ui.status(_("updating to branch %s\n") % bn)
429 destrepo.ui.status(_("updating to branch %s\n") % bn)
429 _update(destrepo, uprev)
430 _update(destrepo, uprev)
430 if update in destrepo._bookmarks:
431 if update in destrepo._bookmarks:
431 bookmarks.setcurrent(destrepo, update)
432 bookmarks.setcurrent(destrepo, update)
432
433
433 return srcpeer, destpeer
434 return srcpeer, destpeer
434 finally:
435 finally:
435 release(srclock, destlock)
436 release(srclock, destlock)
436 if dircleanup is not None:
437 if dircleanup is not None:
437 dircleanup.cleanup()
438 dircleanup.cleanup()
438 if srcpeer is not None:
439 if srcpeer is not None:
439 srcpeer.close()
440 srcpeer.close()
440
441
441 def _showstats(repo, stats):
442 def _showstats(repo, stats):
442 repo.ui.status(_("%d files updated, %d files merged, "
443 repo.ui.status(_("%d files updated, %d files merged, "
443 "%d files removed, %d files unresolved\n") % stats)
444 "%d files removed, %d files unresolved\n") % stats)
444
445
445 def update(repo, node):
446 def update(repo, node):
446 """update the working directory to node, merging linear changes"""
447 """update the working directory to node, merging linear changes"""
447 stats = mergemod.update(repo, node, False, False, None)
448 stats = mergemod.update(repo, node, False, False, None)
448 _showstats(repo, stats)
449 _showstats(repo, stats)
449 if stats[3]:
450 if stats[3]:
450 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
451 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
451 return stats[3] > 0
452 return stats[3] > 0
452
453
453 # naming conflict in clone()
454 # naming conflict in clone()
454 _update = update
455 _update = update
455
456
456 def clean(repo, node, show_stats=True):
457 def clean(repo, node, show_stats=True):
457 """forcibly switch the working directory to node, clobbering changes"""
458 """forcibly switch the working directory to node, clobbering changes"""
458 stats = mergemod.update(repo, node, False, True, None)
459 stats = mergemod.update(repo, node, False, True, None)
459 if show_stats:
460 if show_stats:
460 _showstats(repo, stats)
461 _showstats(repo, stats)
461 return stats[3] > 0
462 return stats[3] > 0
462
463
463 def merge(repo, node, force=None, remind=True):
464 def merge(repo, node, force=None, remind=True):
464 """Branch merge with node, resolving changes. Return true if any
465 """Branch merge with node, resolving changes. Return true if any
465 unresolved conflicts."""
466 unresolved conflicts."""
466 stats = mergemod.update(repo, node, True, force, False)
467 stats = mergemod.update(repo, node, True, force, False)
467 _showstats(repo, stats)
468 _showstats(repo, stats)
468 if stats[3]:
469 if stats[3]:
469 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
470 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
470 "or 'hg update -C .' to abandon\n"))
471 "or 'hg update -C .' to abandon\n"))
471 elif remind:
472 elif remind:
472 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
473 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
473 return stats[3] > 0
474 return stats[3] > 0
474
475
475 def _incoming(displaychlist, subreporecurse, ui, repo, source,
476 def _incoming(displaychlist, subreporecurse, ui, repo, source,
476 opts, buffered=False):
477 opts, buffered=False):
477 """
478 """
478 Helper for incoming / gincoming.
479 Helper for incoming / gincoming.
479 displaychlist gets called with
480 displaychlist gets called with
480 (remoterepo, incomingchangesetlist, displayer) parameters,
481 (remoterepo, incomingchangesetlist, displayer) parameters,
481 and is supposed to contain only code that can't be unified.
482 and is supposed to contain only code that can't be unified.
482 """
483 """
483 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
484 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
484 other = peer(repo, opts, source)
485 other = peer(repo, opts, source)
485 ui.status(_('comparing with %s\n') % util.hidepassword(source))
486 ui.status(_('comparing with %s\n') % util.hidepassword(source))
486 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
487 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
487
488
488 if revs:
489 if revs:
489 revs = [other.lookup(rev) for rev in revs]
490 revs = [other.lookup(rev) for rev in revs]
490 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
491 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
491 revs, opts["bundle"], opts["force"])
492 revs, opts["bundle"], opts["force"])
492 try:
493 try:
493 if not chlist:
494 if not chlist:
494 ui.status(_("no changes found\n"))
495 ui.status(_("no changes found\n"))
495 return subreporecurse()
496 return subreporecurse()
496
497
497 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
498 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
498
499
499 # XXX once graphlog extension makes it into core,
500 # XXX once graphlog extension makes it into core,
500 # should be replaced by a if graph/else
501 # should be replaced by a if graph/else
501 displaychlist(other, chlist, displayer)
502 displaychlist(other, chlist, displayer)
502
503
503 displayer.close()
504 displayer.close()
504 finally:
505 finally:
505 cleanupfn()
506 cleanupfn()
506 subreporecurse()
507 subreporecurse()
507 return 0 # exit code is zero since we found incoming changes
508 return 0 # exit code is zero since we found incoming changes
508
509
509 def incoming(ui, repo, source, opts):
510 def incoming(ui, repo, source, opts):
510 def subreporecurse():
511 def subreporecurse():
511 ret = 1
512 ret = 1
512 if opts.get('subrepos'):
513 if opts.get('subrepos'):
513 ctx = repo[None]
514 ctx = repo[None]
514 for subpath in sorted(ctx.substate):
515 for subpath in sorted(ctx.substate):
515 sub = ctx.sub(subpath)
516 sub = ctx.sub(subpath)
516 ret = min(ret, sub.incoming(ui, source, opts))
517 ret = min(ret, sub.incoming(ui, source, opts))
517 return ret
518 return ret
518
519
519 def display(other, chlist, displayer):
520 def display(other, chlist, displayer):
520 limit = cmdutil.loglimit(opts)
521 limit = cmdutil.loglimit(opts)
521 if opts.get('newest_first'):
522 if opts.get('newest_first'):
522 chlist.reverse()
523 chlist.reverse()
523 count = 0
524 count = 0
524 for n in chlist:
525 for n in chlist:
525 if limit is not None and count >= limit:
526 if limit is not None and count >= limit:
526 break
527 break
527 parents = [p for p in other.changelog.parents(n) if p != nullid]
528 parents = [p for p in other.changelog.parents(n) if p != nullid]
528 if opts.get('no_merges') and len(parents) == 2:
529 if opts.get('no_merges') and len(parents) == 2:
529 continue
530 continue
530 count += 1
531 count += 1
531 displayer.show(other[n])
532 displayer.show(other[n])
532 return _incoming(display, subreporecurse, ui, repo, source, opts)
533 return _incoming(display, subreporecurse, ui, repo, source, opts)
533
534
534 def _outgoing(ui, repo, dest, opts):
535 def _outgoing(ui, repo, dest, opts):
535 dest = ui.expandpath(dest or 'default-push', dest or 'default')
536 dest = ui.expandpath(dest or 'default-push', dest or 'default')
536 dest, branches = parseurl(dest, opts.get('branch'))
537 dest, branches = parseurl(dest, opts.get('branch'))
537 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
538 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
538 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
539 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
539 if revs:
540 if revs:
540 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
541 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
541
542
542 other = peer(repo, opts, dest)
543 other = peer(repo, opts, dest)
543 outgoing = discovery.findcommonoutgoing(repo, other, revs,
544 outgoing = discovery.findcommonoutgoing(repo, other, revs,
544 force=opts.get('force'))
545 force=opts.get('force'))
545 o = outgoing.missing
546 o = outgoing.missing
546 if not o:
547 if not o:
547 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
548 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
548 return None
549 return None
549 return o
550 return o
550
551
551 def outgoing(ui, repo, dest, opts):
552 def outgoing(ui, repo, dest, opts):
552 def recurse():
553 def recurse():
553 ret = 1
554 ret = 1
554 if opts.get('subrepos'):
555 if opts.get('subrepos'):
555 ctx = repo[None]
556 ctx = repo[None]
556 for subpath in sorted(ctx.substate):
557 for subpath in sorted(ctx.substate):
557 sub = ctx.sub(subpath)
558 sub = ctx.sub(subpath)
558 ret = min(ret, sub.outgoing(ui, dest, opts))
559 ret = min(ret, sub.outgoing(ui, dest, opts))
559 return ret
560 return ret
560
561
561 limit = cmdutil.loglimit(opts)
562 limit = cmdutil.loglimit(opts)
562 o = _outgoing(ui, repo, dest, opts)
563 o = _outgoing(ui, repo, dest, opts)
563 if o is None:
564 if o is None:
564 return recurse()
565 return recurse()
565
566
566 if opts.get('newest_first'):
567 if opts.get('newest_first'):
567 o.reverse()
568 o.reverse()
568 displayer = cmdutil.show_changeset(ui, repo, opts)
569 displayer = cmdutil.show_changeset(ui, repo, opts)
569 count = 0
570 count = 0
570 for n in o:
571 for n in o:
571 if limit is not None and count >= limit:
572 if limit is not None and count >= limit:
572 break
573 break
573 parents = [p for p in repo.changelog.parents(n) if p != nullid]
574 parents = [p for p in repo.changelog.parents(n) if p != nullid]
574 if opts.get('no_merges') and len(parents) == 2:
575 if opts.get('no_merges') and len(parents) == 2:
575 continue
576 continue
576 count += 1
577 count += 1
577 displayer.show(repo[n])
578 displayer.show(repo[n])
578 displayer.close()
579 displayer.close()
579 recurse()
580 recurse()
580 return 0 # exit code is zero since we found outgoing changes
581 return 0 # exit code is zero since we found outgoing changes
581
582
582 def revert(repo, node, choose):
583 def revert(repo, node, choose):
583 """revert changes to revision in node without updating dirstate"""
584 """revert changes to revision in node without updating dirstate"""
584 return mergemod.update(repo, node, False, True, choose)[3] > 0
585 return mergemod.update(repo, node, False, True, choose)[3] > 0
585
586
586 def verify(repo):
587 def verify(repo):
587 """verify the consistency of a repository"""
588 """verify the consistency of a repository"""
588 return verifymod.verify(repo)
589 return verifymod.verify(repo)
589
590
590 def remoteui(src, opts):
591 def remoteui(src, opts):
591 'build a remote ui from ui or repo and opts'
592 'build a remote ui from ui or repo and opts'
592 if util.safehasattr(src, 'baseui'): # looks like a repository
593 if util.safehasattr(src, 'baseui'): # looks like a repository
593 dst = src.baseui.copy() # drop repo-specific config
594 dst = src.baseui.copy() # drop repo-specific config
594 src = src.ui # copy target options from repo
595 src = src.ui # copy target options from repo
595 else: # assume it's a global ui object
596 else: # assume it's a global ui object
596 dst = src.copy() # keep all global options
597 dst = src.copy() # keep all global options
597
598
598 # copy ssh-specific options
599 # copy ssh-specific options
599 for o in 'ssh', 'remotecmd':
600 for o in 'ssh', 'remotecmd':
600 v = opts.get(o) or src.config('ui', o)
601 v = opts.get(o) or src.config('ui', o)
601 if v:
602 if v:
602 dst.setconfig("ui", o, v)
603 dst.setconfig("ui", o, v)
603
604
604 # copy bundle-specific options
605 # copy bundle-specific options
605 r = src.config('bundle', 'mainreporoot')
606 r = src.config('bundle', 'mainreporoot')
606 if r:
607 if r:
607 dst.setconfig('bundle', 'mainreporoot', r)
608 dst.setconfig('bundle', 'mainreporoot', r)
608
609
609 # copy selected local settings to the remote ui
610 # copy selected local settings to the remote ui
610 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
611 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
611 for key, val in src.configitems(sect):
612 for key, val in src.configitems(sect):
612 dst.setconfig(sect, key, val)
613 dst.setconfig(sect, key, val)
613 v = src.config('web', 'cacerts')
614 v = src.config('web', 'cacerts')
614 if v:
615 if v:
615 dst.setconfig('web', 'cacerts', util.expandpath(v))
616 dst.setconfig('web', 'cacerts', util.expandpath(v))
616
617
617 return dst
618 return dst
General Comments 0
You need to be logged in to leave comments. Login now