##// END OF EJS Templates
debugpushkey: list keys sorted
Mads Kiilerich <mads at kiilerich.com> -
r18255:7ca534f3 default
parent child Browse files
Show More
@@ -1,6041 +1,6041 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, encoding, templatekw, discovery
13 import patch, help, 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 - skip all revisions that do not touch directories ``foo`` or ``bar``
552 - skip all revisions that do not touch directories ``foo`` or ``bar``
553
553
554 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
554 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
555
555
556 - forget the current bisection::
556 - forget the current bisection::
557
557
558 hg bisect --reset
558 hg bisect --reset
559
559
560 - use 'make && make tests' to automatically find the first broken
560 - use 'make && make tests' to automatically find the first broken
561 revision::
561 revision::
562
562
563 hg bisect --reset
563 hg bisect --reset
564 hg bisect --bad 34
564 hg bisect --bad 34
565 hg bisect --good 12
565 hg bisect --good 12
566 hg bisect --command 'make && make tests'
566 hg bisect --command 'make && make tests'
567
567
568 - see all changesets whose states are already known in the current
568 - see all changesets whose states are already known in the current
569 bisection::
569 bisection::
570
570
571 hg log -r "bisect(pruned)"
571 hg log -r "bisect(pruned)"
572
572
573 - see the changeset currently being bisected (especially useful
573 - see the changeset currently being bisected (especially useful
574 if running with -U/--noupdate)::
574 if running with -U/--noupdate)::
575
575
576 hg log -r "bisect(current)"
576 hg log -r "bisect(current)"
577
577
578 - see all changesets that took part in the current bisection::
578 - see all changesets that took part in the current bisection::
579
579
580 hg log -r "bisect(range)"
580 hg log -r "bisect(range)"
581
581
582 - with the graphlog extension, you can even get a nice graph::
582 - with the graphlog extension, you can even get a nice graph::
583
583
584 hg log --graph -r "bisect(range)"
584 hg log --graph -r "bisect(range)"
585
585
586 See :hg:`help revsets` for more about the `bisect()` keyword.
586 See :hg:`help revsets` for more about the `bisect()` keyword.
587
587
588 Returns 0 on success.
588 Returns 0 on success.
589 """
589 """
590 def extendbisectrange(nodes, good):
590 def extendbisectrange(nodes, good):
591 # bisect is incomplete when it ends on a merge node and
591 # bisect is incomplete when it ends on a merge node and
592 # one of the parent was not checked.
592 # one of the parent was not checked.
593 parents = repo[nodes[0]].parents()
593 parents = repo[nodes[0]].parents()
594 if len(parents) > 1:
594 if len(parents) > 1:
595 side = good and state['bad'] or state['good']
595 side = good and state['bad'] or state['good']
596 num = len(set(i.node() for i in parents) & set(side))
596 num = len(set(i.node() for i in parents) & set(side))
597 if num == 1:
597 if num == 1:
598 return parents[0].ancestor(parents[1])
598 return parents[0].ancestor(parents[1])
599 return None
599 return None
600
600
601 def print_result(nodes, good):
601 def print_result(nodes, good):
602 displayer = cmdutil.show_changeset(ui, repo, {})
602 displayer = cmdutil.show_changeset(ui, repo, {})
603 if len(nodes) == 1:
603 if len(nodes) == 1:
604 # narrowed it down to a single revision
604 # narrowed it down to a single revision
605 if good:
605 if good:
606 ui.write(_("The first good revision is:\n"))
606 ui.write(_("The first good revision is:\n"))
607 else:
607 else:
608 ui.write(_("The first bad revision is:\n"))
608 ui.write(_("The first bad revision is:\n"))
609 displayer.show(repo[nodes[0]])
609 displayer.show(repo[nodes[0]])
610 extendnode = extendbisectrange(nodes, good)
610 extendnode = extendbisectrange(nodes, good)
611 if extendnode is not None:
611 if extendnode is not None:
612 ui.write(_('Not all ancestors of this changeset have been'
612 ui.write(_('Not all ancestors of this changeset have been'
613 ' checked.\nUse bisect --extend to continue the '
613 ' checked.\nUse bisect --extend to continue the '
614 'bisection from\nthe common ancestor, %s.\n')
614 'bisection from\nthe common ancestor, %s.\n')
615 % extendnode)
615 % extendnode)
616 else:
616 else:
617 # multiple possible revisions
617 # multiple possible revisions
618 if good:
618 if good:
619 ui.write(_("Due to skipped revisions, the first "
619 ui.write(_("Due to skipped revisions, the first "
620 "good revision could be any of:\n"))
620 "good revision could be any of:\n"))
621 else:
621 else:
622 ui.write(_("Due to skipped revisions, the first "
622 ui.write(_("Due to skipped revisions, the first "
623 "bad revision could be any of:\n"))
623 "bad revision could be any of:\n"))
624 for n in nodes:
624 for n in nodes:
625 displayer.show(repo[n])
625 displayer.show(repo[n])
626 displayer.close()
626 displayer.close()
627
627
628 def check_state(state, interactive=True):
628 def check_state(state, interactive=True):
629 if not state['good'] or not state['bad']:
629 if not state['good'] or not state['bad']:
630 if (good or bad or skip or reset) and interactive:
630 if (good or bad or skip or reset) and interactive:
631 return
631 return
632 if not state['good']:
632 if not state['good']:
633 raise util.Abort(_('cannot bisect (no known good revisions)'))
633 raise util.Abort(_('cannot bisect (no known good revisions)'))
634 else:
634 else:
635 raise util.Abort(_('cannot bisect (no known bad revisions)'))
635 raise util.Abort(_('cannot bisect (no known bad revisions)'))
636 return True
636 return True
637
637
638 # backward compatibility
638 # backward compatibility
639 if rev in "good bad reset init".split():
639 if rev in "good bad reset init".split():
640 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
640 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
641 cmd, rev, extra = rev, extra, None
641 cmd, rev, extra = rev, extra, None
642 if cmd == "good":
642 if cmd == "good":
643 good = True
643 good = True
644 elif cmd == "bad":
644 elif cmd == "bad":
645 bad = True
645 bad = True
646 else:
646 else:
647 reset = True
647 reset = True
648 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
648 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
649 raise util.Abort(_('incompatible arguments'))
649 raise util.Abort(_('incompatible arguments'))
650
650
651 if reset:
651 if reset:
652 p = repo.join("bisect.state")
652 p = repo.join("bisect.state")
653 if os.path.exists(p):
653 if os.path.exists(p):
654 os.unlink(p)
654 os.unlink(p)
655 return
655 return
656
656
657 state = hbisect.load_state(repo)
657 state = hbisect.load_state(repo)
658
658
659 if command:
659 if command:
660 changesets = 1
660 changesets = 1
661 try:
661 try:
662 node = state['current'][0]
662 node = state['current'][0]
663 except LookupError:
663 except LookupError:
664 if noupdate:
664 if noupdate:
665 raise util.Abort(_('current bisect revision is unknown - '
665 raise util.Abort(_('current bisect revision is unknown - '
666 'start a new bisect to fix'))
666 'start a new bisect to fix'))
667 node, p2 = repo.dirstate.parents()
667 node, p2 = repo.dirstate.parents()
668 if p2 != nullid:
668 if p2 != nullid:
669 raise util.Abort(_('current bisect revision is a merge'))
669 raise util.Abort(_('current bisect revision is a merge'))
670 try:
670 try:
671 while changesets:
671 while changesets:
672 # update state
672 # update state
673 state['current'] = [node]
673 state['current'] = [node]
674 hbisect.save_state(repo, state)
674 hbisect.save_state(repo, state)
675 status = util.system(command,
675 status = util.system(command,
676 environ={'HG_NODE': hex(node)},
676 environ={'HG_NODE': hex(node)},
677 out=ui.fout)
677 out=ui.fout)
678 if status == 125:
678 if status == 125:
679 transition = "skip"
679 transition = "skip"
680 elif status == 0:
680 elif status == 0:
681 transition = "good"
681 transition = "good"
682 # status < 0 means process was killed
682 # status < 0 means process was killed
683 elif status == 127:
683 elif status == 127:
684 raise util.Abort(_("failed to execute %s") % command)
684 raise util.Abort(_("failed to execute %s") % command)
685 elif status < 0:
685 elif status < 0:
686 raise util.Abort(_("%s killed") % command)
686 raise util.Abort(_("%s killed") % command)
687 else:
687 else:
688 transition = "bad"
688 transition = "bad"
689 ctx = scmutil.revsingle(repo, rev, node)
689 ctx = scmutil.revsingle(repo, rev, node)
690 rev = None # clear for future iterations
690 rev = None # clear for future iterations
691 state[transition].append(ctx.node())
691 state[transition].append(ctx.node())
692 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
692 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
693 check_state(state, interactive=False)
693 check_state(state, interactive=False)
694 # bisect
694 # bisect
695 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
695 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
696 # update to next check
696 # update to next check
697 node = nodes[0]
697 node = nodes[0]
698 if not noupdate:
698 if not noupdate:
699 cmdutil.bailifchanged(repo)
699 cmdutil.bailifchanged(repo)
700 hg.clean(repo, node, show_stats=False)
700 hg.clean(repo, node, show_stats=False)
701 finally:
701 finally:
702 state['current'] = [node]
702 state['current'] = [node]
703 hbisect.save_state(repo, state)
703 hbisect.save_state(repo, state)
704 print_result(nodes, good)
704 print_result(nodes, good)
705 return
705 return
706
706
707 # update state
707 # update state
708
708
709 if rev:
709 if rev:
710 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
710 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
711 else:
711 else:
712 nodes = [repo.lookup('.')]
712 nodes = [repo.lookup('.')]
713
713
714 if good or bad or skip:
714 if good or bad or skip:
715 if good:
715 if good:
716 state['good'] += nodes
716 state['good'] += nodes
717 elif bad:
717 elif bad:
718 state['bad'] += nodes
718 state['bad'] += nodes
719 elif skip:
719 elif skip:
720 state['skip'] += nodes
720 state['skip'] += nodes
721 hbisect.save_state(repo, state)
721 hbisect.save_state(repo, state)
722
722
723 if not check_state(state):
723 if not check_state(state):
724 return
724 return
725
725
726 # actually bisect
726 # actually bisect
727 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
727 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
728 if extend:
728 if extend:
729 if not changesets:
729 if not changesets:
730 extendnode = extendbisectrange(nodes, good)
730 extendnode = extendbisectrange(nodes, good)
731 if extendnode is not None:
731 if extendnode is not None:
732 ui.write(_("Extending search to changeset %d:%s\n"
732 ui.write(_("Extending search to changeset %d:%s\n"
733 % (extendnode.rev(), extendnode)))
733 % (extendnode.rev(), extendnode)))
734 state['current'] = [extendnode.node()]
734 state['current'] = [extendnode.node()]
735 hbisect.save_state(repo, state)
735 hbisect.save_state(repo, state)
736 if noupdate:
736 if noupdate:
737 return
737 return
738 cmdutil.bailifchanged(repo)
738 cmdutil.bailifchanged(repo)
739 return hg.clean(repo, extendnode.node())
739 return hg.clean(repo, extendnode.node())
740 raise util.Abort(_("nothing to extend"))
740 raise util.Abort(_("nothing to extend"))
741
741
742 if changesets == 0:
742 if changesets == 0:
743 print_result(nodes, good)
743 print_result(nodes, good)
744 else:
744 else:
745 assert len(nodes) == 1 # only a single node can be tested next
745 assert len(nodes) == 1 # only a single node can be tested next
746 node = nodes[0]
746 node = nodes[0]
747 # compute the approximate number of remaining tests
747 # compute the approximate number of remaining tests
748 tests, size = 0, 2
748 tests, size = 0, 2
749 while size <= changesets:
749 while size <= changesets:
750 tests, size = tests + 1, size * 2
750 tests, size = tests + 1, size * 2
751 rev = repo.changelog.rev(node)
751 rev = repo.changelog.rev(node)
752 ui.write(_("Testing changeset %d:%s "
752 ui.write(_("Testing changeset %d:%s "
753 "(%d changesets remaining, ~%d tests)\n")
753 "(%d changesets remaining, ~%d tests)\n")
754 % (rev, short(node), changesets, tests))
754 % (rev, short(node), changesets, tests))
755 state['current'] = [node]
755 state['current'] = [node]
756 hbisect.save_state(repo, state)
756 hbisect.save_state(repo, state)
757 if not noupdate:
757 if not noupdate:
758 cmdutil.bailifchanged(repo)
758 cmdutil.bailifchanged(repo)
759 return hg.clean(repo, node)
759 return hg.clean(repo, node)
760
760
761 @command('bookmarks|bookmark',
761 @command('bookmarks|bookmark',
762 [('f', 'force', False, _('force')),
762 [('f', 'force', False, _('force')),
763 ('r', 'rev', '', _('revision'), _('REV')),
763 ('r', 'rev', '', _('revision'), _('REV')),
764 ('d', 'delete', False, _('delete a given bookmark')),
764 ('d', 'delete', False, _('delete a given bookmark')),
765 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
765 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
766 ('i', 'inactive', False, _('mark a bookmark inactive'))],
766 ('i', 'inactive', False, _('mark a bookmark inactive'))],
767 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
767 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
768 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
768 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
769 rename=None, inactive=False):
769 rename=None, inactive=False):
770 '''track a line of development with movable markers
770 '''track a line of development with movable markers
771
771
772 Bookmarks are pointers to certain commits that move when committing.
772 Bookmarks are pointers to certain commits that move when committing.
773 Bookmarks are local. They can be renamed, copied and deleted. It is
773 Bookmarks are local. They can be renamed, copied and deleted. It is
774 possible to use :hg:`merge NAME` to merge from a given bookmark, and
774 possible to use :hg:`merge NAME` to merge from a given bookmark, and
775 :hg:`update NAME` to update to a given bookmark.
775 :hg:`update NAME` to update to a given bookmark.
776
776
777 You can use :hg:`bookmark NAME` to set a bookmark on the working
777 You can use :hg:`bookmark NAME` to set a bookmark on the working
778 directory's parent revision with the given name. If you specify
778 directory's parent revision with the given name. If you specify
779 a revision using -r REV (where REV may be an existing bookmark),
779 a revision using -r REV (where REV may be an existing bookmark),
780 the bookmark is assigned to that revision.
780 the bookmark is assigned to that revision.
781
781
782 Bookmarks can be pushed and pulled between repositories (see :hg:`help
782 Bookmarks can be pushed and pulled between repositories (see :hg:`help
783 push` and :hg:`help pull`). This requires both the local and remote
783 push` and :hg:`help pull`). This requires both the local and remote
784 repositories to support bookmarks. For versions prior to 1.8, this means
784 repositories to support bookmarks. For versions prior to 1.8, this means
785 the bookmarks extension must be enabled.
785 the bookmarks extension must be enabled.
786
786
787 With -i/--inactive, the new bookmark will not be made the active
787 With -i/--inactive, the new bookmark will not be made the active
788 bookmark. If -r/--rev is given, the new bookmark will not be made
788 bookmark. If -r/--rev is given, the new bookmark will not be made
789 active even if -i/--inactive is not given. If no NAME is given, the
789 active even if -i/--inactive is not given. If no NAME is given, the
790 current active bookmark will be marked inactive.
790 current active bookmark will be marked inactive.
791 '''
791 '''
792 hexfn = ui.debugflag and hex or short
792 hexfn = ui.debugflag and hex or short
793 marks = repo._bookmarks
793 marks = repo._bookmarks
794 cur = repo.changectx('.').node()
794 cur = repo.changectx('.').node()
795
795
796 def checkformat(mark):
796 def checkformat(mark):
797 mark = mark.strip()
797 mark = mark.strip()
798 if not mark:
798 if not mark:
799 raise util.Abort(_("bookmark names cannot consist entirely of "
799 raise util.Abort(_("bookmark names cannot consist entirely of "
800 "whitespace"))
800 "whitespace"))
801 scmutil.checknewlabel(repo, mark, 'bookmark')
801 scmutil.checknewlabel(repo, mark, 'bookmark')
802 return mark
802 return mark
803
803
804 def checkconflict(repo, mark, force=False):
804 def checkconflict(repo, mark, force=False):
805 if mark in marks and not force:
805 if mark in marks and not force:
806 raise util.Abort(_("bookmark '%s' already exists "
806 raise util.Abort(_("bookmark '%s' already exists "
807 "(use -f to force)") % mark)
807 "(use -f to force)") % mark)
808 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
808 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
809 and not force):
809 and not force):
810 raise util.Abort(
810 raise util.Abort(
811 _("a bookmark cannot have the name of an existing branch"))
811 _("a bookmark cannot have the name of an existing branch"))
812
812
813 if delete and rename:
813 if delete and rename:
814 raise util.Abort(_("--delete and --rename are incompatible"))
814 raise util.Abort(_("--delete and --rename are incompatible"))
815 if delete and rev:
815 if delete and rev:
816 raise util.Abort(_("--rev is incompatible with --delete"))
816 raise util.Abort(_("--rev is incompatible with --delete"))
817 if rename and rev:
817 if rename and rev:
818 raise util.Abort(_("--rev is incompatible with --rename"))
818 raise util.Abort(_("--rev is incompatible with --rename"))
819 if mark is None and (delete or rev):
819 if mark is None and (delete or rev):
820 raise util.Abort(_("bookmark name required"))
820 raise util.Abort(_("bookmark name required"))
821
821
822 if delete:
822 if delete:
823 if mark not in marks:
823 if mark not in marks:
824 raise util.Abort(_("bookmark '%s' does not exist") % mark)
824 raise util.Abort(_("bookmark '%s' does not exist") % mark)
825 if mark == repo._bookmarkcurrent:
825 if mark == repo._bookmarkcurrent:
826 bookmarks.setcurrent(repo, None)
826 bookmarks.setcurrent(repo, None)
827 del marks[mark]
827 del marks[mark]
828 marks.write()
828 marks.write()
829
829
830 elif rename:
830 elif rename:
831 if mark is None:
831 if mark is None:
832 raise util.Abort(_("new bookmark name required"))
832 raise util.Abort(_("new bookmark name required"))
833 mark = checkformat(mark)
833 mark = checkformat(mark)
834 if rename not in marks:
834 if rename not in marks:
835 raise util.Abort(_("bookmark '%s' does not exist") % rename)
835 raise util.Abort(_("bookmark '%s' does not exist") % rename)
836 checkconflict(repo, mark, force)
836 checkconflict(repo, mark, force)
837 marks[mark] = marks[rename]
837 marks[mark] = marks[rename]
838 if repo._bookmarkcurrent == rename and not inactive:
838 if repo._bookmarkcurrent == rename and not inactive:
839 bookmarks.setcurrent(repo, mark)
839 bookmarks.setcurrent(repo, mark)
840 del marks[rename]
840 del marks[rename]
841 marks.write()
841 marks.write()
842
842
843 elif mark is not None:
843 elif mark is not None:
844 mark = checkformat(mark)
844 mark = checkformat(mark)
845 if inactive and mark == repo._bookmarkcurrent:
845 if inactive and mark == repo._bookmarkcurrent:
846 bookmarks.setcurrent(repo, None)
846 bookmarks.setcurrent(repo, None)
847 return
847 return
848 checkconflict(repo, mark, force)
848 checkconflict(repo, mark, force)
849 if rev:
849 if rev:
850 marks[mark] = scmutil.revsingle(repo, rev).node()
850 marks[mark] = scmutil.revsingle(repo, rev).node()
851 else:
851 else:
852 marks[mark] = cur
852 marks[mark] = cur
853 if not inactive and cur == marks[mark]:
853 if not inactive and cur == marks[mark]:
854 bookmarks.setcurrent(repo, mark)
854 bookmarks.setcurrent(repo, mark)
855 marks.write()
855 marks.write()
856
856
857 # Same message whether trying to deactivate the current bookmark (-i
857 # Same message whether trying to deactivate the current bookmark (-i
858 # with no NAME) or listing bookmarks
858 # with no NAME) or listing bookmarks
859 elif len(marks) == 0:
859 elif len(marks) == 0:
860 ui.status(_("no bookmarks set\n"))
860 ui.status(_("no bookmarks set\n"))
861
861
862 elif inactive:
862 elif inactive:
863 if not repo._bookmarkcurrent:
863 if not repo._bookmarkcurrent:
864 ui.status(_("no active bookmark\n"))
864 ui.status(_("no active bookmark\n"))
865 else:
865 else:
866 bookmarks.setcurrent(repo, None)
866 bookmarks.setcurrent(repo, None)
867
867
868 else: # show bookmarks
868 else: # show bookmarks
869 for bmark, n in sorted(marks.iteritems()):
869 for bmark, n in sorted(marks.iteritems()):
870 current = repo._bookmarkcurrent
870 current = repo._bookmarkcurrent
871 if bmark == current and n == cur:
871 if bmark == current and n == cur:
872 prefix, label = '*', 'bookmarks.current'
872 prefix, label = '*', 'bookmarks.current'
873 else:
873 else:
874 prefix, label = ' ', ''
874 prefix, label = ' ', ''
875
875
876 if ui.quiet:
876 if ui.quiet:
877 ui.write("%s\n" % bmark, label=label)
877 ui.write("%s\n" % bmark, label=label)
878 else:
878 else:
879 ui.write(" %s %-25s %d:%s\n" % (
879 ui.write(" %s %-25s %d:%s\n" % (
880 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
880 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
881 label=label)
881 label=label)
882
882
883 @command('branch',
883 @command('branch',
884 [('f', 'force', None,
884 [('f', 'force', None,
885 _('set branch name even if it shadows an existing branch')),
885 _('set branch name even if it shadows an existing branch')),
886 ('C', 'clean', None, _('reset branch name to parent branch name'))],
886 ('C', 'clean', None, _('reset branch name to parent branch name'))],
887 _('[-fC] [NAME]'))
887 _('[-fC] [NAME]'))
888 def branch(ui, repo, label=None, **opts):
888 def branch(ui, repo, label=None, **opts):
889 """set or show the current branch name
889 """set or show the current branch name
890
890
891 .. note::
891 .. note::
892 Branch names are permanent and global. Use :hg:`bookmark` to create a
892 Branch names are permanent and global. Use :hg:`bookmark` to create a
893 light-weight bookmark instead. See :hg:`help glossary` for more
893 light-weight bookmark instead. See :hg:`help glossary` for more
894 information about named branches and bookmarks.
894 information about named branches and bookmarks.
895
895
896 With no argument, show the current branch name. With one argument,
896 With no argument, show the current branch name. With one argument,
897 set the working directory branch name (the branch will not exist
897 set the working directory branch name (the branch will not exist
898 in the repository until the next commit). Standard practice
898 in the repository until the next commit). Standard practice
899 recommends that primary development take place on the 'default'
899 recommends that primary development take place on the 'default'
900 branch.
900 branch.
901
901
902 Unless -f/--force is specified, branch will not let you set a
902 Unless -f/--force is specified, branch will not let you set a
903 branch name that already exists, even if it's inactive.
903 branch name that already exists, even if it's inactive.
904
904
905 Use -C/--clean to reset the working directory branch to that of
905 Use -C/--clean to reset the working directory branch to that of
906 the parent of the working directory, negating a previous branch
906 the parent of the working directory, negating a previous branch
907 change.
907 change.
908
908
909 Use the command :hg:`update` to switch to an existing branch. Use
909 Use the command :hg:`update` to switch to an existing branch. Use
910 :hg:`commit --close-branch` to mark this branch as closed.
910 :hg:`commit --close-branch` to mark this branch as closed.
911
911
912 Returns 0 on success.
912 Returns 0 on success.
913 """
913 """
914 if not opts.get('clean') and not label:
914 if not opts.get('clean') and not label:
915 ui.write("%s\n" % repo.dirstate.branch())
915 ui.write("%s\n" % repo.dirstate.branch())
916 return
916 return
917
917
918 wlock = repo.wlock()
918 wlock = repo.wlock()
919 try:
919 try:
920 if opts.get('clean'):
920 if opts.get('clean'):
921 label = repo[None].p1().branch()
921 label = repo[None].p1().branch()
922 repo.dirstate.setbranch(label)
922 repo.dirstate.setbranch(label)
923 ui.status(_('reset working directory to branch %s\n') % label)
923 ui.status(_('reset working directory to branch %s\n') % label)
924 elif label:
924 elif label:
925 if not opts.get('force') and label in repo.branchmap():
925 if not opts.get('force') and label in repo.branchmap():
926 if label not in [p.branch() for p in repo.parents()]:
926 if label not in [p.branch() for p in repo.parents()]:
927 raise util.Abort(_('a branch of the same name already'
927 raise util.Abort(_('a branch of the same name already'
928 ' exists'),
928 ' exists'),
929 # i18n: "it" refers to an existing branch
929 # i18n: "it" refers to an existing branch
930 hint=_("use 'hg update' to switch to it"))
930 hint=_("use 'hg update' to switch to it"))
931 scmutil.checknewlabel(repo, label, 'branch')
931 scmutil.checknewlabel(repo, label, 'branch')
932 repo.dirstate.setbranch(label)
932 repo.dirstate.setbranch(label)
933 ui.status(_('marked working directory as branch %s\n') % label)
933 ui.status(_('marked working directory as branch %s\n') % label)
934 ui.status(_('(branches are permanent and global, '
934 ui.status(_('(branches are permanent and global, '
935 'did you want a bookmark?)\n'))
935 'did you want a bookmark?)\n'))
936 finally:
936 finally:
937 wlock.release()
937 wlock.release()
938
938
939 @command('branches',
939 @command('branches',
940 [('a', 'active', False, _('show only branches that have unmerged heads')),
940 [('a', 'active', False, _('show only branches that have unmerged heads')),
941 ('c', 'closed', False, _('show normal and closed branches'))],
941 ('c', 'closed', False, _('show normal and closed branches'))],
942 _('[-ac]'))
942 _('[-ac]'))
943 def branches(ui, repo, active=False, closed=False):
943 def branches(ui, repo, active=False, closed=False):
944 """list repository named branches
944 """list repository named branches
945
945
946 List the repository's named branches, indicating which ones are
946 List the repository's named branches, indicating which ones are
947 inactive. If -c/--closed is specified, also list branches which have
947 inactive. If -c/--closed is specified, also list branches which have
948 been marked closed (see :hg:`commit --close-branch`).
948 been marked closed (see :hg:`commit --close-branch`).
949
949
950 If -a/--active is specified, only show active branches. A branch
950 If -a/--active is specified, only show active branches. A branch
951 is considered active if it contains repository heads.
951 is considered active if it contains repository heads.
952
952
953 Use the command :hg:`update` to switch to an existing branch.
953 Use the command :hg:`update` to switch to an existing branch.
954
954
955 Returns 0.
955 Returns 0.
956 """
956 """
957
957
958 hexfunc = ui.debugflag and hex or short
958 hexfunc = ui.debugflag and hex or short
959
959
960 activebranches = set([repo[n].branch() for n in repo.heads()])
960 activebranches = set([repo[n].branch() for n in repo.heads()])
961 branches = []
961 branches = []
962 for tag, heads in repo.branchmap().iteritems():
962 for tag, heads in repo.branchmap().iteritems():
963 for h in reversed(heads):
963 for h in reversed(heads):
964 ctx = repo[h]
964 ctx = repo[h]
965 isopen = not ctx.closesbranch()
965 isopen = not ctx.closesbranch()
966 if isopen:
966 if isopen:
967 tip = ctx
967 tip = ctx
968 break
968 break
969 else:
969 else:
970 tip = repo[heads[-1]]
970 tip = repo[heads[-1]]
971 isactive = tag in activebranches and isopen
971 isactive = tag in activebranches and isopen
972 branches.append((tip, isactive, isopen))
972 branches.append((tip, isactive, isopen))
973 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
973 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
974 reverse=True)
974 reverse=True)
975
975
976 for ctx, isactive, isopen in branches:
976 for ctx, isactive, isopen in branches:
977 if (not active) or isactive:
977 if (not active) or isactive:
978 if isactive:
978 if isactive:
979 label = 'branches.active'
979 label = 'branches.active'
980 notice = ''
980 notice = ''
981 elif not isopen:
981 elif not isopen:
982 if not closed:
982 if not closed:
983 continue
983 continue
984 label = 'branches.closed'
984 label = 'branches.closed'
985 notice = _(' (closed)')
985 notice = _(' (closed)')
986 else:
986 else:
987 label = 'branches.inactive'
987 label = 'branches.inactive'
988 notice = _(' (inactive)')
988 notice = _(' (inactive)')
989 if ctx.branch() == repo.dirstate.branch():
989 if ctx.branch() == repo.dirstate.branch():
990 label = 'branches.current'
990 label = 'branches.current'
991 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
991 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
992 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
992 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
993 'log.changeset changeset.%s' % ctx.phasestr())
993 'log.changeset changeset.%s' % ctx.phasestr())
994 tag = ui.label(ctx.branch(), label)
994 tag = ui.label(ctx.branch(), label)
995 if ui.quiet:
995 if ui.quiet:
996 ui.write("%s\n" % tag)
996 ui.write("%s\n" % tag)
997 else:
997 else:
998 ui.write("%s %s%s\n" % (tag, rev, notice))
998 ui.write("%s %s%s\n" % (tag, rev, notice))
999
999
1000 @command('bundle',
1000 @command('bundle',
1001 [('f', 'force', None, _('run even when the destination is unrelated')),
1001 [('f', 'force', None, _('run even when the destination is unrelated')),
1002 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1002 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1003 _('REV')),
1003 _('REV')),
1004 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1004 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1005 _('BRANCH')),
1005 _('BRANCH')),
1006 ('', 'base', [],
1006 ('', 'base', [],
1007 _('a base changeset assumed to be available at the destination'),
1007 _('a base changeset assumed to be available at the destination'),
1008 _('REV')),
1008 _('REV')),
1009 ('a', 'all', None, _('bundle all changesets in the repository')),
1009 ('a', 'all', None, _('bundle all changesets in the repository')),
1010 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1010 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1011 ] + remoteopts,
1011 ] + remoteopts,
1012 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1012 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1013 def bundle(ui, repo, fname, dest=None, **opts):
1013 def bundle(ui, repo, fname, dest=None, **opts):
1014 """create a changegroup file
1014 """create a changegroup file
1015
1015
1016 Generate a compressed changegroup file collecting changesets not
1016 Generate a compressed changegroup file collecting changesets not
1017 known to be in another repository.
1017 known to be in another repository.
1018
1018
1019 If you omit the destination repository, then hg assumes the
1019 If you omit the destination repository, then hg assumes the
1020 destination will have all the nodes you specify with --base
1020 destination will have all the nodes you specify with --base
1021 parameters. To create a bundle containing all changesets, use
1021 parameters. To create a bundle containing all changesets, use
1022 -a/--all (or --base null).
1022 -a/--all (or --base null).
1023
1023
1024 You can change compression method with the -t/--type option.
1024 You can change compression method with the -t/--type option.
1025 The available compression methods are: none, bzip2, and
1025 The available compression methods are: none, bzip2, and
1026 gzip (by default, bundles are compressed using bzip2).
1026 gzip (by default, bundles are compressed using bzip2).
1027
1027
1028 The bundle file can then be transferred using conventional means
1028 The bundle file can then be transferred using conventional means
1029 and applied to another repository with the unbundle or pull
1029 and applied to another repository with the unbundle or pull
1030 command. This is useful when direct push and pull are not
1030 command. This is useful when direct push and pull are not
1031 available or when exporting an entire repository is undesirable.
1031 available or when exporting an entire repository is undesirable.
1032
1032
1033 Applying bundles preserves all changeset contents including
1033 Applying bundles preserves all changeset contents including
1034 permissions, copy/rename information, and revision history.
1034 permissions, copy/rename information, and revision history.
1035
1035
1036 Returns 0 on success, 1 if no changes found.
1036 Returns 0 on success, 1 if no changes found.
1037 """
1037 """
1038 revs = None
1038 revs = None
1039 if 'rev' in opts:
1039 if 'rev' in opts:
1040 revs = scmutil.revrange(repo, opts['rev'])
1040 revs = scmutil.revrange(repo, opts['rev'])
1041
1041
1042 bundletype = opts.get('type', 'bzip2').lower()
1042 bundletype = opts.get('type', 'bzip2').lower()
1043 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1043 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1044 bundletype = btypes.get(bundletype)
1044 bundletype = btypes.get(bundletype)
1045 if bundletype not in changegroup.bundletypes:
1045 if bundletype not in changegroup.bundletypes:
1046 raise util.Abort(_('unknown bundle type specified with --type'))
1046 raise util.Abort(_('unknown bundle type specified with --type'))
1047
1047
1048 if opts.get('all'):
1048 if opts.get('all'):
1049 base = ['null']
1049 base = ['null']
1050 else:
1050 else:
1051 base = scmutil.revrange(repo, opts.get('base'))
1051 base = scmutil.revrange(repo, opts.get('base'))
1052 if base:
1052 if base:
1053 if dest:
1053 if dest:
1054 raise util.Abort(_("--base is incompatible with specifying "
1054 raise util.Abort(_("--base is incompatible with specifying "
1055 "a destination"))
1055 "a destination"))
1056 common = [repo.lookup(rev) for rev in base]
1056 common = [repo.lookup(rev) for rev in base]
1057 heads = revs and map(repo.lookup, revs) or revs
1057 heads = revs and map(repo.lookup, revs) or revs
1058 cg = repo.getbundle('bundle', heads=heads, common=common)
1058 cg = repo.getbundle('bundle', heads=heads, common=common)
1059 outgoing = None
1059 outgoing = None
1060 else:
1060 else:
1061 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1061 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1062 dest, branches = hg.parseurl(dest, opts.get('branch'))
1062 dest, branches = hg.parseurl(dest, opts.get('branch'))
1063 other = hg.peer(repo, opts, dest)
1063 other = hg.peer(repo, opts, dest)
1064 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1064 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1065 heads = revs and map(repo.lookup, revs) or revs
1065 heads = revs and map(repo.lookup, revs) or revs
1066 outgoing = discovery.findcommonoutgoing(repo, other,
1066 outgoing = discovery.findcommonoutgoing(repo, other,
1067 onlyheads=heads,
1067 onlyheads=heads,
1068 force=opts.get('force'),
1068 force=opts.get('force'),
1069 portable=True)
1069 portable=True)
1070 cg = repo.getlocalbundle('bundle', outgoing)
1070 cg = repo.getlocalbundle('bundle', outgoing)
1071 if not cg:
1071 if not cg:
1072 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1072 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1073 return 1
1073 return 1
1074
1074
1075 changegroup.writebundle(cg, fname, bundletype)
1075 changegroup.writebundle(cg, fname, bundletype)
1076
1076
1077 @command('cat',
1077 @command('cat',
1078 [('o', 'output', '',
1078 [('o', 'output', '',
1079 _('print output to file with formatted name'), _('FORMAT')),
1079 _('print output to file with formatted name'), _('FORMAT')),
1080 ('r', 'rev', '', _('print the given revision'), _('REV')),
1080 ('r', 'rev', '', _('print the given revision'), _('REV')),
1081 ('', 'decode', None, _('apply any matching decode filter')),
1081 ('', 'decode', None, _('apply any matching decode filter')),
1082 ] + walkopts,
1082 ] + walkopts,
1083 _('[OPTION]... FILE...'))
1083 _('[OPTION]... FILE...'))
1084 def cat(ui, repo, file1, *pats, **opts):
1084 def cat(ui, repo, file1, *pats, **opts):
1085 """output the current or given revision of files
1085 """output the current or given revision of files
1086
1086
1087 Print the specified files as they were at the given revision. If
1087 Print the specified files as they were at the given revision. If
1088 no revision is given, the parent of the working directory is used,
1088 no revision is given, the parent of the working directory is used,
1089 or tip if no revision is checked out.
1089 or tip if no revision is checked out.
1090
1090
1091 Output may be to a file, in which case the name of the file is
1091 Output may be to a file, in which case the name of the file is
1092 given using a format string. The formatting rules are the same as
1092 given using a format string. The formatting rules are the same as
1093 for the export command, with the following additions:
1093 for the export command, with the following additions:
1094
1094
1095 :``%s``: basename of file being printed
1095 :``%s``: basename of file being printed
1096 :``%d``: dirname of file being printed, or '.' if in repository root
1096 :``%d``: dirname of file being printed, or '.' if in repository root
1097 :``%p``: root-relative path name of file being printed
1097 :``%p``: root-relative path name of file being printed
1098
1098
1099 Returns 0 on success.
1099 Returns 0 on success.
1100 """
1100 """
1101 ctx = scmutil.revsingle(repo, opts.get('rev'))
1101 ctx = scmutil.revsingle(repo, opts.get('rev'))
1102 err = 1
1102 err = 1
1103 m = scmutil.match(ctx, (file1,) + pats, opts)
1103 m = scmutil.match(ctx, (file1,) + pats, opts)
1104 for abs in ctx.walk(m):
1104 for abs in ctx.walk(m):
1105 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1105 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1106 pathname=abs)
1106 pathname=abs)
1107 data = ctx[abs].data()
1107 data = ctx[abs].data()
1108 if opts.get('decode'):
1108 if opts.get('decode'):
1109 data = repo.wwritedata(abs, data)
1109 data = repo.wwritedata(abs, data)
1110 fp.write(data)
1110 fp.write(data)
1111 fp.close()
1111 fp.close()
1112 err = 0
1112 err = 0
1113 return err
1113 return err
1114
1114
1115 @command('^clone',
1115 @command('^clone',
1116 [('U', 'noupdate', None,
1116 [('U', 'noupdate', None,
1117 _('the clone will include an empty working copy (only a repository)')),
1117 _('the clone will include an empty working copy (only a repository)')),
1118 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1118 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1119 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1119 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1120 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1120 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1121 ('', 'pull', None, _('use pull protocol to copy metadata')),
1121 ('', 'pull', None, _('use pull protocol to copy metadata')),
1122 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1122 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1123 ] + remoteopts,
1123 ] + remoteopts,
1124 _('[OPTION]... SOURCE [DEST]'))
1124 _('[OPTION]... SOURCE [DEST]'))
1125 def clone(ui, source, dest=None, **opts):
1125 def clone(ui, source, dest=None, **opts):
1126 """make a copy of an existing repository
1126 """make a copy of an existing repository
1127
1127
1128 Create a copy of an existing repository in a new directory.
1128 Create a copy of an existing repository in a new directory.
1129
1129
1130 If no destination directory name is specified, it defaults to the
1130 If no destination directory name is specified, it defaults to the
1131 basename of the source.
1131 basename of the source.
1132
1132
1133 The location of the source is added to the new repository's
1133 The location of the source is added to the new repository's
1134 ``.hg/hgrc`` file, as the default to be used for future pulls.
1134 ``.hg/hgrc`` file, as the default to be used for future pulls.
1135
1135
1136 Only local paths and ``ssh://`` URLs are supported as
1136 Only local paths and ``ssh://`` URLs are supported as
1137 destinations. For ``ssh://`` destinations, no working directory or
1137 destinations. For ``ssh://`` destinations, no working directory or
1138 ``.hg/hgrc`` will be created on the remote side.
1138 ``.hg/hgrc`` will be created on the remote side.
1139
1139
1140 To pull only a subset of changesets, specify one or more revisions
1140 To pull only a subset of changesets, specify one or more revisions
1141 identifiers with -r/--rev or branches with -b/--branch. The
1141 identifiers with -r/--rev or branches with -b/--branch. The
1142 resulting clone will contain only the specified changesets and
1142 resulting clone will contain only the specified changesets and
1143 their ancestors. These options (or 'clone src#rev dest') imply
1143 their ancestors. These options (or 'clone src#rev dest') imply
1144 --pull, even for local source repositories. Note that specifying a
1144 --pull, even for local source repositories. Note that specifying a
1145 tag will include the tagged changeset but not the changeset
1145 tag will include the tagged changeset but not the changeset
1146 containing the tag.
1146 containing the tag.
1147
1147
1148 To check out a particular version, use -u/--update, or
1148 To check out a particular version, use -u/--update, or
1149 -U/--noupdate to create a clone with no working directory.
1149 -U/--noupdate to create a clone with no working directory.
1150
1150
1151 .. container:: verbose
1151 .. container:: verbose
1152
1152
1153 For efficiency, hardlinks are used for cloning whenever the
1153 For efficiency, hardlinks are used for cloning whenever the
1154 source and destination are on the same filesystem (note this
1154 source and destination are on the same filesystem (note this
1155 applies only to the repository data, not to the working
1155 applies only to the repository data, not to the working
1156 directory). Some filesystems, such as AFS, implement hardlinking
1156 directory). Some filesystems, such as AFS, implement hardlinking
1157 incorrectly, but do not report errors. In these cases, use the
1157 incorrectly, but do not report errors. In these cases, use the
1158 --pull option to avoid hardlinking.
1158 --pull option to avoid hardlinking.
1159
1159
1160 In some cases, you can clone repositories and the working
1160 In some cases, you can clone repositories and the working
1161 directory using full hardlinks with ::
1161 directory using full hardlinks with ::
1162
1162
1163 $ cp -al REPO REPOCLONE
1163 $ cp -al REPO REPOCLONE
1164
1164
1165 This is the fastest way to clone, but it is not always safe. The
1165 This is the fastest way to clone, but it is not always safe. The
1166 operation is not atomic (making sure REPO is not modified during
1166 operation is not atomic (making sure REPO is not modified during
1167 the operation is up to you) and you have to make sure your
1167 the operation is up to you) and you have to make sure your
1168 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1168 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1169 so). Also, this is not compatible with certain extensions that
1169 so). Also, this is not compatible with certain extensions that
1170 place their metadata under the .hg directory, such as mq.
1170 place their metadata under the .hg directory, such as mq.
1171
1171
1172 Mercurial will update the working directory to the first applicable
1172 Mercurial will update the working directory to the first applicable
1173 revision from this list:
1173 revision from this list:
1174
1174
1175 a) null if -U or the source repository has no changesets
1175 a) null if -U or the source repository has no changesets
1176 b) if -u . and the source repository is local, the first parent of
1176 b) if -u . and the source repository is local, the first parent of
1177 the source repository's working directory
1177 the source repository's working directory
1178 c) the changeset specified with -u (if a branch name, this means the
1178 c) the changeset specified with -u (if a branch name, this means the
1179 latest head of that branch)
1179 latest head of that branch)
1180 d) the changeset specified with -r
1180 d) the changeset specified with -r
1181 e) the tipmost head specified with -b
1181 e) the tipmost head specified with -b
1182 f) the tipmost head specified with the url#branch source syntax
1182 f) the tipmost head specified with the url#branch source syntax
1183 g) the tipmost head of the default branch
1183 g) the tipmost head of the default branch
1184 h) tip
1184 h) tip
1185
1185
1186 Examples:
1186 Examples:
1187
1187
1188 - clone a remote repository to a new directory named hg/::
1188 - clone a remote repository to a new directory named hg/::
1189
1189
1190 hg clone http://selenic.com/hg
1190 hg clone http://selenic.com/hg
1191
1191
1192 - create a lightweight local clone::
1192 - create a lightweight local clone::
1193
1193
1194 hg clone project/ project-feature/
1194 hg clone project/ project-feature/
1195
1195
1196 - clone from an absolute path on an ssh server (note double-slash)::
1196 - clone from an absolute path on an ssh server (note double-slash)::
1197
1197
1198 hg clone ssh://user@server//home/projects/alpha/
1198 hg clone ssh://user@server//home/projects/alpha/
1199
1199
1200 - do a high-speed clone over a LAN while checking out a
1200 - do a high-speed clone over a LAN while checking out a
1201 specified version::
1201 specified version::
1202
1202
1203 hg clone --uncompressed http://server/repo -u 1.5
1203 hg clone --uncompressed http://server/repo -u 1.5
1204
1204
1205 - create a repository without changesets after a particular revision::
1205 - create a repository without changesets after a particular revision::
1206
1206
1207 hg clone -r 04e544 experimental/ good/
1207 hg clone -r 04e544 experimental/ good/
1208
1208
1209 - clone (and track) a particular named branch::
1209 - clone (and track) a particular named branch::
1210
1210
1211 hg clone http://selenic.com/hg#stable
1211 hg clone http://selenic.com/hg#stable
1212
1212
1213 See :hg:`help urls` for details on specifying URLs.
1213 See :hg:`help urls` for details on specifying URLs.
1214
1214
1215 Returns 0 on success.
1215 Returns 0 on success.
1216 """
1216 """
1217 if opts.get('noupdate') and opts.get('updaterev'):
1217 if opts.get('noupdate') and opts.get('updaterev'):
1218 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1218 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1219
1219
1220 r = hg.clone(ui, opts, source, dest,
1220 r = hg.clone(ui, opts, source, dest,
1221 pull=opts.get('pull'),
1221 pull=opts.get('pull'),
1222 stream=opts.get('uncompressed'),
1222 stream=opts.get('uncompressed'),
1223 rev=opts.get('rev'),
1223 rev=opts.get('rev'),
1224 update=opts.get('updaterev') or not opts.get('noupdate'),
1224 update=opts.get('updaterev') or not opts.get('noupdate'),
1225 branch=opts.get('branch'))
1225 branch=opts.get('branch'))
1226
1226
1227 return r is None
1227 return r is None
1228
1228
1229 @command('^commit|ci',
1229 @command('^commit|ci',
1230 [('A', 'addremove', None,
1230 [('A', 'addremove', None,
1231 _('mark new/missing files as added/removed before committing')),
1231 _('mark new/missing files as added/removed before committing')),
1232 ('', 'close-branch', None,
1232 ('', 'close-branch', None,
1233 _('mark a branch as closed, hiding it from the branch list')),
1233 _('mark a branch as closed, hiding it from the branch list')),
1234 ('', 'amend', None, _('amend the parent of the working dir')),
1234 ('', 'amend', None, _('amend the parent of the working dir')),
1235 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1235 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1236 _('[OPTION]... [FILE]...'))
1236 _('[OPTION]... [FILE]...'))
1237 def commit(ui, repo, *pats, **opts):
1237 def commit(ui, repo, *pats, **opts):
1238 """commit the specified files or all outstanding changes
1238 """commit the specified files or all outstanding changes
1239
1239
1240 Commit changes to the given files into the repository. Unlike a
1240 Commit changes to the given files into the repository. Unlike a
1241 centralized SCM, this operation is a local operation. See
1241 centralized SCM, this operation is a local operation. See
1242 :hg:`push` for a way to actively distribute your changes.
1242 :hg:`push` for a way to actively distribute your changes.
1243
1243
1244 If a list of files is omitted, all changes reported by :hg:`status`
1244 If a list of files is omitted, all changes reported by :hg:`status`
1245 will be committed.
1245 will be committed.
1246
1246
1247 If you are committing the result of a merge, do not provide any
1247 If you are committing the result of a merge, do not provide any
1248 filenames or -I/-X filters.
1248 filenames or -I/-X filters.
1249
1249
1250 If no commit message is specified, Mercurial starts your
1250 If no commit message is specified, Mercurial starts your
1251 configured editor where you can enter a message. In case your
1251 configured editor where you can enter a message. In case your
1252 commit fails, you will find a backup of your message in
1252 commit fails, you will find a backup of your message in
1253 ``.hg/last-message.txt``.
1253 ``.hg/last-message.txt``.
1254
1254
1255 The --amend flag can be used to amend the parent of the
1255 The --amend flag can be used to amend the parent of the
1256 working directory with a new commit that contains the changes
1256 working directory with a new commit that contains the changes
1257 in the parent in addition to those currently reported by :hg:`status`,
1257 in the parent in addition to those currently reported by :hg:`status`,
1258 if there are any. The old commit is stored in a backup bundle in
1258 if there are any. The old commit is stored in a backup bundle in
1259 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1259 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1260 on how to restore it).
1260 on how to restore it).
1261
1261
1262 Message, user and date are taken from the amended commit unless
1262 Message, user and date are taken from the amended commit unless
1263 specified. When a message isn't specified on the command line,
1263 specified. When a message isn't specified on the command line,
1264 the editor will open with the message of the amended commit.
1264 the editor will open with the message of the amended commit.
1265
1265
1266 It is not possible to amend public changesets (see :hg:`help phases`)
1266 It is not possible to amend public changesets (see :hg:`help phases`)
1267 or changesets that have children.
1267 or changesets that have children.
1268
1268
1269 See :hg:`help dates` for a list of formats valid for -d/--date.
1269 See :hg:`help dates` for a list of formats valid for -d/--date.
1270
1270
1271 Returns 0 on success, 1 if nothing changed.
1271 Returns 0 on success, 1 if nothing changed.
1272 """
1272 """
1273 if opts.get('subrepos'):
1273 if opts.get('subrepos'):
1274 # Let --subrepos on the command line override config setting.
1274 # Let --subrepos on the command line override config setting.
1275 ui.setconfig('ui', 'commitsubrepos', True)
1275 ui.setconfig('ui', 'commitsubrepos', True)
1276
1276
1277 extra = {}
1277 extra = {}
1278 if opts.get('close_branch'):
1278 if opts.get('close_branch'):
1279 if repo['.'].node() not in repo.branchheads():
1279 if repo['.'].node() not in repo.branchheads():
1280 # The topo heads set is included in the branch heads set of the
1280 # The topo heads set is included in the branch heads set of the
1281 # current branch, so it's sufficient to test branchheads
1281 # current branch, so it's sufficient to test branchheads
1282 raise util.Abort(_('can only close branch heads'))
1282 raise util.Abort(_('can only close branch heads'))
1283 extra['close'] = 1
1283 extra['close'] = 1
1284
1284
1285 branch = repo[None].branch()
1285 branch = repo[None].branch()
1286 bheads = repo.branchheads(branch)
1286 bheads = repo.branchheads(branch)
1287
1287
1288 if opts.get('amend'):
1288 if opts.get('amend'):
1289 if ui.configbool('ui', 'commitsubrepos'):
1289 if ui.configbool('ui', 'commitsubrepos'):
1290 raise util.Abort(_('cannot amend recursively'))
1290 raise util.Abort(_('cannot amend recursively'))
1291
1291
1292 old = repo['.']
1292 old = repo['.']
1293 if old.phase() == phases.public:
1293 if old.phase() == phases.public:
1294 raise util.Abort(_('cannot amend public changesets'))
1294 raise util.Abort(_('cannot amend public changesets'))
1295 if len(old.parents()) > 1:
1295 if len(old.parents()) > 1:
1296 raise util.Abort(_('cannot amend merge changesets'))
1296 raise util.Abort(_('cannot amend merge changesets'))
1297 if len(repo[None].parents()) > 1:
1297 if len(repo[None].parents()) > 1:
1298 raise util.Abort(_('cannot amend while merging'))
1298 raise util.Abort(_('cannot amend while merging'))
1299 if (not obsolete._enabled) and old.children():
1299 if (not obsolete._enabled) and old.children():
1300 raise util.Abort(_('cannot amend changeset with children'))
1300 raise util.Abort(_('cannot amend changeset with children'))
1301
1301
1302 e = cmdutil.commiteditor
1302 e = cmdutil.commiteditor
1303 if opts.get('force_editor'):
1303 if opts.get('force_editor'):
1304 e = cmdutil.commitforceeditor
1304 e = cmdutil.commitforceeditor
1305
1305
1306 def commitfunc(ui, repo, message, match, opts):
1306 def commitfunc(ui, repo, message, match, opts):
1307 editor = e
1307 editor = e
1308 # message contains text from -m or -l, if it's empty,
1308 # message contains text from -m or -l, if it's empty,
1309 # open the editor with the old message
1309 # open the editor with the old message
1310 if not message:
1310 if not message:
1311 message = old.description()
1311 message = old.description()
1312 editor = cmdutil.commitforceeditor
1312 editor = cmdutil.commitforceeditor
1313 return repo.commit(message,
1313 return repo.commit(message,
1314 opts.get('user') or old.user(),
1314 opts.get('user') or old.user(),
1315 opts.get('date') or old.date(),
1315 opts.get('date') or old.date(),
1316 match,
1316 match,
1317 editor=editor,
1317 editor=editor,
1318 extra=extra)
1318 extra=extra)
1319
1319
1320 current = repo._bookmarkcurrent
1320 current = repo._bookmarkcurrent
1321 marks = old.bookmarks()
1321 marks = old.bookmarks()
1322 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1322 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1323 if node == old.node():
1323 if node == old.node():
1324 ui.status(_("nothing changed\n"))
1324 ui.status(_("nothing changed\n"))
1325 return 1
1325 return 1
1326 elif marks:
1326 elif marks:
1327 ui.debug('moving bookmarks %r from %s to %s\n' %
1327 ui.debug('moving bookmarks %r from %s to %s\n' %
1328 (marks, old.hex(), hex(node)))
1328 (marks, old.hex(), hex(node)))
1329 newmarks = repo._bookmarks
1329 newmarks = repo._bookmarks
1330 for bm in marks:
1330 for bm in marks:
1331 newmarks[bm] = node
1331 newmarks[bm] = node
1332 if bm == current:
1332 if bm == current:
1333 bookmarks.setcurrent(repo, bm)
1333 bookmarks.setcurrent(repo, bm)
1334 newmarks.write()
1334 newmarks.write()
1335 else:
1335 else:
1336 e = cmdutil.commiteditor
1336 e = cmdutil.commiteditor
1337 if opts.get('force_editor'):
1337 if opts.get('force_editor'):
1338 e = cmdutil.commitforceeditor
1338 e = cmdutil.commitforceeditor
1339
1339
1340 def commitfunc(ui, repo, message, match, opts):
1340 def commitfunc(ui, repo, message, match, opts):
1341 return repo.commit(message, opts.get('user'), opts.get('date'),
1341 return repo.commit(message, opts.get('user'), opts.get('date'),
1342 match, editor=e, extra=extra)
1342 match, editor=e, extra=extra)
1343
1343
1344 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1344 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1345
1345
1346 if not node:
1346 if not node:
1347 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1347 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1348 if stat[3]:
1348 if stat[3]:
1349 ui.status(_("nothing changed (%d missing files, see "
1349 ui.status(_("nothing changed (%d missing files, see "
1350 "'hg status')\n") % len(stat[3]))
1350 "'hg status')\n") % len(stat[3]))
1351 else:
1351 else:
1352 ui.status(_("nothing changed\n"))
1352 ui.status(_("nothing changed\n"))
1353 return 1
1353 return 1
1354
1354
1355 ctx = repo[node]
1355 ctx = repo[node]
1356 parents = ctx.parents()
1356 parents = ctx.parents()
1357
1357
1358 if (not opts.get('amend') and bheads and node not in bheads and not
1358 if (not opts.get('amend') and bheads and node not in bheads and not
1359 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1359 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1360 ui.status(_('created new head\n'))
1360 ui.status(_('created new head\n'))
1361 # The message is not printed for initial roots. For the other
1361 # The message is not printed for initial roots. For the other
1362 # changesets, it is printed in the following situations:
1362 # changesets, it is printed in the following situations:
1363 #
1363 #
1364 # Par column: for the 2 parents with ...
1364 # Par column: for the 2 parents with ...
1365 # N: null or no parent
1365 # N: null or no parent
1366 # B: parent is on another named branch
1366 # B: parent is on another named branch
1367 # C: parent is a regular non head changeset
1367 # C: parent is a regular non head changeset
1368 # H: parent was a branch head of the current branch
1368 # H: parent was a branch head of the current branch
1369 # Msg column: whether we print "created new head" message
1369 # Msg column: whether we print "created new head" message
1370 # In the following, it is assumed that there already exists some
1370 # In the following, it is assumed that there already exists some
1371 # initial branch heads of the current branch, otherwise nothing is
1371 # initial branch heads of the current branch, otherwise nothing is
1372 # printed anyway.
1372 # printed anyway.
1373 #
1373 #
1374 # Par Msg Comment
1374 # Par Msg Comment
1375 # N N y additional topo root
1375 # N N y additional topo root
1376 #
1376 #
1377 # B N y additional branch root
1377 # B N y additional branch root
1378 # C N y additional topo head
1378 # C N y additional topo head
1379 # H N n usual case
1379 # H N n usual case
1380 #
1380 #
1381 # B B y weird additional branch root
1381 # B B y weird additional branch root
1382 # C B y branch merge
1382 # C B y branch merge
1383 # H B n merge with named branch
1383 # H B n merge with named branch
1384 #
1384 #
1385 # C C y additional head from merge
1385 # C C y additional head from merge
1386 # C H n merge with a head
1386 # C H n merge with a head
1387 #
1387 #
1388 # H H n head merge: head count decreases
1388 # H H n head merge: head count decreases
1389
1389
1390 if not opts.get('close_branch'):
1390 if not opts.get('close_branch'):
1391 for r in parents:
1391 for r in parents:
1392 if r.closesbranch() and r.branch() == branch:
1392 if r.closesbranch() and r.branch() == branch:
1393 ui.status(_('reopening closed branch head %d\n') % r)
1393 ui.status(_('reopening closed branch head %d\n') % r)
1394
1394
1395 if ui.debugflag:
1395 if ui.debugflag:
1396 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1396 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1397 elif ui.verbose:
1397 elif ui.verbose:
1398 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1398 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1399
1399
1400 @command('copy|cp',
1400 @command('copy|cp',
1401 [('A', 'after', None, _('record a copy that has already occurred')),
1401 [('A', 'after', None, _('record a copy that has already occurred')),
1402 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1402 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1403 ] + walkopts + dryrunopts,
1403 ] + walkopts + dryrunopts,
1404 _('[OPTION]... [SOURCE]... DEST'))
1404 _('[OPTION]... [SOURCE]... DEST'))
1405 def copy(ui, repo, *pats, **opts):
1405 def copy(ui, repo, *pats, **opts):
1406 """mark files as copied for the next commit
1406 """mark files as copied for the next commit
1407
1407
1408 Mark dest as having copies of source files. If dest is a
1408 Mark dest as having copies of source files. If dest is a
1409 directory, copies are put in that directory. If dest is a file,
1409 directory, copies are put in that directory. If dest is a file,
1410 the source must be a single file.
1410 the source must be a single file.
1411
1411
1412 By default, this command copies the contents of files as they
1412 By default, this command copies the contents of files as they
1413 exist in the working directory. If invoked with -A/--after, the
1413 exist in the working directory. If invoked with -A/--after, the
1414 operation is recorded, but no copying is performed.
1414 operation is recorded, but no copying is performed.
1415
1415
1416 This command takes effect with the next commit. To undo a copy
1416 This command takes effect with the next commit. To undo a copy
1417 before that, see :hg:`revert`.
1417 before that, see :hg:`revert`.
1418
1418
1419 Returns 0 on success, 1 if errors are encountered.
1419 Returns 0 on success, 1 if errors are encountered.
1420 """
1420 """
1421 wlock = repo.wlock(False)
1421 wlock = repo.wlock(False)
1422 try:
1422 try:
1423 return cmdutil.copy(ui, repo, pats, opts)
1423 return cmdutil.copy(ui, repo, pats, opts)
1424 finally:
1424 finally:
1425 wlock.release()
1425 wlock.release()
1426
1426
1427 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1427 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1428 def debugancestor(ui, repo, *args):
1428 def debugancestor(ui, repo, *args):
1429 """find the ancestor revision of two revisions in a given index"""
1429 """find the ancestor revision of two revisions in a given index"""
1430 if len(args) == 3:
1430 if len(args) == 3:
1431 index, rev1, rev2 = args
1431 index, rev1, rev2 = args
1432 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1432 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1433 lookup = r.lookup
1433 lookup = r.lookup
1434 elif len(args) == 2:
1434 elif len(args) == 2:
1435 if not repo:
1435 if not repo:
1436 raise util.Abort(_("there is no Mercurial repository here "
1436 raise util.Abort(_("there is no Mercurial repository here "
1437 "(.hg not found)"))
1437 "(.hg not found)"))
1438 rev1, rev2 = args
1438 rev1, rev2 = args
1439 r = repo.changelog
1439 r = repo.changelog
1440 lookup = repo.lookup
1440 lookup = repo.lookup
1441 else:
1441 else:
1442 raise util.Abort(_('either two or three arguments required'))
1442 raise util.Abort(_('either two or three arguments required'))
1443 a = r.ancestor(lookup(rev1), lookup(rev2))
1443 a = r.ancestor(lookup(rev1), lookup(rev2))
1444 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1444 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1445
1445
1446 @command('debugbuilddag',
1446 @command('debugbuilddag',
1447 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1447 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1448 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1448 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1449 ('n', 'new-file', None, _('add new file at each rev'))],
1449 ('n', 'new-file', None, _('add new file at each rev'))],
1450 _('[OPTION]... [TEXT]'))
1450 _('[OPTION]... [TEXT]'))
1451 def debugbuilddag(ui, repo, text=None,
1451 def debugbuilddag(ui, repo, text=None,
1452 mergeable_file=False,
1452 mergeable_file=False,
1453 overwritten_file=False,
1453 overwritten_file=False,
1454 new_file=False):
1454 new_file=False):
1455 """builds a repo with a given DAG from scratch in the current empty repo
1455 """builds a repo with a given DAG from scratch in the current empty repo
1456
1456
1457 The description of the DAG is read from stdin if not given on the
1457 The description of the DAG is read from stdin if not given on the
1458 command line.
1458 command line.
1459
1459
1460 Elements:
1460 Elements:
1461
1461
1462 - "+n" is a linear run of n nodes based on the current default parent
1462 - "+n" is a linear run of n nodes based on the current default parent
1463 - "." is a single node based on the current default parent
1463 - "." is a single node based on the current default parent
1464 - "$" resets the default parent to null (implied at the start);
1464 - "$" resets the default parent to null (implied at the start);
1465 otherwise the default parent is always the last node created
1465 otherwise the default parent is always the last node created
1466 - "<p" sets the default parent to the backref p
1466 - "<p" sets the default parent to the backref p
1467 - "*p" is a fork at parent p, which is a backref
1467 - "*p" is a fork at parent p, which is a backref
1468 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1468 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1469 - "/p2" is a merge of the preceding node and p2
1469 - "/p2" is a merge of the preceding node and p2
1470 - ":tag" defines a local tag for the preceding node
1470 - ":tag" defines a local tag for the preceding node
1471 - "@branch" sets the named branch for subsequent nodes
1471 - "@branch" sets the named branch for subsequent nodes
1472 - "#...\\n" is a comment up to the end of the line
1472 - "#...\\n" is a comment up to the end of the line
1473
1473
1474 Whitespace between the above elements is ignored.
1474 Whitespace between the above elements is ignored.
1475
1475
1476 A backref is either
1476 A backref is either
1477
1477
1478 - a number n, which references the node curr-n, where curr is the current
1478 - a number n, which references the node curr-n, where curr is the current
1479 node, or
1479 node, or
1480 - the name of a local tag you placed earlier using ":tag", or
1480 - the name of a local tag you placed earlier using ":tag", or
1481 - empty to denote the default parent.
1481 - empty to denote the default parent.
1482
1482
1483 All string valued-elements are either strictly alphanumeric, or must
1483 All string valued-elements are either strictly alphanumeric, or must
1484 be enclosed in double quotes ("..."), with "\\" as escape character.
1484 be enclosed in double quotes ("..."), with "\\" as escape character.
1485 """
1485 """
1486
1486
1487 if text is None:
1487 if text is None:
1488 ui.status(_("reading DAG from stdin\n"))
1488 ui.status(_("reading DAG from stdin\n"))
1489 text = ui.fin.read()
1489 text = ui.fin.read()
1490
1490
1491 cl = repo.changelog
1491 cl = repo.changelog
1492 if len(cl) > 0:
1492 if len(cl) > 0:
1493 raise util.Abort(_('repository is not empty'))
1493 raise util.Abort(_('repository is not empty'))
1494
1494
1495 # determine number of revs in DAG
1495 # determine number of revs in DAG
1496 total = 0
1496 total = 0
1497 for type, data in dagparser.parsedag(text):
1497 for type, data in dagparser.parsedag(text):
1498 if type == 'n':
1498 if type == 'n':
1499 total += 1
1499 total += 1
1500
1500
1501 if mergeable_file:
1501 if mergeable_file:
1502 linesperrev = 2
1502 linesperrev = 2
1503 # make a file with k lines per rev
1503 # make a file with k lines per rev
1504 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1504 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1505 initialmergedlines.append("")
1505 initialmergedlines.append("")
1506
1506
1507 tags = []
1507 tags = []
1508
1508
1509 lock = tr = None
1509 lock = tr = None
1510 try:
1510 try:
1511 lock = repo.lock()
1511 lock = repo.lock()
1512 tr = repo.transaction("builddag")
1512 tr = repo.transaction("builddag")
1513
1513
1514 at = -1
1514 at = -1
1515 atbranch = 'default'
1515 atbranch = 'default'
1516 nodeids = []
1516 nodeids = []
1517 id = 0
1517 id = 0
1518 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1518 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1519 for type, data in dagparser.parsedag(text):
1519 for type, data in dagparser.parsedag(text):
1520 if type == 'n':
1520 if type == 'n':
1521 ui.note(('node %s\n' % str(data)))
1521 ui.note(('node %s\n' % str(data)))
1522 id, ps = data
1522 id, ps = data
1523
1523
1524 files = []
1524 files = []
1525 fctxs = {}
1525 fctxs = {}
1526
1526
1527 p2 = None
1527 p2 = None
1528 if mergeable_file:
1528 if mergeable_file:
1529 fn = "mf"
1529 fn = "mf"
1530 p1 = repo[ps[0]]
1530 p1 = repo[ps[0]]
1531 if len(ps) > 1:
1531 if len(ps) > 1:
1532 p2 = repo[ps[1]]
1532 p2 = repo[ps[1]]
1533 pa = p1.ancestor(p2)
1533 pa = p1.ancestor(p2)
1534 base, local, other = [x[fn].data() for x in (pa, p1,
1534 base, local, other = [x[fn].data() for x in (pa, p1,
1535 p2)]
1535 p2)]
1536 m3 = simplemerge.Merge3Text(base, local, other)
1536 m3 = simplemerge.Merge3Text(base, local, other)
1537 ml = [l.strip() for l in m3.merge_lines()]
1537 ml = [l.strip() for l in m3.merge_lines()]
1538 ml.append("")
1538 ml.append("")
1539 elif at > 0:
1539 elif at > 0:
1540 ml = p1[fn].data().split("\n")
1540 ml = p1[fn].data().split("\n")
1541 else:
1541 else:
1542 ml = initialmergedlines
1542 ml = initialmergedlines
1543 ml[id * linesperrev] += " r%i" % id
1543 ml[id * linesperrev] += " r%i" % id
1544 mergedtext = "\n".join(ml)
1544 mergedtext = "\n".join(ml)
1545 files.append(fn)
1545 files.append(fn)
1546 fctxs[fn] = context.memfilectx(fn, mergedtext)
1546 fctxs[fn] = context.memfilectx(fn, mergedtext)
1547
1547
1548 if overwritten_file:
1548 if overwritten_file:
1549 fn = "of"
1549 fn = "of"
1550 files.append(fn)
1550 files.append(fn)
1551 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1551 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1552
1552
1553 if new_file:
1553 if new_file:
1554 fn = "nf%i" % id
1554 fn = "nf%i" % id
1555 files.append(fn)
1555 files.append(fn)
1556 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1556 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1557 if len(ps) > 1:
1557 if len(ps) > 1:
1558 if not p2:
1558 if not p2:
1559 p2 = repo[ps[1]]
1559 p2 = repo[ps[1]]
1560 for fn in p2:
1560 for fn in p2:
1561 if fn.startswith("nf"):
1561 if fn.startswith("nf"):
1562 files.append(fn)
1562 files.append(fn)
1563 fctxs[fn] = p2[fn]
1563 fctxs[fn] = p2[fn]
1564
1564
1565 def fctxfn(repo, cx, path):
1565 def fctxfn(repo, cx, path):
1566 return fctxs.get(path)
1566 return fctxs.get(path)
1567
1567
1568 if len(ps) == 0 or ps[0] < 0:
1568 if len(ps) == 0 or ps[0] < 0:
1569 pars = [None, None]
1569 pars = [None, None]
1570 elif len(ps) == 1:
1570 elif len(ps) == 1:
1571 pars = [nodeids[ps[0]], None]
1571 pars = [nodeids[ps[0]], None]
1572 else:
1572 else:
1573 pars = [nodeids[p] for p in ps]
1573 pars = [nodeids[p] for p in ps]
1574 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1574 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1575 date=(id, 0),
1575 date=(id, 0),
1576 user="debugbuilddag",
1576 user="debugbuilddag",
1577 extra={'branch': atbranch})
1577 extra={'branch': atbranch})
1578 nodeid = repo.commitctx(cx)
1578 nodeid = repo.commitctx(cx)
1579 nodeids.append(nodeid)
1579 nodeids.append(nodeid)
1580 at = id
1580 at = id
1581 elif type == 'l':
1581 elif type == 'l':
1582 id, name = data
1582 id, name = data
1583 ui.note(('tag %s\n' % name))
1583 ui.note(('tag %s\n' % name))
1584 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1584 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1585 elif type == 'a':
1585 elif type == 'a':
1586 ui.note(('branch %s\n' % data))
1586 ui.note(('branch %s\n' % data))
1587 atbranch = data
1587 atbranch = data
1588 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1588 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1589 tr.close()
1589 tr.close()
1590
1590
1591 if tags:
1591 if tags:
1592 repo.opener.write("localtags", "".join(tags))
1592 repo.opener.write("localtags", "".join(tags))
1593 finally:
1593 finally:
1594 ui.progress(_('building'), None)
1594 ui.progress(_('building'), None)
1595 release(tr, lock)
1595 release(tr, lock)
1596
1596
1597 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1597 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1598 def debugbundle(ui, bundlepath, all=None, **opts):
1598 def debugbundle(ui, bundlepath, all=None, **opts):
1599 """lists the contents of a bundle"""
1599 """lists the contents of a bundle"""
1600 f = hg.openpath(ui, bundlepath)
1600 f = hg.openpath(ui, bundlepath)
1601 try:
1601 try:
1602 gen = changegroup.readbundle(f, bundlepath)
1602 gen = changegroup.readbundle(f, bundlepath)
1603 if all:
1603 if all:
1604 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1604 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1605
1605
1606 def showchunks(named):
1606 def showchunks(named):
1607 ui.write("\n%s\n" % named)
1607 ui.write("\n%s\n" % named)
1608 chain = None
1608 chain = None
1609 while True:
1609 while True:
1610 chunkdata = gen.deltachunk(chain)
1610 chunkdata = gen.deltachunk(chain)
1611 if not chunkdata:
1611 if not chunkdata:
1612 break
1612 break
1613 node = chunkdata['node']
1613 node = chunkdata['node']
1614 p1 = chunkdata['p1']
1614 p1 = chunkdata['p1']
1615 p2 = chunkdata['p2']
1615 p2 = chunkdata['p2']
1616 cs = chunkdata['cs']
1616 cs = chunkdata['cs']
1617 deltabase = chunkdata['deltabase']
1617 deltabase = chunkdata['deltabase']
1618 delta = chunkdata['delta']
1618 delta = chunkdata['delta']
1619 ui.write("%s %s %s %s %s %s\n" %
1619 ui.write("%s %s %s %s %s %s\n" %
1620 (hex(node), hex(p1), hex(p2),
1620 (hex(node), hex(p1), hex(p2),
1621 hex(cs), hex(deltabase), len(delta)))
1621 hex(cs), hex(deltabase), len(delta)))
1622 chain = node
1622 chain = node
1623
1623
1624 chunkdata = gen.changelogheader()
1624 chunkdata = gen.changelogheader()
1625 showchunks("changelog")
1625 showchunks("changelog")
1626 chunkdata = gen.manifestheader()
1626 chunkdata = gen.manifestheader()
1627 showchunks("manifest")
1627 showchunks("manifest")
1628 while True:
1628 while True:
1629 chunkdata = gen.filelogheader()
1629 chunkdata = gen.filelogheader()
1630 if not chunkdata:
1630 if not chunkdata:
1631 break
1631 break
1632 fname = chunkdata['filename']
1632 fname = chunkdata['filename']
1633 showchunks(fname)
1633 showchunks(fname)
1634 else:
1634 else:
1635 chunkdata = gen.changelogheader()
1635 chunkdata = gen.changelogheader()
1636 chain = None
1636 chain = None
1637 while True:
1637 while True:
1638 chunkdata = gen.deltachunk(chain)
1638 chunkdata = gen.deltachunk(chain)
1639 if not chunkdata:
1639 if not chunkdata:
1640 break
1640 break
1641 node = chunkdata['node']
1641 node = chunkdata['node']
1642 ui.write("%s\n" % hex(node))
1642 ui.write("%s\n" % hex(node))
1643 chain = node
1643 chain = node
1644 finally:
1644 finally:
1645 f.close()
1645 f.close()
1646
1646
1647 @command('debugcheckstate', [], '')
1647 @command('debugcheckstate', [], '')
1648 def debugcheckstate(ui, repo):
1648 def debugcheckstate(ui, repo):
1649 """validate the correctness of the current dirstate"""
1649 """validate the correctness of the current dirstate"""
1650 parent1, parent2 = repo.dirstate.parents()
1650 parent1, parent2 = repo.dirstate.parents()
1651 m1 = repo[parent1].manifest()
1651 m1 = repo[parent1].manifest()
1652 m2 = repo[parent2].manifest()
1652 m2 = repo[parent2].manifest()
1653 errors = 0
1653 errors = 0
1654 for f in repo.dirstate:
1654 for f in repo.dirstate:
1655 state = repo.dirstate[f]
1655 state = repo.dirstate[f]
1656 if state in "nr" and f not in m1:
1656 if state in "nr" and f not in m1:
1657 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1657 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1658 errors += 1
1658 errors += 1
1659 if state in "a" and f in m1:
1659 if state in "a" and f in m1:
1660 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1660 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1661 errors += 1
1661 errors += 1
1662 if state in "m" and f not in m1 and f not in m2:
1662 if state in "m" and f not in m1 and f not in m2:
1663 ui.warn(_("%s in state %s, but not in either manifest\n") %
1663 ui.warn(_("%s in state %s, but not in either manifest\n") %
1664 (f, state))
1664 (f, state))
1665 errors += 1
1665 errors += 1
1666 for f in m1:
1666 for f in m1:
1667 state = repo.dirstate[f]
1667 state = repo.dirstate[f]
1668 if state not in "nrm":
1668 if state not in "nrm":
1669 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1669 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1670 errors += 1
1670 errors += 1
1671 if errors:
1671 if errors:
1672 error = _(".hg/dirstate inconsistent with current parent's manifest")
1672 error = _(".hg/dirstate inconsistent with current parent's manifest")
1673 raise util.Abort(error)
1673 raise util.Abort(error)
1674
1674
1675 @command('debugcommands', [], _('[COMMAND]'))
1675 @command('debugcommands', [], _('[COMMAND]'))
1676 def debugcommands(ui, cmd='', *args):
1676 def debugcommands(ui, cmd='', *args):
1677 """list all available commands and options"""
1677 """list all available commands and options"""
1678 for cmd, vals in sorted(table.iteritems()):
1678 for cmd, vals in sorted(table.iteritems()):
1679 cmd = cmd.split('|')[0].strip('^')
1679 cmd = cmd.split('|')[0].strip('^')
1680 opts = ', '.join([i[1] for i in vals[1]])
1680 opts = ', '.join([i[1] for i in vals[1]])
1681 ui.write('%s: %s\n' % (cmd, opts))
1681 ui.write('%s: %s\n' % (cmd, opts))
1682
1682
1683 @command('debugcomplete',
1683 @command('debugcomplete',
1684 [('o', 'options', None, _('show the command options'))],
1684 [('o', 'options', None, _('show the command options'))],
1685 _('[-o] CMD'))
1685 _('[-o] CMD'))
1686 def debugcomplete(ui, cmd='', **opts):
1686 def debugcomplete(ui, cmd='', **opts):
1687 """returns the completion list associated with the given command"""
1687 """returns the completion list associated with the given command"""
1688
1688
1689 if opts.get('options'):
1689 if opts.get('options'):
1690 options = []
1690 options = []
1691 otables = [globalopts]
1691 otables = [globalopts]
1692 if cmd:
1692 if cmd:
1693 aliases, entry = cmdutil.findcmd(cmd, table, False)
1693 aliases, entry = cmdutil.findcmd(cmd, table, False)
1694 otables.append(entry[1])
1694 otables.append(entry[1])
1695 for t in otables:
1695 for t in otables:
1696 for o in t:
1696 for o in t:
1697 if "(DEPRECATED)" in o[3]:
1697 if "(DEPRECATED)" in o[3]:
1698 continue
1698 continue
1699 if o[0]:
1699 if o[0]:
1700 options.append('-%s' % o[0])
1700 options.append('-%s' % o[0])
1701 options.append('--%s' % o[1])
1701 options.append('--%s' % o[1])
1702 ui.write("%s\n" % "\n".join(options))
1702 ui.write("%s\n" % "\n".join(options))
1703 return
1703 return
1704
1704
1705 cmdlist = cmdutil.findpossible(cmd, table)
1705 cmdlist = cmdutil.findpossible(cmd, table)
1706 if ui.verbose:
1706 if ui.verbose:
1707 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1707 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1708 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1708 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1709
1709
1710 @command('debugdag',
1710 @command('debugdag',
1711 [('t', 'tags', None, _('use tags as labels')),
1711 [('t', 'tags', None, _('use tags as labels')),
1712 ('b', 'branches', None, _('annotate with branch names')),
1712 ('b', 'branches', None, _('annotate with branch names')),
1713 ('', 'dots', None, _('use dots for runs')),
1713 ('', 'dots', None, _('use dots for runs')),
1714 ('s', 'spaces', None, _('separate elements by spaces'))],
1714 ('s', 'spaces', None, _('separate elements by spaces'))],
1715 _('[OPTION]... [FILE [REV]...]'))
1715 _('[OPTION]... [FILE [REV]...]'))
1716 def debugdag(ui, repo, file_=None, *revs, **opts):
1716 def debugdag(ui, repo, file_=None, *revs, **opts):
1717 """format the changelog or an index DAG as a concise textual description
1717 """format the changelog or an index DAG as a concise textual description
1718
1718
1719 If you pass a revlog index, the revlog's DAG is emitted. If you list
1719 If you pass a revlog index, the revlog's DAG is emitted. If you list
1720 revision numbers, they get labeled in the output as rN.
1720 revision numbers, they get labeled in the output as rN.
1721
1721
1722 Otherwise, the changelog DAG of the current repo is emitted.
1722 Otherwise, the changelog DAG of the current repo is emitted.
1723 """
1723 """
1724 spaces = opts.get('spaces')
1724 spaces = opts.get('spaces')
1725 dots = opts.get('dots')
1725 dots = opts.get('dots')
1726 if file_:
1726 if file_:
1727 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1727 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1728 revs = set((int(r) for r in revs))
1728 revs = set((int(r) for r in revs))
1729 def events():
1729 def events():
1730 for r in rlog:
1730 for r in rlog:
1731 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1731 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1732 if p != -1)))
1732 if p != -1)))
1733 if r in revs:
1733 if r in revs:
1734 yield 'l', (r, "r%i" % r)
1734 yield 'l', (r, "r%i" % r)
1735 elif repo:
1735 elif repo:
1736 cl = repo.changelog
1736 cl = repo.changelog
1737 tags = opts.get('tags')
1737 tags = opts.get('tags')
1738 branches = opts.get('branches')
1738 branches = opts.get('branches')
1739 if tags:
1739 if tags:
1740 labels = {}
1740 labels = {}
1741 for l, n in repo.tags().items():
1741 for l, n in repo.tags().items():
1742 labels.setdefault(cl.rev(n), []).append(l)
1742 labels.setdefault(cl.rev(n), []).append(l)
1743 def events():
1743 def events():
1744 b = "default"
1744 b = "default"
1745 for r in cl:
1745 for r in cl:
1746 if branches:
1746 if branches:
1747 newb = cl.read(cl.node(r))[5]['branch']
1747 newb = cl.read(cl.node(r))[5]['branch']
1748 if newb != b:
1748 if newb != b:
1749 yield 'a', newb
1749 yield 'a', newb
1750 b = newb
1750 b = newb
1751 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1751 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1752 if p != -1)))
1752 if p != -1)))
1753 if tags:
1753 if tags:
1754 ls = labels.get(r)
1754 ls = labels.get(r)
1755 if ls:
1755 if ls:
1756 for l in ls:
1756 for l in ls:
1757 yield 'l', (r, l)
1757 yield 'l', (r, l)
1758 else:
1758 else:
1759 raise util.Abort(_('need repo for changelog dag'))
1759 raise util.Abort(_('need repo for changelog dag'))
1760
1760
1761 for line in dagparser.dagtextlines(events(),
1761 for line in dagparser.dagtextlines(events(),
1762 addspaces=spaces,
1762 addspaces=spaces,
1763 wraplabels=True,
1763 wraplabels=True,
1764 wrapannotations=True,
1764 wrapannotations=True,
1765 wrapnonlinear=dots,
1765 wrapnonlinear=dots,
1766 usedots=dots,
1766 usedots=dots,
1767 maxlinewidth=70):
1767 maxlinewidth=70):
1768 ui.write(line)
1768 ui.write(line)
1769 ui.write("\n")
1769 ui.write("\n")
1770
1770
1771 @command('debugdata',
1771 @command('debugdata',
1772 [('c', 'changelog', False, _('open changelog')),
1772 [('c', 'changelog', False, _('open changelog')),
1773 ('m', 'manifest', False, _('open manifest'))],
1773 ('m', 'manifest', False, _('open manifest'))],
1774 _('-c|-m|FILE REV'))
1774 _('-c|-m|FILE REV'))
1775 def debugdata(ui, repo, file_, rev = None, **opts):
1775 def debugdata(ui, repo, file_, rev = None, **opts):
1776 """dump the contents of a data file revision"""
1776 """dump the contents of a data file revision"""
1777 if opts.get('changelog') or opts.get('manifest'):
1777 if opts.get('changelog') or opts.get('manifest'):
1778 file_, rev = None, file_
1778 file_, rev = None, file_
1779 elif rev is None:
1779 elif rev is None:
1780 raise error.CommandError('debugdata', _('invalid arguments'))
1780 raise error.CommandError('debugdata', _('invalid arguments'))
1781 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1781 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1782 try:
1782 try:
1783 ui.write(r.revision(r.lookup(rev)))
1783 ui.write(r.revision(r.lookup(rev)))
1784 except KeyError:
1784 except KeyError:
1785 raise util.Abort(_('invalid revision identifier %s') % rev)
1785 raise util.Abort(_('invalid revision identifier %s') % rev)
1786
1786
1787 @command('debugdate',
1787 @command('debugdate',
1788 [('e', 'extended', None, _('try extended date formats'))],
1788 [('e', 'extended', None, _('try extended date formats'))],
1789 _('[-e] DATE [RANGE]'))
1789 _('[-e] DATE [RANGE]'))
1790 def debugdate(ui, date, range=None, **opts):
1790 def debugdate(ui, date, range=None, **opts):
1791 """parse and display a date"""
1791 """parse and display a date"""
1792 if opts["extended"]:
1792 if opts["extended"]:
1793 d = util.parsedate(date, util.extendeddateformats)
1793 d = util.parsedate(date, util.extendeddateformats)
1794 else:
1794 else:
1795 d = util.parsedate(date)
1795 d = util.parsedate(date)
1796 ui.write(("internal: %s %s\n") % d)
1796 ui.write(("internal: %s %s\n") % d)
1797 ui.write(("standard: %s\n") % util.datestr(d))
1797 ui.write(("standard: %s\n") % util.datestr(d))
1798 if range:
1798 if range:
1799 m = util.matchdate(range)
1799 m = util.matchdate(range)
1800 ui.write(("match: %s\n") % m(d[0]))
1800 ui.write(("match: %s\n") % m(d[0]))
1801
1801
1802 @command('debugdiscovery',
1802 @command('debugdiscovery',
1803 [('', 'old', None, _('use old-style discovery')),
1803 [('', 'old', None, _('use old-style discovery')),
1804 ('', 'nonheads', None,
1804 ('', 'nonheads', None,
1805 _('use old-style discovery with non-heads included')),
1805 _('use old-style discovery with non-heads included')),
1806 ] + remoteopts,
1806 ] + remoteopts,
1807 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1807 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1808 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1808 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1809 """runs the changeset discovery protocol in isolation"""
1809 """runs the changeset discovery protocol in isolation"""
1810 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1810 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1811 opts.get('branch'))
1811 opts.get('branch'))
1812 remote = hg.peer(repo, opts, remoteurl)
1812 remote = hg.peer(repo, opts, remoteurl)
1813 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1813 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1814
1814
1815 # make sure tests are repeatable
1815 # make sure tests are repeatable
1816 random.seed(12323)
1816 random.seed(12323)
1817
1817
1818 def doit(localheads, remoteheads, remote=remote):
1818 def doit(localheads, remoteheads, remote=remote):
1819 if opts.get('old'):
1819 if opts.get('old'):
1820 if localheads:
1820 if localheads:
1821 raise util.Abort('cannot use localheads with old style '
1821 raise util.Abort('cannot use localheads with old style '
1822 'discovery')
1822 'discovery')
1823 if not util.safehasattr(remote, 'branches'):
1823 if not util.safehasattr(remote, 'branches'):
1824 # enable in-client legacy support
1824 # enable in-client legacy support
1825 remote = localrepo.locallegacypeer(remote.local())
1825 remote = localrepo.locallegacypeer(remote.local())
1826 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1826 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1827 force=True)
1827 force=True)
1828 common = set(common)
1828 common = set(common)
1829 if not opts.get('nonheads'):
1829 if not opts.get('nonheads'):
1830 ui.write(("unpruned common: %s\n") %
1830 ui.write(("unpruned common: %s\n") %
1831 " ".join(sorted(short(n) for n in common)))
1831 " ".join(sorted(short(n) for n in common)))
1832 dag = dagutil.revlogdag(repo.changelog)
1832 dag = dagutil.revlogdag(repo.changelog)
1833 all = dag.ancestorset(dag.internalizeall(common))
1833 all = dag.ancestorset(dag.internalizeall(common))
1834 common = dag.externalizeall(dag.headsetofconnecteds(all))
1834 common = dag.externalizeall(dag.headsetofconnecteds(all))
1835 else:
1835 else:
1836 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1836 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1837 common = set(common)
1837 common = set(common)
1838 rheads = set(hds)
1838 rheads = set(hds)
1839 lheads = set(repo.heads())
1839 lheads = set(repo.heads())
1840 ui.write(("common heads: %s\n") %
1840 ui.write(("common heads: %s\n") %
1841 " ".join(sorted(short(n) for n in common)))
1841 " ".join(sorted(short(n) for n in common)))
1842 if lheads <= common:
1842 if lheads <= common:
1843 ui.write(("local is subset\n"))
1843 ui.write(("local is subset\n"))
1844 elif rheads <= common:
1844 elif rheads <= common:
1845 ui.write(("remote is subset\n"))
1845 ui.write(("remote is subset\n"))
1846
1846
1847 serverlogs = opts.get('serverlog')
1847 serverlogs = opts.get('serverlog')
1848 if serverlogs:
1848 if serverlogs:
1849 for filename in serverlogs:
1849 for filename in serverlogs:
1850 logfile = open(filename, 'r')
1850 logfile = open(filename, 'r')
1851 try:
1851 try:
1852 line = logfile.readline()
1852 line = logfile.readline()
1853 while line:
1853 while line:
1854 parts = line.strip().split(';')
1854 parts = line.strip().split(';')
1855 op = parts[1]
1855 op = parts[1]
1856 if op == 'cg':
1856 if op == 'cg':
1857 pass
1857 pass
1858 elif op == 'cgss':
1858 elif op == 'cgss':
1859 doit(parts[2].split(' '), parts[3].split(' '))
1859 doit(parts[2].split(' '), parts[3].split(' '))
1860 elif op == 'unb':
1860 elif op == 'unb':
1861 doit(parts[3].split(' '), parts[2].split(' '))
1861 doit(parts[3].split(' '), parts[2].split(' '))
1862 line = logfile.readline()
1862 line = logfile.readline()
1863 finally:
1863 finally:
1864 logfile.close()
1864 logfile.close()
1865
1865
1866 else:
1866 else:
1867 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1867 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1868 opts.get('remote_head'))
1868 opts.get('remote_head'))
1869 localrevs = opts.get('local_head')
1869 localrevs = opts.get('local_head')
1870 doit(localrevs, remoterevs)
1870 doit(localrevs, remoterevs)
1871
1871
1872 @command('debugfileset',
1872 @command('debugfileset',
1873 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1873 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1874 _('[-r REV] FILESPEC'))
1874 _('[-r REV] FILESPEC'))
1875 def debugfileset(ui, repo, expr, **opts):
1875 def debugfileset(ui, repo, expr, **opts):
1876 '''parse and apply a fileset specification'''
1876 '''parse and apply a fileset specification'''
1877 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1877 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1878 if ui.verbose:
1878 if ui.verbose:
1879 tree = fileset.parse(expr)[0]
1879 tree = fileset.parse(expr)[0]
1880 ui.note(tree, "\n")
1880 ui.note(tree, "\n")
1881
1881
1882 for f in fileset.getfileset(ctx, expr):
1882 for f in fileset.getfileset(ctx, expr):
1883 ui.write("%s\n" % f)
1883 ui.write("%s\n" % f)
1884
1884
1885 @command('debugfsinfo', [], _('[PATH]'))
1885 @command('debugfsinfo', [], _('[PATH]'))
1886 def debugfsinfo(ui, path = "."):
1886 def debugfsinfo(ui, path = "."):
1887 """show information detected about current filesystem"""
1887 """show information detected about current filesystem"""
1888 util.writefile('.debugfsinfo', '')
1888 util.writefile('.debugfsinfo', '')
1889 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1889 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1890 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1890 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1891 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1891 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1892 and 'yes' or 'no'))
1892 and 'yes' or 'no'))
1893 os.unlink('.debugfsinfo')
1893 os.unlink('.debugfsinfo')
1894
1894
1895 @command('debuggetbundle',
1895 @command('debuggetbundle',
1896 [('H', 'head', [], _('id of head node'), _('ID')),
1896 [('H', 'head', [], _('id of head node'), _('ID')),
1897 ('C', 'common', [], _('id of common node'), _('ID')),
1897 ('C', 'common', [], _('id of common node'), _('ID')),
1898 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1898 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1899 _('REPO FILE [-H|-C ID]...'))
1899 _('REPO FILE [-H|-C ID]...'))
1900 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1900 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1901 """retrieves a bundle from a repo
1901 """retrieves a bundle from a repo
1902
1902
1903 Every ID must be a full-length hex node id string. Saves the bundle to the
1903 Every ID must be a full-length hex node id string. Saves the bundle to the
1904 given file.
1904 given file.
1905 """
1905 """
1906 repo = hg.peer(ui, opts, repopath)
1906 repo = hg.peer(ui, opts, repopath)
1907 if not repo.capable('getbundle'):
1907 if not repo.capable('getbundle'):
1908 raise util.Abort("getbundle() not supported by target repository")
1908 raise util.Abort("getbundle() not supported by target repository")
1909 args = {}
1909 args = {}
1910 if common:
1910 if common:
1911 args['common'] = [bin(s) for s in common]
1911 args['common'] = [bin(s) for s in common]
1912 if head:
1912 if head:
1913 args['heads'] = [bin(s) for s in head]
1913 args['heads'] = [bin(s) for s in head]
1914 bundle = repo.getbundle('debug', **args)
1914 bundle = repo.getbundle('debug', **args)
1915
1915
1916 bundletype = opts.get('type', 'bzip2').lower()
1916 bundletype = opts.get('type', 'bzip2').lower()
1917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1918 bundletype = btypes.get(bundletype)
1918 bundletype = btypes.get(bundletype)
1919 if bundletype not in changegroup.bundletypes:
1919 if bundletype not in changegroup.bundletypes:
1920 raise util.Abort(_('unknown bundle type specified with --type'))
1920 raise util.Abort(_('unknown bundle type specified with --type'))
1921 changegroup.writebundle(bundle, bundlepath, bundletype)
1921 changegroup.writebundle(bundle, bundlepath, bundletype)
1922
1922
1923 @command('debugignore', [], '')
1923 @command('debugignore', [], '')
1924 def debugignore(ui, repo, *values, **opts):
1924 def debugignore(ui, repo, *values, **opts):
1925 """display the combined ignore pattern"""
1925 """display the combined ignore pattern"""
1926 ignore = repo.dirstate._ignore
1926 ignore = repo.dirstate._ignore
1927 includepat = getattr(ignore, 'includepat', None)
1927 includepat = getattr(ignore, 'includepat', None)
1928 if includepat is not None:
1928 if includepat is not None:
1929 ui.write("%s\n" % includepat)
1929 ui.write("%s\n" % includepat)
1930 else:
1930 else:
1931 raise util.Abort(_("no ignore patterns found"))
1931 raise util.Abort(_("no ignore patterns found"))
1932
1932
1933 @command('debugindex',
1933 @command('debugindex',
1934 [('c', 'changelog', False, _('open changelog')),
1934 [('c', 'changelog', False, _('open changelog')),
1935 ('m', 'manifest', False, _('open manifest')),
1935 ('m', 'manifest', False, _('open manifest')),
1936 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1936 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1937 _('[-f FORMAT] -c|-m|FILE'))
1937 _('[-f FORMAT] -c|-m|FILE'))
1938 def debugindex(ui, repo, file_ = None, **opts):
1938 def debugindex(ui, repo, file_ = None, **opts):
1939 """dump the contents of an index file"""
1939 """dump the contents of an index file"""
1940 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1940 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1941 format = opts.get('format', 0)
1941 format = opts.get('format', 0)
1942 if format not in (0, 1):
1942 if format not in (0, 1):
1943 raise util.Abort(_("unknown format %d") % format)
1943 raise util.Abort(_("unknown format %d") % format)
1944
1944
1945 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1945 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1946 if generaldelta:
1946 if generaldelta:
1947 basehdr = ' delta'
1947 basehdr = ' delta'
1948 else:
1948 else:
1949 basehdr = ' base'
1949 basehdr = ' base'
1950
1950
1951 if format == 0:
1951 if format == 0:
1952 ui.write(" rev offset length " + basehdr + " linkrev"
1952 ui.write(" rev offset length " + basehdr + " linkrev"
1953 " nodeid p1 p2\n")
1953 " nodeid p1 p2\n")
1954 elif format == 1:
1954 elif format == 1:
1955 ui.write(" rev flag offset length"
1955 ui.write(" rev flag offset length"
1956 " size " + basehdr + " link p1 p2"
1956 " size " + basehdr + " link p1 p2"
1957 " nodeid\n")
1957 " nodeid\n")
1958
1958
1959 for i in r:
1959 for i in r:
1960 node = r.node(i)
1960 node = r.node(i)
1961 if generaldelta:
1961 if generaldelta:
1962 base = r.deltaparent(i)
1962 base = r.deltaparent(i)
1963 else:
1963 else:
1964 base = r.chainbase(i)
1964 base = r.chainbase(i)
1965 if format == 0:
1965 if format == 0:
1966 try:
1966 try:
1967 pp = r.parents(node)
1967 pp = r.parents(node)
1968 except Exception:
1968 except Exception:
1969 pp = [nullid, nullid]
1969 pp = [nullid, nullid]
1970 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1970 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1971 i, r.start(i), r.length(i), base, r.linkrev(i),
1971 i, r.start(i), r.length(i), base, r.linkrev(i),
1972 short(node), short(pp[0]), short(pp[1])))
1972 short(node), short(pp[0]), short(pp[1])))
1973 elif format == 1:
1973 elif format == 1:
1974 pr = r.parentrevs(i)
1974 pr = r.parentrevs(i)
1975 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1975 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1976 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1976 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1977 base, r.linkrev(i), pr[0], pr[1], short(node)))
1977 base, r.linkrev(i), pr[0], pr[1], short(node)))
1978
1978
1979 @command('debugindexdot', [], _('FILE'))
1979 @command('debugindexdot', [], _('FILE'))
1980 def debugindexdot(ui, repo, file_):
1980 def debugindexdot(ui, repo, file_):
1981 """dump an index DAG as a graphviz dot file"""
1981 """dump an index DAG as a graphviz dot file"""
1982 r = None
1982 r = None
1983 if repo:
1983 if repo:
1984 filelog = repo.file(file_)
1984 filelog = repo.file(file_)
1985 if len(filelog):
1985 if len(filelog):
1986 r = filelog
1986 r = filelog
1987 if not r:
1987 if not r:
1988 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1988 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1989 ui.write(("digraph G {\n"))
1989 ui.write(("digraph G {\n"))
1990 for i in r:
1990 for i in r:
1991 node = r.node(i)
1991 node = r.node(i)
1992 pp = r.parents(node)
1992 pp = r.parents(node)
1993 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1993 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1994 if pp[1] != nullid:
1994 if pp[1] != nullid:
1995 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1995 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1996 ui.write("}\n")
1996 ui.write("}\n")
1997
1997
1998 @command('debuginstall', [], '')
1998 @command('debuginstall', [], '')
1999 def debuginstall(ui):
1999 def debuginstall(ui):
2000 '''test Mercurial installation
2000 '''test Mercurial installation
2001
2001
2002 Returns 0 on success.
2002 Returns 0 on success.
2003 '''
2003 '''
2004
2004
2005 def writetemp(contents):
2005 def writetemp(contents):
2006 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2006 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2007 f = os.fdopen(fd, "wb")
2007 f = os.fdopen(fd, "wb")
2008 f.write(contents)
2008 f.write(contents)
2009 f.close()
2009 f.close()
2010 return name
2010 return name
2011
2011
2012 problems = 0
2012 problems = 0
2013
2013
2014 # encoding
2014 # encoding
2015 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2015 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2016 try:
2016 try:
2017 encoding.fromlocal("test")
2017 encoding.fromlocal("test")
2018 except util.Abort, inst:
2018 except util.Abort, inst:
2019 ui.write(" %s\n" % inst)
2019 ui.write(" %s\n" % inst)
2020 ui.write(_(" (check that your locale is properly set)\n"))
2020 ui.write(_(" (check that your locale is properly set)\n"))
2021 problems += 1
2021 problems += 1
2022
2022
2023 # Python lib
2023 # Python lib
2024 ui.status(_("checking Python lib (%s)...\n")
2024 ui.status(_("checking Python lib (%s)...\n")
2025 % os.path.dirname(os.__file__))
2025 % os.path.dirname(os.__file__))
2026
2026
2027 # compiled modules
2027 # compiled modules
2028 ui.status(_("checking installed modules (%s)...\n")
2028 ui.status(_("checking installed modules (%s)...\n")
2029 % os.path.dirname(__file__))
2029 % os.path.dirname(__file__))
2030 try:
2030 try:
2031 import bdiff, mpatch, base85, osutil
2031 import bdiff, mpatch, base85, osutil
2032 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2032 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2033 except Exception, inst:
2033 except Exception, inst:
2034 ui.write(" %s\n" % inst)
2034 ui.write(" %s\n" % inst)
2035 ui.write(_(" One or more extensions could not be found"))
2035 ui.write(_(" One or more extensions could not be found"))
2036 ui.write(_(" (check that you compiled the extensions)\n"))
2036 ui.write(_(" (check that you compiled the extensions)\n"))
2037 problems += 1
2037 problems += 1
2038
2038
2039 # templates
2039 # templates
2040 import templater
2040 import templater
2041 p = templater.templatepath()
2041 p = templater.templatepath()
2042 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2042 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2043 try:
2043 try:
2044 templater.templater(templater.templatepath("map-cmdline.default"))
2044 templater.templater(templater.templatepath("map-cmdline.default"))
2045 except Exception, inst:
2045 except Exception, inst:
2046 ui.write(" %s\n" % inst)
2046 ui.write(" %s\n" % inst)
2047 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2047 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2048 problems += 1
2048 problems += 1
2049
2049
2050 # editor
2050 # editor
2051 ui.status(_("checking commit editor...\n"))
2051 ui.status(_("checking commit editor...\n"))
2052 editor = ui.geteditor()
2052 editor = ui.geteditor()
2053 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2053 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2054 if not cmdpath:
2054 if not cmdpath:
2055 if editor == 'vi':
2055 if editor == 'vi':
2056 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2056 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2057 ui.write(_(" (specify a commit editor in your configuration"
2057 ui.write(_(" (specify a commit editor in your configuration"
2058 " file)\n"))
2058 " file)\n"))
2059 else:
2059 else:
2060 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2060 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2061 ui.write(_(" (specify a commit editor in your configuration"
2061 ui.write(_(" (specify a commit editor in your configuration"
2062 " file)\n"))
2062 " file)\n"))
2063 problems += 1
2063 problems += 1
2064
2064
2065 # check username
2065 # check username
2066 ui.status(_("checking username...\n"))
2066 ui.status(_("checking username...\n"))
2067 try:
2067 try:
2068 ui.username()
2068 ui.username()
2069 except util.Abort, e:
2069 except util.Abort, e:
2070 ui.write(" %s\n" % e)
2070 ui.write(" %s\n" % e)
2071 ui.write(_(" (specify a username in your configuration file)\n"))
2071 ui.write(_(" (specify a username in your configuration file)\n"))
2072 problems += 1
2072 problems += 1
2073
2073
2074 if not problems:
2074 if not problems:
2075 ui.status(_("no problems detected\n"))
2075 ui.status(_("no problems detected\n"))
2076 else:
2076 else:
2077 ui.write(_("%s problems detected,"
2077 ui.write(_("%s problems detected,"
2078 " please check your install!\n") % problems)
2078 " please check your install!\n") % problems)
2079
2079
2080 return problems
2080 return problems
2081
2081
2082 @command('debugknown', [], _('REPO ID...'))
2082 @command('debugknown', [], _('REPO ID...'))
2083 def debugknown(ui, repopath, *ids, **opts):
2083 def debugknown(ui, repopath, *ids, **opts):
2084 """test whether node ids are known to a repo
2084 """test whether node ids are known to a repo
2085
2085
2086 Every ID must be a full-length hex node id string. Returns a list of 0s
2086 Every ID must be a full-length hex node id string. Returns a list of 0s
2087 and 1s indicating unknown/known.
2087 and 1s indicating unknown/known.
2088 """
2088 """
2089 repo = hg.peer(ui, opts, repopath)
2089 repo = hg.peer(ui, opts, repopath)
2090 if not repo.capable('known'):
2090 if not repo.capable('known'):
2091 raise util.Abort("known() not supported by target repository")
2091 raise util.Abort("known() not supported by target repository")
2092 flags = repo.known([bin(s) for s in ids])
2092 flags = repo.known([bin(s) for s in ids])
2093 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2093 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2094
2094
2095 @command('debugobsolete',
2095 @command('debugobsolete',
2096 [('', 'flags', 0, _('markers flag')),
2096 [('', 'flags', 0, _('markers flag')),
2097 ] + commitopts2,
2097 ] + commitopts2,
2098 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2098 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2099 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2099 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2100 """create arbitrary obsolete marker"""
2100 """create arbitrary obsolete marker"""
2101 def parsenodeid(s):
2101 def parsenodeid(s):
2102 try:
2102 try:
2103 # We do not use revsingle/revrange functions here to accept
2103 # We do not use revsingle/revrange functions here to accept
2104 # arbitrary node identifiers, possibly not present in the
2104 # arbitrary node identifiers, possibly not present in the
2105 # local repository.
2105 # local repository.
2106 n = bin(s)
2106 n = bin(s)
2107 if len(n) != len(nullid):
2107 if len(n) != len(nullid):
2108 raise TypeError()
2108 raise TypeError()
2109 return n
2109 return n
2110 except TypeError:
2110 except TypeError:
2111 raise util.Abort('changeset references must be full hexadecimal '
2111 raise util.Abort('changeset references must be full hexadecimal '
2112 'node identifiers')
2112 'node identifiers')
2113
2113
2114 if precursor is not None:
2114 if precursor is not None:
2115 metadata = {}
2115 metadata = {}
2116 if 'date' in opts:
2116 if 'date' in opts:
2117 metadata['date'] = opts['date']
2117 metadata['date'] = opts['date']
2118 metadata['user'] = opts['user'] or ui.username()
2118 metadata['user'] = opts['user'] or ui.username()
2119 succs = tuple(parsenodeid(succ) for succ in successors)
2119 succs = tuple(parsenodeid(succ) for succ in successors)
2120 l = repo.lock()
2120 l = repo.lock()
2121 try:
2121 try:
2122 tr = repo.transaction('debugobsolete')
2122 tr = repo.transaction('debugobsolete')
2123 try:
2123 try:
2124 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2124 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2125 opts['flags'], metadata)
2125 opts['flags'], metadata)
2126 tr.close()
2126 tr.close()
2127 finally:
2127 finally:
2128 tr.release()
2128 tr.release()
2129 finally:
2129 finally:
2130 l.release()
2130 l.release()
2131 else:
2131 else:
2132 for m in obsolete.allmarkers(repo):
2132 for m in obsolete.allmarkers(repo):
2133 ui.write(hex(m.precnode()))
2133 ui.write(hex(m.precnode()))
2134 for repl in m.succnodes():
2134 for repl in m.succnodes():
2135 ui.write(' ')
2135 ui.write(' ')
2136 ui.write(hex(repl))
2136 ui.write(hex(repl))
2137 ui.write(' %X ' % m._data[2])
2137 ui.write(' %X ' % m._data[2])
2138 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2138 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2139 sorted(m.metadata().items()))))
2139 sorted(m.metadata().items()))))
2140 ui.write('\n')
2140 ui.write('\n')
2141
2141
2142 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2142 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2143 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2143 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2144 '''access the pushkey key/value protocol
2144 '''access the pushkey key/value protocol
2145
2145
2146 With two args, list the keys in the given namespace.
2146 With two args, list the keys in the given namespace.
2147
2147
2148 With five args, set a key to new if it currently is set to old.
2148 With five args, set a key to new if it currently is set to old.
2149 Reports success or failure.
2149 Reports success or failure.
2150 '''
2150 '''
2151
2151
2152 target = hg.peer(ui, {}, repopath)
2152 target = hg.peer(ui, {}, repopath)
2153 if keyinfo:
2153 if keyinfo:
2154 key, old, new = keyinfo
2154 key, old, new = keyinfo
2155 r = target.pushkey(namespace, key, old, new)
2155 r = target.pushkey(namespace, key, old, new)
2156 ui.status(str(r) + '\n')
2156 ui.status(str(r) + '\n')
2157 return not r
2157 return not r
2158 else:
2158 else:
2159 for k, v in target.listkeys(namespace).iteritems():
2159 for k, v in sorted(target.listkeys(namespace).iteritems()):
2160 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2160 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2161 v.encode('string-escape')))
2161 v.encode('string-escape')))
2162
2162
2163 @command('debugpvec', [], _('A B'))
2163 @command('debugpvec', [], _('A B'))
2164 def debugpvec(ui, repo, a, b=None):
2164 def debugpvec(ui, repo, a, b=None):
2165 ca = scmutil.revsingle(repo, a)
2165 ca = scmutil.revsingle(repo, a)
2166 cb = scmutil.revsingle(repo, b)
2166 cb = scmutil.revsingle(repo, b)
2167 pa = pvec.ctxpvec(ca)
2167 pa = pvec.ctxpvec(ca)
2168 pb = pvec.ctxpvec(cb)
2168 pb = pvec.ctxpvec(cb)
2169 if pa == pb:
2169 if pa == pb:
2170 rel = "="
2170 rel = "="
2171 elif pa > pb:
2171 elif pa > pb:
2172 rel = ">"
2172 rel = ">"
2173 elif pa < pb:
2173 elif pa < pb:
2174 rel = "<"
2174 rel = "<"
2175 elif pa | pb:
2175 elif pa | pb:
2176 rel = "|"
2176 rel = "|"
2177 ui.write(_("a: %s\n") % pa)
2177 ui.write(_("a: %s\n") % pa)
2178 ui.write(_("b: %s\n") % pb)
2178 ui.write(_("b: %s\n") % pb)
2179 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2179 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2180 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2180 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2181 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2181 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2182 pa.distance(pb), rel))
2182 pa.distance(pb), rel))
2183
2183
2184 @command('debugrebuildstate',
2184 @command('debugrebuildstate',
2185 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2185 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2186 _('[-r REV] [REV]'))
2186 _('[-r REV] [REV]'))
2187 def debugrebuildstate(ui, repo, rev="tip"):
2187 def debugrebuildstate(ui, repo, rev="tip"):
2188 """rebuild the dirstate as it would look like for the given revision"""
2188 """rebuild the dirstate as it would look like for the given revision"""
2189 ctx = scmutil.revsingle(repo, rev)
2189 ctx = scmutil.revsingle(repo, rev)
2190 wlock = repo.wlock()
2190 wlock = repo.wlock()
2191 try:
2191 try:
2192 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2192 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2193 finally:
2193 finally:
2194 wlock.release()
2194 wlock.release()
2195
2195
2196 @command('debugrename',
2196 @command('debugrename',
2197 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2197 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2198 _('[-r REV] FILE'))
2198 _('[-r REV] FILE'))
2199 def debugrename(ui, repo, file1, *pats, **opts):
2199 def debugrename(ui, repo, file1, *pats, **opts):
2200 """dump rename information"""
2200 """dump rename information"""
2201
2201
2202 ctx = scmutil.revsingle(repo, opts.get('rev'))
2202 ctx = scmutil.revsingle(repo, opts.get('rev'))
2203 m = scmutil.match(ctx, (file1,) + pats, opts)
2203 m = scmutil.match(ctx, (file1,) + pats, opts)
2204 for abs in ctx.walk(m):
2204 for abs in ctx.walk(m):
2205 fctx = ctx[abs]
2205 fctx = ctx[abs]
2206 o = fctx.filelog().renamed(fctx.filenode())
2206 o = fctx.filelog().renamed(fctx.filenode())
2207 rel = m.rel(abs)
2207 rel = m.rel(abs)
2208 if o:
2208 if o:
2209 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2209 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2210 else:
2210 else:
2211 ui.write(_("%s not renamed\n") % rel)
2211 ui.write(_("%s not renamed\n") % rel)
2212
2212
2213 @command('debugrevlog',
2213 @command('debugrevlog',
2214 [('c', 'changelog', False, _('open changelog')),
2214 [('c', 'changelog', False, _('open changelog')),
2215 ('m', 'manifest', False, _('open manifest')),
2215 ('m', 'manifest', False, _('open manifest')),
2216 ('d', 'dump', False, _('dump index data'))],
2216 ('d', 'dump', False, _('dump index data'))],
2217 _('-c|-m|FILE'))
2217 _('-c|-m|FILE'))
2218 def debugrevlog(ui, repo, file_ = None, **opts):
2218 def debugrevlog(ui, repo, file_ = None, **opts):
2219 """show data and statistics about a revlog"""
2219 """show data and statistics about a revlog"""
2220 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2220 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2221
2221
2222 if opts.get("dump"):
2222 if opts.get("dump"):
2223 numrevs = len(r)
2223 numrevs = len(r)
2224 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2224 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2225 " rawsize totalsize compression heads\n")
2225 " rawsize totalsize compression heads\n")
2226 ts = 0
2226 ts = 0
2227 heads = set()
2227 heads = set()
2228 for rev in xrange(numrevs):
2228 for rev in xrange(numrevs):
2229 dbase = r.deltaparent(rev)
2229 dbase = r.deltaparent(rev)
2230 if dbase == -1:
2230 if dbase == -1:
2231 dbase = rev
2231 dbase = rev
2232 cbase = r.chainbase(rev)
2232 cbase = r.chainbase(rev)
2233 p1, p2 = r.parentrevs(rev)
2233 p1, p2 = r.parentrevs(rev)
2234 rs = r.rawsize(rev)
2234 rs = r.rawsize(rev)
2235 ts = ts + rs
2235 ts = ts + rs
2236 heads -= set(r.parentrevs(rev))
2236 heads -= set(r.parentrevs(rev))
2237 heads.add(rev)
2237 heads.add(rev)
2238 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2238 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2239 (rev, p1, p2, r.start(rev), r.end(rev),
2239 (rev, p1, p2, r.start(rev), r.end(rev),
2240 r.start(dbase), r.start(cbase),
2240 r.start(dbase), r.start(cbase),
2241 r.start(p1), r.start(p2),
2241 r.start(p1), r.start(p2),
2242 rs, ts, ts / r.end(rev), len(heads)))
2242 rs, ts, ts / r.end(rev), len(heads)))
2243 return 0
2243 return 0
2244
2244
2245 v = r.version
2245 v = r.version
2246 format = v & 0xFFFF
2246 format = v & 0xFFFF
2247 flags = []
2247 flags = []
2248 gdelta = False
2248 gdelta = False
2249 if v & revlog.REVLOGNGINLINEDATA:
2249 if v & revlog.REVLOGNGINLINEDATA:
2250 flags.append('inline')
2250 flags.append('inline')
2251 if v & revlog.REVLOGGENERALDELTA:
2251 if v & revlog.REVLOGGENERALDELTA:
2252 gdelta = True
2252 gdelta = True
2253 flags.append('generaldelta')
2253 flags.append('generaldelta')
2254 if not flags:
2254 if not flags:
2255 flags = ['(none)']
2255 flags = ['(none)']
2256
2256
2257 nummerges = 0
2257 nummerges = 0
2258 numfull = 0
2258 numfull = 0
2259 numprev = 0
2259 numprev = 0
2260 nump1 = 0
2260 nump1 = 0
2261 nump2 = 0
2261 nump2 = 0
2262 numother = 0
2262 numother = 0
2263 nump1prev = 0
2263 nump1prev = 0
2264 nump2prev = 0
2264 nump2prev = 0
2265 chainlengths = []
2265 chainlengths = []
2266
2266
2267 datasize = [None, 0, 0L]
2267 datasize = [None, 0, 0L]
2268 fullsize = [None, 0, 0L]
2268 fullsize = [None, 0, 0L]
2269 deltasize = [None, 0, 0L]
2269 deltasize = [None, 0, 0L]
2270
2270
2271 def addsize(size, l):
2271 def addsize(size, l):
2272 if l[0] is None or size < l[0]:
2272 if l[0] is None or size < l[0]:
2273 l[0] = size
2273 l[0] = size
2274 if size > l[1]:
2274 if size > l[1]:
2275 l[1] = size
2275 l[1] = size
2276 l[2] += size
2276 l[2] += size
2277
2277
2278 numrevs = len(r)
2278 numrevs = len(r)
2279 for rev in xrange(numrevs):
2279 for rev in xrange(numrevs):
2280 p1, p2 = r.parentrevs(rev)
2280 p1, p2 = r.parentrevs(rev)
2281 delta = r.deltaparent(rev)
2281 delta = r.deltaparent(rev)
2282 if format > 0:
2282 if format > 0:
2283 addsize(r.rawsize(rev), datasize)
2283 addsize(r.rawsize(rev), datasize)
2284 if p2 != nullrev:
2284 if p2 != nullrev:
2285 nummerges += 1
2285 nummerges += 1
2286 size = r.length(rev)
2286 size = r.length(rev)
2287 if delta == nullrev:
2287 if delta == nullrev:
2288 chainlengths.append(0)
2288 chainlengths.append(0)
2289 numfull += 1
2289 numfull += 1
2290 addsize(size, fullsize)
2290 addsize(size, fullsize)
2291 else:
2291 else:
2292 chainlengths.append(chainlengths[delta] + 1)
2292 chainlengths.append(chainlengths[delta] + 1)
2293 addsize(size, deltasize)
2293 addsize(size, deltasize)
2294 if delta == rev - 1:
2294 if delta == rev - 1:
2295 numprev += 1
2295 numprev += 1
2296 if delta == p1:
2296 if delta == p1:
2297 nump1prev += 1
2297 nump1prev += 1
2298 elif delta == p2:
2298 elif delta == p2:
2299 nump2prev += 1
2299 nump2prev += 1
2300 elif delta == p1:
2300 elif delta == p1:
2301 nump1 += 1
2301 nump1 += 1
2302 elif delta == p2:
2302 elif delta == p2:
2303 nump2 += 1
2303 nump2 += 1
2304 elif delta != nullrev:
2304 elif delta != nullrev:
2305 numother += 1
2305 numother += 1
2306
2306
2307 # Adjust size min value for empty cases
2307 # Adjust size min value for empty cases
2308 for size in (datasize, fullsize, deltasize):
2308 for size in (datasize, fullsize, deltasize):
2309 if size[0] is None:
2309 if size[0] is None:
2310 size[0] = 0
2310 size[0] = 0
2311
2311
2312 numdeltas = numrevs - numfull
2312 numdeltas = numrevs - numfull
2313 numoprev = numprev - nump1prev - nump2prev
2313 numoprev = numprev - nump1prev - nump2prev
2314 totalrawsize = datasize[2]
2314 totalrawsize = datasize[2]
2315 datasize[2] /= numrevs
2315 datasize[2] /= numrevs
2316 fulltotal = fullsize[2]
2316 fulltotal = fullsize[2]
2317 fullsize[2] /= numfull
2317 fullsize[2] /= numfull
2318 deltatotal = deltasize[2]
2318 deltatotal = deltasize[2]
2319 if numrevs - numfull > 0:
2319 if numrevs - numfull > 0:
2320 deltasize[2] /= numrevs - numfull
2320 deltasize[2] /= numrevs - numfull
2321 totalsize = fulltotal + deltatotal
2321 totalsize = fulltotal + deltatotal
2322 avgchainlen = sum(chainlengths) / numrevs
2322 avgchainlen = sum(chainlengths) / numrevs
2323 compratio = totalrawsize / totalsize
2323 compratio = totalrawsize / totalsize
2324
2324
2325 basedfmtstr = '%%%dd\n'
2325 basedfmtstr = '%%%dd\n'
2326 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2326 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2327
2327
2328 def dfmtstr(max):
2328 def dfmtstr(max):
2329 return basedfmtstr % len(str(max))
2329 return basedfmtstr % len(str(max))
2330 def pcfmtstr(max, padding=0):
2330 def pcfmtstr(max, padding=0):
2331 return basepcfmtstr % (len(str(max)), ' ' * padding)
2331 return basepcfmtstr % (len(str(max)), ' ' * padding)
2332
2332
2333 def pcfmt(value, total):
2333 def pcfmt(value, total):
2334 return (value, 100 * float(value) / total)
2334 return (value, 100 * float(value) / total)
2335
2335
2336 ui.write(('format : %d\n') % format)
2336 ui.write(('format : %d\n') % format)
2337 ui.write(('flags : %s\n') % ', '.join(flags))
2337 ui.write(('flags : %s\n') % ', '.join(flags))
2338
2338
2339 ui.write('\n')
2339 ui.write('\n')
2340 fmt = pcfmtstr(totalsize)
2340 fmt = pcfmtstr(totalsize)
2341 fmt2 = dfmtstr(totalsize)
2341 fmt2 = dfmtstr(totalsize)
2342 ui.write(('revisions : ') + fmt2 % numrevs)
2342 ui.write(('revisions : ') + fmt2 % numrevs)
2343 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2343 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2344 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2344 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2345 ui.write(('revisions : ') + fmt2 % numrevs)
2345 ui.write(('revisions : ') + fmt2 % numrevs)
2346 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2346 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2347 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2347 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2348 ui.write(('revision size : ') + fmt2 % totalsize)
2348 ui.write(('revision size : ') + fmt2 % totalsize)
2349 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2349 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2350 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2350 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2351
2351
2352 ui.write('\n')
2352 ui.write('\n')
2353 fmt = dfmtstr(max(avgchainlen, compratio))
2353 fmt = dfmtstr(max(avgchainlen, compratio))
2354 ui.write(('avg chain length : ') + fmt % avgchainlen)
2354 ui.write(('avg chain length : ') + fmt % avgchainlen)
2355 ui.write(('compression ratio : ') + fmt % compratio)
2355 ui.write(('compression ratio : ') + fmt % compratio)
2356
2356
2357 if format > 0:
2357 if format > 0:
2358 ui.write('\n')
2358 ui.write('\n')
2359 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2359 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2360 % tuple(datasize))
2360 % tuple(datasize))
2361 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2361 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2362 % tuple(fullsize))
2362 % tuple(fullsize))
2363 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2363 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2364 % tuple(deltasize))
2364 % tuple(deltasize))
2365
2365
2366 if numdeltas > 0:
2366 if numdeltas > 0:
2367 ui.write('\n')
2367 ui.write('\n')
2368 fmt = pcfmtstr(numdeltas)
2368 fmt = pcfmtstr(numdeltas)
2369 fmt2 = pcfmtstr(numdeltas, 4)
2369 fmt2 = pcfmtstr(numdeltas, 4)
2370 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2370 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2371 if numprev > 0:
2371 if numprev > 0:
2372 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2372 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2373 numprev))
2373 numprev))
2374 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2374 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2375 numprev))
2375 numprev))
2376 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2376 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2377 numprev))
2377 numprev))
2378 if gdelta:
2378 if gdelta:
2379 ui.write(('deltas against p1 : ')
2379 ui.write(('deltas against p1 : ')
2380 + fmt % pcfmt(nump1, numdeltas))
2380 + fmt % pcfmt(nump1, numdeltas))
2381 ui.write(('deltas against p2 : ')
2381 ui.write(('deltas against p2 : ')
2382 + fmt % pcfmt(nump2, numdeltas))
2382 + fmt % pcfmt(nump2, numdeltas))
2383 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2383 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2384 numdeltas))
2384 numdeltas))
2385
2385
2386 @command('debugrevspec', [], ('REVSPEC'))
2386 @command('debugrevspec', [], ('REVSPEC'))
2387 def debugrevspec(ui, repo, expr):
2387 def debugrevspec(ui, repo, expr):
2388 """parse and apply a revision specification
2388 """parse and apply a revision specification
2389
2389
2390 Use --verbose to print the parsed tree before and after aliases
2390 Use --verbose to print the parsed tree before and after aliases
2391 expansion.
2391 expansion.
2392 """
2392 """
2393 if ui.verbose:
2393 if ui.verbose:
2394 tree = revset.parse(expr)[0]
2394 tree = revset.parse(expr)[0]
2395 ui.note(revset.prettyformat(tree), "\n")
2395 ui.note(revset.prettyformat(tree), "\n")
2396 newtree = revset.findaliases(ui, tree)
2396 newtree = revset.findaliases(ui, tree)
2397 if newtree != tree:
2397 if newtree != tree:
2398 ui.note(revset.prettyformat(newtree), "\n")
2398 ui.note(revset.prettyformat(newtree), "\n")
2399 func = revset.match(ui, expr)
2399 func = revset.match(ui, expr)
2400 for c in func(repo, range(len(repo))):
2400 for c in func(repo, range(len(repo))):
2401 ui.write("%s\n" % c)
2401 ui.write("%s\n" % c)
2402
2402
2403 @command('debugsetparents', [], _('REV1 [REV2]'))
2403 @command('debugsetparents', [], _('REV1 [REV2]'))
2404 def debugsetparents(ui, repo, rev1, rev2=None):
2404 def debugsetparents(ui, repo, rev1, rev2=None):
2405 """manually set the parents of the current working directory
2405 """manually set the parents of the current working directory
2406
2406
2407 This is useful for writing repository conversion tools, but should
2407 This is useful for writing repository conversion tools, but should
2408 be used with care.
2408 be used with care.
2409
2409
2410 Returns 0 on success.
2410 Returns 0 on success.
2411 """
2411 """
2412
2412
2413 r1 = scmutil.revsingle(repo, rev1).node()
2413 r1 = scmutil.revsingle(repo, rev1).node()
2414 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2414 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2415
2415
2416 wlock = repo.wlock()
2416 wlock = repo.wlock()
2417 try:
2417 try:
2418 repo.setparents(r1, r2)
2418 repo.setparents(r1, r2)
2419 finally:
2419 finally:
2420 wlock.release()
2420 wlock.release()
2421
2421
2422 @command('debugstate',
2422 @command('debugstate',
2423 [('', 'nodates', None, _('do not display the saved mtime')),
2423 [('', 'nodates', None, _('do not display the saved mtime')),
2424 ('', 'datesort', None, _('sort by saved mtime'))],
2424 ('', 'datesort', None, _('sort by saved mtime'))],
2425 _('[OPTION]...'))
2425 _('[OPTION]...'))
2426 def debugstate(ui, repo, nodates=None, datesort=None):
2426 def debugstate(ui, repo, nodates=None, datesort=None):
2427 """show the contents of the current dirstate"""
2427 """show the contents of the current dirstate"""
2428 timestr = ""
2428 timestr = ""
2429 showdate = not nodates
2429 showdate = not nodates
2430 if datesort:
2430 if datesort:
2431 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2431 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2432 else:
2432 else:
2433 keyfunc = None # sort by filename
2433 keyfunc = None # sort by filename
2434 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2434 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2435 if showdate:
2435 if showdate:
2436 if ent[3] == -1:
2436 if ent[3] == -1:
2437 # Pad or slice to locale representation
2437 # Pad or slice to locale representation
2438 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2438 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2439 time.localtime(0)))
2439 time.localtime(0)))
2440 timestr = 'unset'
2440 timestr = 'unset'
2441 timestr = (timestr[:locale_len] +
2441 timestr = (timestr[:locale_len] +
2442 ' ' * (locale_len - len(timestr)))
2442 ' ' * (locale_len - len(timestr)))
2443 else:
2443 else:
2444 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2444 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2445 time.localtime(ent[3]))
2445 time.localtime(ent[3]))
2446 if ent[1] & 020000:
2446 if ent[1] & 020000:
2447 mode = 'lnk'
2447 mode = 'lnk'
2448 else:
2448 else:
2449 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2449 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2450 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2450 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2451 for f in repo.dirstate.copies():
2451 for f in repo.dirstate.copies():
2452 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2452 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2453
2453
2454 @command('debugsub',
2454 @command('debugsub',
2455 [('r', 'rev', '',
2455 [('r', 'rev', '',
2456 _('revision to check'), _('REV'))],
2456 _('revision to check'), _('REV'))],
2457 _('[-r REV] [REV]'))
2457 _('[-r REV] [REV]'))
2458 def debugsub(ui, repo, rev=None):
2458 def debugsub(ui, repo, rev=None):
2459 ctx = scmutil.revsingle(repo, rev, None)
2459 ctx = scmutil.revsingle(repo, rev, None)
2460 for k, v in sorted(ctx.substate.items()):
2460 for k, v in sorted(ctx.substate.items()):
2461 ui.write(('path %s\n') % k)
2461 ui.write(('path %s\n') % k)
2462 ui.write((' source %s\n') % v[0])
2462 ui.write((' source %s\n') % v[0])
2463 ui.write((' revision %s\n') % v[1])
2463 ui.write((' revision %s\n') % v[1])
2464
2464
2465 @command('debugsuccessorssets',
2465 @command('debugsuccessorssets',
2466 [],
2466 [],
2467 _('[REV]'))
2467 _('[REV]'))
2468 def debugsuccessorssets(ui, repo, *revs):
2468 def debugsuccessorssets(ui, repo, *revs):
2469 """show set of successors for revision
2469 """show set of successors for revision
2470
2470
2471 A successors set of changeset A is a consistent group of revisions that
2471 A successors set of changeset A is a consistent group of revisions that
2472 succeed A. It contains non-obsolete changesets only.
2472 succeed A. It contains non-obsolete changesets only.
2473
2473
2474 In most cases a changeset A has a single successors set containing a single
2474 In most cases a changeset A has a single successors set containing a single
2475 successors (changeset A replaced by A').
2475 successors (changeset A replaced by A').
2476
2476
2477 A changeset that is made obsolete with no successors are called "pruned".
2477 A changeset that is made obsolete with no successors are called "pruned".
2478 Such changesets have no successors sets at all.
2478 Such changesets have no successors sets at all.
2479
2479
2480 A changeset that has been "split" will have a successors set containing
2480 A changeset that has been "split" will have a successors set containing
2481 more than one successors.
2481 more than one successors.
2482
2482
2483 A changeset that has been rewritten in multiple different ways is called
2483 A changeset that has been rewritten in multiple different ways is called
2484 "divergent". Such changesets have multiple successor sets (each of which
2484 "divergent". Such changesets have multiple successor sets (each of which
2485 may also be split, i.e. have multiple successors).
2485 may also be split, i.e. have multiple successors).
2486
2486
2487 Results are displayed as follows::
2487 Results are displayed as follows::
2488
2488
2489 <rev1>
2489 <rev1>
2490 <successors-1A>
2490 <successors-1A>
2491 <rev2>
2491 <rev2>
2492 <successors-2A>
2492 <successors-2A>
2493 <successors-2B1> <successors-2B2> <successors-2B3>
2493 <successors-2B1> <successors-2B2> <successors-2B3>
2494
2494
2495 Here rev2 has two possible (i.e. divergent) successors sets. The first
2495 Here rev2 has two possible (i.e. divergent) successors sets. The first
2496 holds one element, whereas the second holds three (i.e. the changeset has
2496 holds one element, whereas the second holds three (i.e. the changeset has
2497 been split).
2497 been split).
2498 """
2498 """
2499 # passed to successorssets caching computation from one call to another
2499 # passed to successorssets caching computation from one call to another
2500 cache = {}
2500 cache = {}
2501 ctx2str = str
2501 ctx2str = str
2502 node2str = short
2502 node2str = short
2503 if ui.debug():
2503 if ui.debug():
2504 def ctx2str(ctx):
2504 def ctx2str(ctx):
2505 return ctx.hex()
2505 return ctx.hex()
2506 node2str = hex
2506 node2str = hex
2507 for rev in scmutil.revrange(repo, revs):
2507 for rev in scmutil.revrange(repo, revs):
2508 ctx = repo[rev]
2508 ctx = repo[rev]
2509 ui.write('%s\n'% ctx2str(ctx))
2509 ui.write('%s\n'% ctx2str(ctx))
2510 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2510 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2511 if succsset:
2511 if succsset:
2512 ui.write(' ')
2512 ui.write(' ')
2513 ui.write(node2str(succsset[0]))
2513 ui.write(node2str(succsset[0]))
2514 for node in succsset[1:]:
2514 for node in succsset[1:]:
2515 ui.write(' ')
2515 ui.write(' ')
2516 ui.write(node2str(node))
2516 ui.write(node2str(node))
2517 ui.write('\n')
2517 ui.write('\n')
2518
2518
2519 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2519 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2520 def debugwalk(ui, repo, *pats, **opts):
2520 def debugwalk(ui, repo, *pats, **opts):
2521 """show how files match on given patterns"""
2521 """show how files match on given patterns"""
2522 m = scmutil.match(repo[None], pats, opts)
2522 m = scmutil.match(repo[None], pats, opts)
2523 items = list(repo.walk(m))
2523 items = list(repo.walk(m))
2524 if not items:
2524 if not items:
2525 return
2525 return
2526 f = lambda fn: fn
2526 f = lambda fn: fn
2527 if ui.configbool('ui', 'slash') and os.sep != '/':
2527 if ui.configbool('ui', 'slash') and os.sep != '/':
2528 f = lambda fn: util.normpath(fn)
2528 f = lambda fn: util.normpath(fn)
2529 fmt = 'f %%-%ds %%-%ds %%s' % (
2529 fmt = 'f %%-%ds %%-%ds %%s' % (
2530 max([len(abs) for abs in items]),
2530 max([len(abs) for abs in items]),
2531 max([len(m.rel(abs)) for abs in items]))
2531 max([len(m.rel(abs)) for abs in items]))
2532 for abs in items:
2532 for abs in items:
2533 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2533 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2534 ui.write("%s\n" % line.rstrip())
2534 ui.write("%s\n" % line.rstrip())
2535
2535
2536 @command('debugwireargs',
2536 @command('debugwireargs',
2537 [('', 'three', '', 'three'),
2537 [('', 'three', '', 'three'),
2538 ('', 'four', '', 'four'),
2538 ('', 'four', '', 'four'),
2539 ('', 'five', '', 'five'),
2539 ('', 'five', '', 'five'),
2540 ] + remoteopts,
2540 ] + remoteopts,
2541 _('REPO [OPTIONS]... [ONE [TWO]]'))
2541 _('REPO [OPTIONS]... [ONE [TWO]]'))
2542 def debugwireargs(ui, repopath, *vals, **opts):
2542 def debugwireargs(ui, repopath, *vals, **opts):
2543 repo = hg.peer(ui, opts, repopath)
2543 repo = hg.peer(ui, opts, repopath)
2544 for opt in remoteopts:
2544 for opt in remoteopts:
2545 del opts[opt[1]]
2545 del opts[opt[1]]
2546 args = {}
2546 args = {}
2547 for k, v in opts.iteritems():
2547 for k, v in opts.iteritems():
2548 if v:
2548 if v:
2549 args[k] = v
2549 args[k] = v
2550 # run twice to check that we don't mess up the stream for the next command
2550 # run twice to check that we don't mess up the stream for the next command
2551 res1 = repo.debugwireargs(*vals, **args)
2551 res1 = repo.debugwireargs(*vals, **args)
2552 res2 = repo.debugwireargs(*vals, **args)
2552 res2 = repo.debugwireargs(*vals, **args)
2553 ui.write("%s\n" % res1)
2553 ui.write("%s\n" % res1)
2554 if res1 != res2:
2554 if res1 != res2:
2555 ui.warn("%s\n" % res2)
2555 ui.warn("%s\n" % res2)
2556
2556
2557 @command('^diff',
2557 @command('^diff',
2558 [('r', 'rev', [], _('revision'), _('REV')),
2558 [('r', 'rev', [], _('revision'), _('REV')),
2559 ('c', 'change', '', _('change made by revision'), _('REV'))
2559 ('c', 'change', '', _('change made by revision'), _('REV'))
2560 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2560 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2561 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2561 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2562 def diff(ui, repo, *pats, **opts):
2562 def diff(ui, repo, *pats, **opts):
2563 """diff repository (or selected files)
2563 """diff repository (or selected files)
2564
2564
2565 Show differences between revisions for the specified files.
2565 Show differences between revisions for the specified files.
2566
2566
2567 Differences between files are shown using the unified diff format.
2567 Differences between files are shown using the unified diff format.
2568
2568
2569 .. note::
2569 .. note::
2570 diff may generate unexpected results for merges, as it will
2570 diff may generate unexpected results for merges, as it will
2571 default to comparing against the working directory's first
2571 default to comparing against the working directory's first
2572 parent changeset if no revisions are specified.
2572 parent changeset if no revisions are specified.
2573
2573
2574 When two revision arguments are given, then changes are shown
2574 When two revision arguments are given, then changes are shown
2575 between those revisions. If only one revision is specified then
2575 between those revisions. If only one revision is specified then
2576 that revision is compared to the working directory, and, when no
2576 that revision is compared to the working directory, and, when no
2577 revisions are specified, the working directory files are compared
2577 revisions are specified, the working directory files are compared
2578 to its parent.
2578 to its parent.
2579
2579
2580 Alternatively you can specify -c/--change with a revision to see
2580 Alternatively you can specify -c/--change with a revision to see
2581 the changes in that changeset relative to its first parent.
2581 the changes in that changeset relative to its first parent.
2582
2582
2583 Without the -a/--text option, diff will avoid generating diffs of
2583 Without the -a/--text option, diff will avoid generating diffs of
2584 files it detects as binary. With -a, diff will generate a diff
2584 files it detects as binary. With -a, diff will generate a diff
2585 anyway, probably with undesirable results.
2585 anyway, probably with undesirable results.
2586
2586
2587 Use the -g/--git option to generate diffs in the git extended diff
2587 Use the -g/--git option to generate diffs in the git extended diff
2588 format. For more information, read :hg:`help diffs`.
2588 format. For more information, read :hg:`help diffs`.
2589
2589
2590 .. container:: verbose
2590 .. container:: verbose
2591
2591
2592 Examples:
2592 Examples:
2593
2593
2594 - compare a file in the current working directory to its parent::
2594 - compare a file in the current working directory to its parent::
2595
2595
2596 hg diff foo.c
2596 hg diff foo.c
2597
2597
2598 - compare two historical versions of a directory, with rename info::
2598 - compare two historical versions of a directory, with rename info::
2599
2599
2600 hg diff --git -r 1.0:1.2 lib/
2600 hg diff --git -r 1.0:1.2 lib/
2601
2601
2602 - get change stats relative to the last change on some date::
2602 - get change stats relative to the last change on some date::
2603
2603
2604 hg diff --stat -r "date('may 2')"
2604 hg diff --stat -r "date('may 2')"
2605
2605
2606 - diff all newly-added files that contain a keyword::
2606 - diff all newly-added files that contain a keyword::
2607
2607
2608 hg diff "set:added() and grep(GNU)"
2608 hg diff "set:added() and grep(GNU)"
2609
2609
2610 - compare a revision and its parents::
2610 - compare a revision and its parents::
2611
2611
2612 hg diff -c 9353 # compare against first parent
2612 hg diff -c 9353 # compare against first parent
2613 hg diff -r 9353^:9353 # same using revset syntax
2613 hg diff -r 9353^:9353 # same using revset syntax
2614 hg diff -r 9353^2:9353 # compare against the second parent
2614 hg diff -r 9353^2:9353 # compare against the second parent
2615
2615
2616 Returns 0 on success.
2616 Returns 0 on success.
2617 """
2617 """
2618
2618
2619 revs = opts.get('rev')
2619 revs = opts.get('rev')
2620 change = opts.get('change')
2620 change = opts.get('change')
2621 stat = opts.get('stat')
2621 stat = opts.get('stat')
2622 reverse = opts.get('reverse')
2622 reverse = opts.get('reverse')
2623
2623
2624 if revs and change:
2624 if revs and change:
2625 msg = _('cannot specify --rev and --change at the same time')
2625 msg = _('cannot specify --rev and --change at the same time')
2626 raise util.Abort(msg)
2626 raise util.Abort(msg)
2627 elif change:
2627 elif change:
2628 node2 = scmutil.revsingle(repo, change, None).node()
2628 node2 = scmutil.revsingle(repo, change, None).node()
2629 node1 = repo[node2].p1().node()
2629 node1 = repo[node2].p1().node()
2630 else:
2630 else:
2631 node1, node2 = scmutil.revpair(repo, revs)
2631 node1, node2 = scmutil.revpair(repo, revs)
2632
2632
2633 if reverse:
2633 if reverse:
2634 node1, node2 = node2, node1
2634 node1, node2 = node2, node1
2635
2635
2636 diffopts = patch.diffopts(ui, opts)
2636 diffopts = patch.diffopts(ui, opts)
2637 m = scmutil.match(repo[node2], pats, opts)
2637 m = scmutil.match(repo[node2], pats, opts)
2638 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2638 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2639 listsubrepos=opts.get('subrepos'))
2639 listsubrepos=opts.get('subrepos'))
2640
2640
2641 @command('^export',
2641 @command('^export',
2642 [('o', 'output', '',
2642 [('o', 'output', '',
2643 _('print output to file with formatted name'), _('FORMAT')),
2643 _('print output to file with formatted name'), _('FORMAT')),
2644 ('', 'switch-parent', None, _('diff against the second parent')),
2644 ('', 'switch-parent', None, _('diff against the second parent')),
2645 ('r', 'rev', [], _('revisions to export'), _('REV')),
2645 ('r', 'rev', [], _('revisions to export'), _('REV')),
2646 ] + diffopts,
2646 ] + diffopts,
2647 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2647 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2648 def export(ui, repo, *changesets, **opts):
2648 def export(ui, repo, *changesets, **opts):
2649 """dump the header and diffs for one or more changesets
2649 """dump the header and diffs for one or more changesets
2650
2650
2651 Print the changeset header and diffs for one or more revisions.
2651 Print the changeset header and diffs for one or more revisions.
2652
2652
2653 The information shown in the changeset header is: author, date,
2653 The information shown in the changeset header is: author, date,
2654 branch name (if non-default), changeset hash, parent(s) and commit
2654 branch name (if non-default), changeset hash, parent(s) and commit
2655 comment.
2655 comment.
2656
2656
2657 .. note::
2657 .. note::
2658 export may generate unexpected diff output for merge
2658 export may generate unexpected diff output for merge
2659 changesets, as it will compare the merge changeset against its
2659 changesets, as it will compare the merge changeset against its
2660 first parent only.
2660 first parent only.
2661
2661
2662 Output may be to a file, in which case the name of the file is
2662 Output may be to a file, in which case the name of the file is
2663 given using a format string. The formatting rules are as follows:
2663 given using a format string. The formatting rules are as follows:
2664
2664
2665 :``%%``: literal "%" character
2665 :``%%``: literal "%" character
2666 :``%H``: changeset hash (40 hexadecimal digits)
2666 :``%H``: changeset hash (40 hexadecimal digits)
2667 :``%N``: number of patches being generated
2667 :``%N``: number of patches being generated
2668 :``%R``: changeset revision number
2668 :``%R``: changeset revision number
2669 :``%b``: basename of the exporting repository
2669 :``%b``: basename of the exporting repository
2670 :``%h``: short-form changeset hash (12 hexadecimal digits)
2670 :``%h``: short-form changeset hash (12 hexadecimal digits)
2671 :``%m``: first line of the commit message (only alphanumeric characters)
2671 :``%m``: first line of the commit message (only alphanumeric characters)
2672 :``%n``: zero-padded sequence number, starting at 1
2672 :``%n``: zero-padded sequence number, starting at 1
2673 :``%r``: zero-padded changeset revision number
2673 :``%r``: zero-padded changeset revision number
2674
2674
2675 Without the -a/--text option, export will avoid generating diffs
2675 Without the -a/--text option, export will avoid generating diffs
2676 of files it detects as binary. With -a, export will generate a
2676 of files it detects as binary. With -a, export will generate a
2677 diff anyway, probably with undesirable results.
2677 diff anyway, probably with undesirable results.
2678
2678
2679 Use the -g/--git option to generate diffs in the git extended diff
2679 Use the -g/--git option to generate diffs in the git extended diff
2680 format. See :hg:`help diffs` for more information.
2680 format. See :hg:`help diffs` for more information.
2681
2681
2682 With the --switch-parent option, the diff will be against the
2682 With the --switch-parent option, the diff will be against the
2683 second parent. It can be useful to review a merge.
2683 second parent. It can be useful to review a merge.
2684
2684
2685 .. container:: verbose
2685 .. container:: verbose
2686
2686
2687 Examples:
2687 Examples:
2688
2688
2689 - use export and import to transplant a bugfix to the current
2689 - use export and import to transplant a bugfix to the current
2690 branch::
2690 branch::
2691
2691
2692 hg export -r 9353 | hg import -
2692 hg export -r 9353 | hg import -
2693
2693
2694 - export all the changesets between two revisions to a file with
2694 - export all the changesets between two revisions to a file with
2695 rename information::
2695 rename information::
2696
2696
2697 hg export --git -r 123:150 > changes.txt
2697 hg export --git -r 123:150 > changes.txt
2698
2698
2699 - split outgoing changes into a series of patches with
2699 - split outgoing changes into a series of patches with
2700 descriptive names::
2700 descriptive names::
2701
2701
2702 hg export -r "outgoing()" -o "%n-%m.patch"
2702 hg export -r "outgoing()" -o "%n-%m.patch"
2703
2703
2704 Returns 0 on success.
2704 Returns 0 on success.
2705 """
2705 """
2706 changesets += tuple(opts.get('rev', []))
2706 changesets += tuple(opts.get('rev', []))
2707 revs = scmutil.revrange(repo, changesets)
2707 revs = scmutil.revrange(repo, changesets)
2708 if not revs:
2708 if not revs:
2709 raise util.Abort(_("export requires at least one changeset"))
2709 raise util.Abort(_("export requires at least one changeset"))
2710 if len(revs) > 1:
2710 if len(revs) > 1:
2711 ui.note(_('exporting patches:\n'))
2711 ui.note(_('exporting patches:\n'))
2712 else:
2712 else:
2713 ui.note(_('exporting patch:\n'))
2713 ui.note(_('exporting patch:\n'))
2714 cmdutil.export(repo, revs, template=opts.get('output'),
2714 cmdutil.export(repo, revs, template=opts.get('output'),
2715 switch_parent=opts.get('switch_parent'),
2715 switch_parent=opts.get('switch_parent'),
2716 opts=patch.diffopts(ui, opts))
2716 opts=patch.diffopts(ui, opts))
2717
2717
2718 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2718 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2719 def forget(ui, repo, *pats, **opts):
2719 def forget(ui, repo, *pats, **opts):
2720 """forget the specified files on the next commit
2720 """forget the specified files on the next commit
2721
2721
2722 Mark the specified files so they will no longer be tracked
2722 Mark the specified files so they will no longer be tracked
2723 after the next commit.
2723 after the next commit.
2724
2724
2725 This only removes files from the current branch, not from the
2725 This only removes files from the current branch, not from the
2726 entire project history, and it does not delete them from the
2726 entire project history, and it does not delete them from the
2727 working directory.
2727 working directory.
2728
2728
2729 To undo a forget before the next commit, see :hg:`add`.
2729 To undo a forget before the next commit, see :hg:`add`.
2730
2730
2731 .. container:: verbose
2731 .. container:: verbose
2732
2732
2733 Examples:
2733 Examples:
2734
2734
2735 - forget newly-added binary files::
2735 - forget newly-added binary files::
2736
2736
2737 hg forget "set:added() and binary()"
2737 hg forget "set:added() and binary()"
2738
2738
2739 - forget files that would be excluded by .hgignore::
2739 - forget files that would be excluded by .hgignore::
2740
2740
2741 hg forget "set:hgignore()"
2741 hg forget "set:hgignore()"
2742
2742
2743 Returns 0 on success.
2743 Returns 0 on success.
2744 """
2744 """
2745
2745
2746 if not pats:
2746 if not pats:
2747 raise util.Abort(_('no files specified'))
2747 raise util.Abort(_('no files specified'))
2748
2748
2749 m = scmutil.match(repo[None], pats, opts)
2749 m = scmutil.match(repo[None], pats, opts)
2750 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2750 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2751 return rejected and 1 or 0
2751 return rejected and 1 or 0
2752
2752
2753 @command(
2753 @command(
2754 'graft',
2754 'graft',
2755 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2755 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2756 ('c', 'continue', False, _('resume interrupted graft')),
2756 ('c', 'continue', False, _('resume interrupted graft')),
2757 ('e', 'edit', False, _('invoke editor on commit messages')),
2757 ('e', 'edit', False, _('invoke editor on commit messages')),
2758 ('', 'log', None, _('append graft info to log message')),
2758 ('', 'log', None, _('append graft info to log message')),
2759 ('D', 'currentdate', False,
2759 ('D', 'currentdate', False,
2760 _('record the current date as commit date')),
2760 _('record the current date as commit date')),
2761 ('U', 'currentuser', False,
2761 ('U', 'currentuser', False,
2762 _('record the current user as committer'), _('DATE'))]
2762 _('record the current user as committer'), _('DATE'))]
2763 + commitopts2 + mergetoolopts + dryrunopts,
2763 + commitopts2 + mergetoolopts + dryrunopts,
2764 _('[OPTION]... [-r] REV...'))
2764 _('[OPTION]... [-r] REV...'))
2765 def graft(ui, repo, *revs, **opts):
2765 def graft(ui, repo, *revs, **opts):
2766 '''copy changes from other branches onto the current branch
2766 '''copy changes from other branches onto the current branch
2767
2767
2768 This command uses Mercurial's merge logic to copy individual
2768 This command uses Mercurial's merge logic to copy individual
2769 changes from other branches without merging branches in the
2769 changes from other branches without merging branches in the
2770 history graph. This is sometimes known as 'backporting' or
2770 history graph. This is sometimes known as 'backporting' or
2771 'cherry-picking'. By default, graft will copy user, date, and
2771 'cherry-picking'. By default, graft will copy user, date, and
2772 description from the source changesets.
2772 description from the source changesets.
2773
2773
2774 Changesets that are ancestors of the current revision, that have
2774 Changesets that are ancestors of the current revision, that have
2775 already been grafted, or that are merges will be skipped.
2775 already been grafted, or that are merges will be skipped.
2776
2776
2777 If --log is specified, log messages will have a comment appended
2777 If --log is specified, log messages will have a comment appended
2778 of the form::
2778 of the form::
2779
2779
2780 (grafted from CHANGESETHASH)
2780 (grafted from CHANGESETHASH)
2781
2781
2782 If a graft merge results in conflicts, the graft process is
2782 If a graft merge results in conflicts, the graft process is
2783 interrupted so that the current merge can be manually resolved.
2783 interrupted so that the current merge can be manually resolved.
2784 Once all conflicts are addressed, the graft process can be
2784 Once all conflicts are addressed, the graft process can be
2785 continued with the -c/--continue option.
2785 continued with the -c/--continue option.
2786
2786
2787 .. note::
2787 .. note::
2788 The -c/--continue option does not reapply earlier options.
2788 The -c/--continue option does not reapply earlier options.
2789
2789
2790 .. container:: verbose
2790 .. container:: verbose
2791
2791
2792 Examples:
2792 Examples:
2793
2793
2794 - copy a single change to the stable branch and edit its description::
2794 - copy a single change to the stable branch and edit its description::
2795
2795
2796 hg update stable
2796 hg update stable
2797 hg graft --edit 9393
2797 hg graft --edit 9393
2798
2798
2799 - graft a range of changesets with one exception, updating dates::
2799 - graft a range of changesets with one exception, updating dates::
2800
2800
2801 hg graft -D "2085::2093 and not 2091"
2801 hg graft -D "2085::2093 and not 2091"
2802
2802
2803 - continue a graft after resolving conflicts::
2803 - continue a graft after resolving conflicts::
2804
2804
2805 hg graft -c
2805 hg graft -c
2806
2806
2807 - show the source of a grafted changeset::
2807 - show the source of a grafted changeset::
2808
2808
2809 hg log --debug -r tip
2809 hg log --debug -r tip
2810
2810
2811 Returns 0 on successful completion.
2811 Returns 0 on successful completion.
2812 '''
2812 '''
2813
2813
2814 revs = list(revs)
2814 revs = list(revs)
2815 revs.extend(opts['rev'])
2815 revs.extend(opts['rev'])
2816
2816
2817 if not opts.get('user') and opts.get('currentuser'):
2817 if not opts.get('user') and opts.get('currentuser'):
2818 opts['user'] = ui.username()
2818 opts['user'] = ui.username()
2819 if not opts.get('date') and opts.get('currentdate'):
2819 if not opts.get('date') and opts.get('currentdate'):
2820 opts['date'] = "%d %d" % util.makedate()
2820 opts['date'] = "%d %d" % util.makedate()
2821
2821
2822 editor = None
2822 editor = None
2823 if opts.get('edit'):
2823 if opts.get('edit'):
2824 editor = cmdutil.commitforceeditor
2824 editor = cmdutil.commitforceeditor
2825
2825
2826 cont = False
2826 cont = False
2827 if opts['continue']:
2827 if opts['continue']:
2828 cont = True
2828 cont = True
2829 if revs:
2829 if revs:
2830 raise util.Abort(_("can't specify --continue and revisions"))
2830 raise util.Abort(_("can't specify --continue and revisions"))
2831 # read in unfinished revisions
2831 # read in unfinished revisions
2832 try:
2832 try:
2833 nodes = repo.opener.read('graftstate').splitlines()
2833 nodes = repo.opener.read('graftstate').splitlines()
2834 revs = [repo[node].rev() for node in nodes]
2834 revs = [repo[node].rev() for node in nodes]
2835 except IOError, inst:
2835 except IOError, inst:
2836 if inst.errno != errno.ENOENT:
2836 if inst.errno != errno.ENOENT:
2837 raise
2837 raise
2838 raise util.Abort(_("no graft state found, can't continue"))
2838 raise util.Abort(_("no graft state found, can't continue"))
2839 else:
2839 else:
2840 cmdutil.bailifchanged(repo)
2840 cmdutil.bailifchanged(repo)
2841 if not revs:
2841 if not revs:
2842 raise util.Abort(_('no revisions specified'))
2842 raise util.Abort(_('no revisions specified'))
2843 revs = scmutil.revrange(repo, revs)
2843 revs = scmutil.revrange(repo, revs)
2844
2844
2845 # check for merges
2845 # check for merges
2846 for rev in repo.revs('%ld and merge()', revs):
2846 for rev in repo.revs('%ld and merge()', revs):
2847 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2847 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2848 revs.remove(rev)
2848 revs.remove(rev)
2849 if not revs:
2849 if not revs:
2850 return -1
2850 return -1
2851
2851
2852 # check for ancestors of dest branch
2852 # check for ancestors of dest branch
2853 for rev in repo.revs('::. and %ld', revs):
2853 for rev in repo.revs('::. and %ld', revs):
2854 ui.warn(_('skipping ancestor revision %s\n') % rev)
2854 ui.warn(_('skipping ancestor revision %s\n') % rev)
2855 revs.remove(rev)
2855 revs.remove(rev)
2856 if not revs:
2856 if not revs:
2857 return -1
2857 return -1
2858
2858
2859 # analyze revs for earlier grafts
2859 # analyze revs for earlier grafts
2860 ids = {}
2860 ids = {}
2861 for ctx in repo.set("%ld", revs):
2861 for ctx in repo.set("%ld", revs):
2862 ids[ctx.hex()] = ctx.rev()
2862 ids[ctx.hex()] = ctx.rev()
2863 n = ctx.extra().get('source')
2863 n = ctx.extra().get('source')
2864 if n:
2864 if n:
2865 ids[n] = ctx.rev()
2865 ids[n] = ctx.rev()
2866
2866
2867 # check ancestors for earlier grafts
2867 # check ancestors for earlier grafts
2868 ui.debug('scanning for duplicate grafts\n')
2868 ui.debug('scanning for duplicate grafts\n')
2869 for ctx in repo.set("::. - ::%ld", revs):
2869 for ctx in repo.set("::. - ::%ld", revs):
2870 n = ctx.extra().get('source')
2870 n = ctx.extra().get('source')
2871 if n in ids:
2871 if n in ids:
2872 r = repo[n].rev()
2872 r = repo[n].rev()
2873 if r in revs:
2873 if r in revs:
2874 ui.warn(_('skipping already grafted revision %s\n') % r)
2874 ui.warn(_('skipping already grafted revision %s\n') % r)
2875 revs.remove(r)
2875 revs.remove(r)
2876 elif ids[n] in revs:
2876 elif ids[n] in revs:
2877 ui.warn(_('skipping already grafted revision %s '
2877 ui.warn(_('skipping already grafted revision %s '
2878 '(same origin %d)\n') % (ids[n], r))
2878 '(same origin %d)\n') % (ids[n], r))
2879 revs.remove(ids[n])
2879 revs.remove(ids[n])
2880 elif ctx.hex() in ids:
2880 elif ctx.hex() in ids:
2881 r = ids[ctx.hex()]
2881 r = ids[ctx.hex()]
2882 ui.warn(_('skipping already grafted revision %s '
2882 ui.warn(_('skipping already grafted revision %s '
2883 '(was grafted from %d)\n') % (r, ctx.rev()))
2883 '(was grafted from %d)\n') % (r, ctx.rev()))
2884 revs.remove(r)
2884 revs.remove(r)
2885 if not revs:
2885 if not revs:
2886 return -1
2886 return -1
2887
2887
2888 wlock = repo.wlock()
2888 wlock = repo.wlock()
2889 try:
2889 try:
2890 current = repo['.']
2890 current = repo['.']
2891 for pos, ctx in enumerate(repo.set("%ld", revs)):
2891 for pos, ctx in enumerate(repo.set("%ld", revs)):
2892
2892
2893 ui.status(_('grafting revision %s\n') % ctx.rev())
2893 ui.status(_('grafting revision %s\n') % ctx.rev())
2894 if opts.get('dry_run'):
2894 if opts.get('dry_run'):
2895 continue
2895 continue
2896
2896
2897 source = ctx.extra().get('source')
2897 source = ctx.extra().get('source')
2898 if not source:
2898 if not source:
2899 source = ctx.hex()
2899 source = ctx.hex()
2900 extra = {'source': source}
2900 extra = {'source': source}
2901 user = ctx.user()
2901 user = ctx.user()
2902 if opts.get('user'):
2902 if opts.get('user'):
2903 user = opts['user']
2903 user = opts['user']
2904 date = ctx.date()
2904 date = ctx.date()
2905 if opts.get('date'):
2905 if opts.get('date'):
2906 date = opts['date']
2906 date = opts['date']
2907 message = ctx.description()
2907 message = ctx.description()
2908 if opts.get('log'):
2908 if opts.get('log'):
2909 message += '\n(grafted from %s)' % ctx.hex()
2909 message += '\n(grafted from %s)' % ctx.hex()
2910
2910
2911 # we don't merge the first commit when continuing
2911 # we don't merge the first commit when continuing
2912 if not cont:
2912 if not cont:
2913 # perform the graft merge with p1(rev) as 'ancestor'
2913 # perform the graft merge with p1(rev) as 'ancestor'
2914 try:
2914 try:
2915 # ui.forcemerge is an internal variable, do not document
2915 # ui.forcemerge is an internal variable, do not document
2916 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2916 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2917 stats = mergemod.update(repo, ctx.node(), True, True, False,
2917 stats = mergemod.update(repo, ctx.node(), True, True, False,
2918 ctx.p1().node())
2918 ctx.p1().node())
2919 finally:
2919 finally:
2920 repo.ui.setconfig('ui', 'forcemerge', '')
2920 repo.ui.setconfig('ui', 'forcemerge', '')
2921 # report any conflicts
2921 # report any conflicts
2922 if stats and stats[3] > 0:
2922 if stats and stats[3] > 0:
2923 # write out state for --continue
2923 # write out state for --continue
2924 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2924 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2925 repo.opener.write('graftstate', ''.join(nodelines))
2925 repo.opener.write('graftstate', ''.join(nodelines))
2926 raise util.Abort(
2926 raise util.Abort(
2927 _("unresolved conflicts, can't continue"),
2927 _("unresolved conflicts, can't continue"),
2928 hint=_('use hg resolve and hg graft --continue'))
2928 hint=_('use hg resolve and hg graft --continue'))
2929 else:
2929 else:
2930 cont = False
2930 cont = False
2931
2931
2932 # drop the second merge parent
2932 # drop the second merge parent
2933 repo.setparents(current.node(), nullid)
2933 repo.setparents(current.node(), nullid)
2934 repo.dirstate.write()
2934 repo.dirstate.write()
2935 # fix up dirstate for copies and renames
2935 # fix up dirstate for copies and renames
2936 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2936 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2937
2937
2938 # commit
2938 # commit
2939 node = repo.commit(text=message, user=user,
2939 node = repo.commit(text=message, user=user,
2940 date=date, extra=extra, editor=editor)
2940 date=date, extra=extra, editor=editor)
2941 if node is None:
2941 if node is None:
2942 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2942 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2943 else:
2943 else:
2944 current = repo[node]
2944 current = repo[node]
2945 finally:
2945 finally:
2946 wlock.release()
2946 wlock.release()
2947
2947
2948 # remove state when we complete successfully
2948 # remove state when we complete successfully
2949 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2949 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2950 util.unlinkpath(repo.join('graftstate'))
2950 util.unlinkpath(repo.join('graftstate'))
2951
2951
2952 return 0
2952 return 0
2953
2953
2954 @command('grep',
2954 @command('grep',
2955 [('0', 'print0', None, _('end fields with NUL')),
2955 [('0', 'print0', None, _('end fields with NUL')),
2956 ('', 'all', None, _('print all revisions that match')),
2956 ('', 'all', None, _('print all revisions that match')),
2957 ('a', 'text', None, _('treat all files as text')),
2957 ('a', 'text', None, _('treat all files as text')),
2958 ('f', 'follow', None,
2958 ('f', 'follow', None,
2959 _('follow changeset history,'
2959 _('follow changeset history,'
2960 ' or file history across copies and renames')),
2960 ' or file history across copies and renames')),
2961 ('i', 'ignore-case', None, _('ignore case when matching')),
2961 ('i', 'ignore-case', None, _('ignore case when matching')),
2962 ('l', 'files-with-matches', None,
2962 ('l', 'files-with-matches', None,
2963 _('print only filenames and revisions that match')),
2963 _('print only filenames and revisions that match')),
2964 ('n', 'line-number', None, _('print matching line numbers')),
2964 ('n', 'line-number', None, _('print matching line numbers')),
2965 ('r', 'rev', [],
2965 ('r', 'rev', [],
2966 _('only search files changed within revision range'), _('REV')),
2966 _('only search files changed within revision range'), _('REV')),
2967 ('u', 'user', None, _('list the author (long with -v)')),
2967 ('u', 'user', None, _('list the author (long with -v)')),
2968 ('d', 'date', None, _('list the date (short with -q)')),
2968 ('d', 'date', None, _('list the date (short with -q)')),
2969 ] + walkopts,
2969 ] + walkopts,
2970 _('[OPTION]... PATTERN [FILE]...'))
2970 _('[OPTION]... PATTERN [FILE]...'))
2971 def grep(ui, repo, pattern, *pats, **opts):
2971 def grep(ui, repo, pattern, *pats, **opts):
2972 """search for a pattern in specified files and revisions
2972 """search for a pattern in specified files and revisions
2973
2973
2974 Search revisions of files for a regular expression.
2974 Search revisions of files for a regular expression.
2975
2975
2976 This command behaves differently than Unix grep. It only accepts
2976 This command behaves differently than Unix grep. It only accepts
2977 Python/Perl regexps. It searches repository history, not the
2977 Python/Perl regexps. It searches repository history, not the
2978 working directory. It always prints the revision number in which a
2978 working directory. It always prints the revision number in which a
2979 match appears.
2979 match appears.
2980
2980
2981 By default, grep only prints output for the first revision of a
2981 By default, grep only prints output for the first revision of a
2982 file in which it finds a match. To get it to print every revision
2982 file in which it finds a match. To get it to print every revision
2983 that contains a change in match status ("-" for a match that
2983 that contains a change in match status ("-" for a match that
2984 becomes a non-match, or "+" for a non-match that becomes a match),
2984 becomes a non-match, or "+" for a non-match that becomes a match),
2985 use the --all flag.
2985 use the --all flag.
2986
2986
2987 Returns 0 if a match is found, 1 otherwise.
2987 Returns 0 if a match is found, 1 otherwise.
2988 """
2988 """
2989 reflags = re.M
2989 reflags = re.M
2990 if opts.get('ignore_case'):
2990 if opts.get('ignore_case'):
2991 reflags |= re.I
2991 reflags |= re.I
2992 try:
2992 try:
2993 regexp = re.compile(pattern, reflags)
2993 regexp = re.compile(pattern, reflags)
2994 except re.error, inst:
2994 except re.error, inst:
2995 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2995 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2996 return 1
2996 return 1
2997 sep, eol = ':', '\n'
2997 sep, eol = ':', '\n'
2998 if opts.get('print0'):
2998 if opts.get('print0'):
2999 sep = eol = '\0'
2999 sep = eol = '\0'
3000
3000
3001 getfile = util.lrucachefunc(repo.file)
3001 getfile = util.lrucachefunc(repo.file)
3002
3002
3003 def matchlines(body):
3003 def matchlines(body):
3004 begin = 0
3004 begin = 0
3005 linenum = 0
3005 linenum = 0
3006 while begin < len(body):
3006 while begin < len(body):
3007 match = regexp.search(body, begin)
3007 match = regexp.search(body, begin)
3008 if not match:
3008 if not match:
3009 break
3009 break
3010 mstart, mend = match.span()
3010 mstart, mend = match.span()
3011 linenum += body.count('\n', begin, mstart) + 1
3011 linenum += body.count('\n', begin, mstart) + 1
3012 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3012 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3013 begin = body.find('\n', mend) + 1 or len(body) + 1
3013 begin = body.find('\n', mend) + 1 or len(body) + 1
3014 lend = begin - 1
3014 lend = begin - 1
3015 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3015 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3016
3016
3017 class linestate(object):
3017 class linestate(object):
3018 def __init__(self, line, linenum, colstart, colend):
3018 def __init__(self, line, linenum, colstart, colend):
3019 self.line = line
3019 self.line = line
3020 self.linenum = linenum
3020 self.linenum = linenum
3021 self.colstart = colstart
3021 self.colstart = colstart
3022 self.colend = colend
3022 self.colend = colend
3023
3023
3024 def __hash__(self):
3024 def __hash__(self):
3025 return hash((self.linenum, self.line))
3025 return hash((self.linenum, self.line))
3026
3026
3027 def __eq__(self, other):
3027 def __eq__(self, other):
3028 return self.line == other.line
3028 return self.line == other.line
3029
3029
3030 matches = {}
3030 matches = {}
3031 copies = {}
3031 copies = {}
3032 def grepbody(fn, rev, body):
3032 def grepbody(fn, rev, body):
3033 matches[rev].setdefault(fn, [])
3033 matches[rev].setdefault(fn, [])
3034 m = matches[rev][fn]
3034 m = matches[rev][fn]
3035 for lnum, cstart, cend, line in matchlines(body):
3035 for lnum, cstart, cend, line in matchlines(body):
3036 s = linestate(line, lnum, cstart, cend)
3036 s = linestate(line, lnum, cstart, cend)
3037 m.append(s)
3037 m.append(s)
3038
3038
3039 def difflinestates(a, b):
3039 def difflinestates(a, b):
3040 sm = difflib.SequenceMatcher(None, a, b)
3040 sm = difflib.SequenceMatcher(None, a, b)
3041 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3041 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3042 if tag == 'insert':
3042 if tag == 'insert':
3043 for i in xrange(blo, bhi):
3043 for i in xrange(blo, bhi):
3044 yield ('+', b[i])
3044 yield ('+', b[i])
3045 elif tag == 'delete':
3045 elif tag == 'delete':
3046 for i in xrange(alo, ahi):
3046 for i in xrange(alo, ahi):
3047 yield ('-', a[i])
3047 yield ('-', a[i])
3048 elif tag == 'replace':
3048 elif tag == 'replace':
3049 for i in xrange(alo, ahi):
3049 for i in xrange(alo, ahi):
3050 yield ('-', a[i])
3050 yield ('-', a[i])
3051 for i in xrange(blo, bhi):
3051 for i in xrange(blo, bhi):
3052 yield ('+', b[i])
3052 yield ('+', b[i])
3053
3053
3054 def display(fn, ctx, pstates, states):
3054 def display(fn, ctx, pstates, states):
3055 rev = ctx.rev()
3055 rev = ctx.rev()
3056 datefunc = ui.quiet and util.shortdate or util.datestr
3056 datefunc = ui.quiet and util.shortdate or util.datestr
3057 found = False
3057 found = False
3058 filerevmatches = {}
3058 filerevmatches = {}
3059 def binary():
3059 def binary():
3060 flog = getfile(fn)
3060 flog = getfile(fn)
3061 return util.binary(flog.read(ctx.filenode(fn)))
3061 return util.binary(flog.read(ctx.filenode(fn)))
3062
3062
3063 if opts.get('all'):
3063 if opts.get('all'):
3064 iter = difflinestates(pstates, states)
3064 iter = difflinestates(pstates, states)
3065 else:
3065 else:
3066 iter = [('', l) for l in states]
3066 iter = [('', l) for l in states]
3067 for change, l in iter:
3067 for change, l in iter:
3068 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3068 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3069 before, match, after = None, None, None
3069 before, match, after = None, None, None
3070
3070
3071 if opts.get('line_number'):
3071 if opts.get('line_number'):
3072 cols.append((str(l.linenum), 'grep.linenumber'))
3072 cols.append((str(l.linenum), 'grep.linenumber'))
3073 if opts.get('all'):
3073 if opts.get('all'):
3074 cols.append((change, 'grep.change'))
3074 cols.append((change, 'grep.change'))
3075 if opts.get('user'):
3075 if opts.get('user'):
3076 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3076 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3077 if opts.get('date'):
3077 if opts.get('date'):
3078 cols.append((datefunc(ctx.date()), 'grep.date'))
3078 cols.append((datefunc(ctx.date()), 'grep.date'))
3079 if opts.get('files_with_matches'):
3079 if opts.get('files_with_matches'):
3080 c = (fn, rev)
3080 c = (fn, rev)
3081 if c in filerevmatches:
3081 if c in filerevmatches:
3082 continue
3082 continue
3083 filerevmatches[c] = 1
3083 filerevmatches[c] = 1
3084 else:
3084 else:
3085 before = l.line[:l.colstart]
3085 before = l.line[:l.colstart]
3086 match = l.line[l.colstart:l.colend]
3086 match = l.line[l.colstart:l.colend]
3087 after = l.line[l.colend:]
3087 after = l.line[l.colend:]
3088 for col, label in cols[:-1]:
3088 for col, label in cols[:-1]:
3089 ui.write(col, label=label)
3089 ui.write(col, label=label)
3090 ui.write(sep, label='grep.sep')
3090 ui.write(sep, label='grep.sep')
3091 ui.write(cols[-1][0], label=cols[-1][1])
3091 ui.write(cols[-1][0], label=cols[-1][1])
3092 if before is not None:
3092 if before is not None:
3093 ui.write(sep, label='grep.sep')
3093 ui.write(sep, label='grep.sep')
3094 if not opts.get('text') and binary():
3094 if not opts.get('text') and binary():
3095 ui.write(" Binary file matches")
3095 ui.write(" Binary file matches")
3096 else:
3096 else:
3097 ui.write(before)
3097 ui.write(before)
3098 ui.write(match, label='grep.match')
3098 ui.write(match, label='grep.match')
3099 ui.write(after)
3099 ui.write(after)
3100 ui.write(eol)
3100 ui.write(eol)
3101 found = True
3101 found = True
3102 return found
3102 return found
3103
3103
3104 skip = {}
3104 skip = {}
3105 revfiles = {}
3105 revfiles = {}
3106 matchfn = scmutil.match(repo[None], pats, opts)
3106 matchfn = scmutil.match(repo[None], pats, opts)
3107 found = False
3107 found = False
3108 follow = opts.get('follow')
3108 follow = opts.get('follow')
3109
3109
3110 def prep(ctx, fns):
3110 def prep(ctx, fns):
3111 rev = ctx.rev()
3111 rev = ctx.rev()
3112 pctx = ctx.p1()
3112 pctx = ctx.p1()
3113 parent = pctx.rev()
3113 parent = pctx.rev()
3114 matches.setdefault(rev, {})
3114 matches.setdefault(rev, {})
3115 matches.setdefault(parent, {})
3115 matches.setdefault(parent, {})
3116 files = revfiles.setdefault(rev, [])
3116 files = revfiles.setdefault(rev, [])
3117 for fn in fns:
3117 for fn in fns:
3118 flog = getfile(fn)
3118 flog = getfile(fn)
3119 try:
3119 try:
3120 fnode = ctx.filenode(fn)
3120 fnode = ctx.filenode(fn)
3121 except error.LookupError:
3121 except error.LookupError:
3122 continue
3122 continue
3123
3123
3124 copied = flog.renamed(fnode)
3124 copied = flog.renamed(fnode)
3125 copy = follow and copied and copied[0]
3125 copy = follow and copied and copied[0]
3126 if copy:
3126 if copy:
3127 copies.setdefault(rev, {})[fn] = copy
3127 copies.setdefault(rev, {})[fn] = copy
3128 if fn in skip:
3128 if fn in skip:
3129 if copy:
3129 if copy:
3130 skip[copy] = True
3130 skip[copy] = True
3131 continue
3131 continue
3132 files.append(fn)
3132 files.append(fn)
3133
3133
3134 if fn not in matches[rev]:
3134 if fn not in matches[rev]:
3135 grepbody(fn, rev, flog.read(fnode))
3135 grepbody(fn, rev, flog.read(fnode))
3136
3136
3137 pfn = copy or fn
3137 pfn = copy or fn
3138 if pfn not in matches[parent]:
3138 if pfn not in matches[parent]:
3139 try:
3139 try:
3140 fnode = pctx.filenode(pfn)
3140 fnode = pctx.filenode(pfn)
3141 grepbody(pfn, parent, flog.read(fnode))
3141 grepbody(pfn, parent, flog.read(fnode))
3142 except error.LookupError:
3142 except error.LookupError:
3143 pass
3143 pass
3144
3144
3145 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3145 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3146 rev = ctx.rev()
3146 rev = ctx.rev()
3147 parent = ctx.p1().rev()
3147 parent = ctx.p1().rev()
3148 for fn in sorted(revfiles.get(rev, [])):
3148 for fn in sorted(revfiles.get(rev, [])):
3149 states = matches[rev][fn]
3149 states = matches[rev][fn]
3150 copy = copies.get(rev, {}).get(fn)
3150 copy = copies.get(rev, {}).get(fn)
3151 if fn in skip:
3151 if fn in skip:
3152 if copy:
3152 if copy:
3153 skip[copy] = True
3153 skip[copy] = True
3154 continue
3154 continue
3155 pstates = matches.get(parent, {}).get(copy or fn, [])
3155 pstates = matches.get(parent, {}).get(copy or fn, [])
3156 if pstates or states:
3156 if pstates or states:
3157 r = display(fn, ctx, pstates, states)
3157 r = display(fn, ctx, pstates, states)
3158 found = found or r
3158 found = found or r
3159 if r and not opts.get('all'):
3159 if r and not opts.get('all'):
3160 skip[fn] = True
3160 skip[fn] = True
3161 if copy:
3161 if copy:
3162 skip[copy] = True
3162 skip[copy] = True
3163 del matches[rev]
3163 del matches[rev]
3164 del revfiles[rev]
3164 del revfiles[rev]
3165
3165
3166 return not found
3166 return not found
3167
3167
3168 @command('heads',
3168 @command('heads',
3169 [('r', 'rev', '',
3169 [('r', 'rev', '',
3170 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3170 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3171 ('t', 'topo', False, _('show topological heads only')),
3171 ('t', 'topo', False, _('show topological heads only')),
3172 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3172 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3173 ('c', 'closed', False, _('show normal and closed branch heads')),
3173 ('c', 'closed', False, _('show normal and closed branch heads')),
3174 ] + templateopts,
3174 ] + templateopts,
3175 _('[-ct] [-r STARTREV] [REV]...'))
3175 _('[-ct] [-r STARTREV] [REV]...'))
3176 def heads(ui, repo, *branchrevs, **opts):
3176 def heads(ui, repo, *branchrevs, **opts):
3177 """show current repository heads or show branch heads
3177 """show current repository heads or show branch heads
3178
3178
3179 With no arguments, show all repository branch heads.
3179 With no arguments, show all repository branch heads.
3180
3180
3181 Repository "heads" are changesets with no child changesets. They are
3181 Repository "heads" are changesets with no child changesets. They are
3182 where development generally takes place and are the usual targets
3182 where development generally takes place and are the usual targets
3183 for update and merge operations. Branch heads are changesets that have
3183 for update and merge operations. Branch heads are changesets that have
3184 no child changeset on the same branch.
3184 no child changeset on the same branch.
3185
3185
3186 If one or more REVs are given, only branch heads on the branches
3186 If one or more REVs are given, only branch heads on the branches
3187 associated with the specified changesets are shown. This means
3187 associated with the specified changesets are shown. This means
3188 that you can use :hg:`heads foo` to see the heads on a branch
3188 that you can use :hg:`heads foo` to see the heads on a branch
3189 named ``foo``.
3189 named ``foo``.
3190
3190
3191 If -c/--closed is specified, also show branch heads marked closed
3191 If -c/--closed is specified, also show branch heads marked closed
3192 (see :hg:`commit --close-branch`).
3192 (see :hg:`commit --close-branch`).
3193
3193
3194 If STARTREV is specified, only those heads that are descendants of
3194 If STARTREV is specified, only those heads that are descendants of
3195 STARTREV will be displayed.
3195 STARTREV will be displayed.
3196
3196
3197 If -t/--topo is specified, named branch mechanics will be ignored and only
3197 If -t/--topo is specified, named branch mechanics will be ignored and only
3198 changesets without children will be shown.
3198 changesets without children will be shown.
3199
3199
3200 Returns 0 if matching heads are found, 1 if not.
3200 Returns 0 if matching heads are found, 1 if not.
3201 """
3201 """
3202
3202
3203 start = None
3203 start = None
3204 if 'rev' in opts:
3204 if 'rev' in opts:
3205 start = scmutil.revsingle(repo, opts['rev'], None).node()
3205 start = scmutil.revsingle(repo, opts['rev'], None).node()
3206
3206
3207 if opts.get('topo'):
3207 if opts.get('topo'):
3208 heads = [repo[h] for h in repo.heads(start)]
3208 heads = [repo[h] for h in repo.heads(start)]
3209 else:
3209 else:
3210 heads = []
3210 heads = []
3211 for branch in repo.branchmap():
3211 for branch in repo.branchmap():
3212 heads += repo.branchheads(branch, start, opts.get('closed'))
3212 heads += repo.branchheads(branch, start, opts.get('closed'))
3213 heads = [repo[h] for h in heads]
3213 heads = [repo[h] for h in heads]
3214
3214
3215 if branchrevs:
3215 if branchrevs:
3216 branches = set(repo[br].branch() for br in branchrevs)
3216 branches = set(repo[br].branch() for br in branchrevs)
3217 heads = [h for h in heads if h.branch() in branches]
3217 heads = [h for h in heads if h.branch() in branches]
3218
3218
3219 if opts.get('active') and branchrevs:
3219 if opts.get('active') and branchrevs:
3220 dagheads = repo.heads(start)
3220 dagheads = repo.heads(start)
3221 heads = [h for h in heads if h.node() in dagheads]
3221 heads = [h for h in heads if h.node() in dagheads]
3222
3222
3223 if branchrevs:
3223 if branchrevs:
3224 haveheads = set(h.branch() for h in heads)
3224 haveheads = set(h.branch() for h in heads)
3225 if branches - haveheads:
3225 if branches - haveheads:
3226 headless = ', '.join(b for b in branches - haveheads)
3226 headless = ', '.join(b for b in branches - haveheads)
3227 msg = _('no open branch heads found on branches %s')
3227 msg = _('no open branch heads found on branches %s')
3228 if opts.get('rev'):
3228 if opts.get('rev'):
3229 msg += _(' (started at %s)') % opts['rev']
3229 msg += _(' (started at %s)') % opts['rev']
3230 ui.warn((msg + '\n') % headless)
3230 ui.warn((msg + '\n') % headless)
3231
3231
3232 if not heads:
3232 if not heads:
3233 return 1
3233 return 1
3234
3234
3235 heads = sorted(heads, key=lambda x: -x.rev())
3235 heads = sorted(heads, key=lambda x: -x.rev())
3236 displayer = cmdutil.show_changeset(ui, repo, opts)
3236 displayer = cmdutil.show_changeset(ui, repo, opts)
3237 for ctx in heads:
3237 for ctx in heads:
3238 displayer.show(ctx)
3238 displayer.show(ctx)
3239 displayer.close()
3239 displayer.close()
3240
3240
3241 @command('help',
3241 @command('help',
3242 [('e', 'extension', None, _('show only help for extensions')),
3242 [('e', 'extension', None, _('show only help for extensions')),
3243 ('c', 'command', None, _('show only help for commands')),
3243 ('c', 'command', None, _('show only help for commands')),
3244 ('k', 'keyword', '', _('show topics matching keyword')),
3244 ('k', 'keyword', '', _('show topics matching keyword')),
3245 ],
3245 ],
3246 _('[-ec] [TOPIC]'))
3246 _('[-ec] [TOPIC]'))
3247 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3247 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3248 """show help for a given topic or a help overview
3248 """show help for a given topic or a help overview
3249
3249
3250 With no arguments, print a list of commands with short help messages.
3250 With no arguments, print a list of commands with short help messages.
3251
3251
3252 Given a topic, extension, or command name, print help for that
3252 Given a topic, extension, or command name, print help for that
3253 topic.
3253 topic.
3254
3254
3255 Returns 0 if successful.
3255 Returns 0 if successful.
3256 """
3256 """
3257
3257
3258 textwidth = min(ui.termwidth(), 80) - 2
3258 textwidth = min(ui.termwidth(), 80) - 2
3259
3259
3260 def helpcmd(name):
3260 def helpcmd(name):
3261 try:
3261 try:
3262 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3262 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3263 except error.AmbiguousCommand, inst:
3263 except error.AmbiguousCommand, inst:
3264 # py3k fix: except vars can't be used outside the scope of the
3264 # py3k fix: except vars can't be used outside the scope of the
3265 # except block, nor can be used inside a lambda. python issue4617
3265 # except block, nor can be used inside a lambda. python issue4617
3266 prefix = inst.args[0]
3266 prefix = inst.args[0]
3267 select = lambda c: c.lstrip('^').startswith(prefix)
3267 select = lambda c: c.lstrip('^').startswith(prefix)
3268 rst = helplist(select)
3268 rst = helplist(select)
3269 return rst
3269 return rst
3270
3270
3271 rst = []
3271 rst = []
3272
3272
3273 # check if it's an invalid alias and display its error if it is
3273 # check if it's an invalid alias and display its error if it is
3274 if getattr(entry[0], 'badalias', False):
3274 if getattr(entry[0], 'badalias', False):
3275 if not unknowncmd:
3275 if not unknowncmd:
3276 ui.pushbuffer()
3276 ui.pushbuffer()
3277 entry[0](ui)
3277 entry[0](ui)
3278 rst.append(ui.popbuffer())
3278 rst.append(ui.popbuffer())
3279 return rst
3279 return rst
3280
3280
3281 # synopsis
3281 # synopsis
3282 if len(entry) > 2:
3282 if len(entry) > 2:
3283 if entry[2].startswith('hg'):
3283 if entry[2].startswith('hg'):
3284 rst.append("%s\n" % entry[2])
3284 rst.append("%s\n" % entry[2])
3285 else:
3285 else:
3286 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3286 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3287 else:
3287 else:
3288 rst.append('hg %s\n' % aliases[0])
3288 rst.append('hg %s\n' % aliases[0])
3289 # aliases
3289 # aliases
3290 if full and not ui.quiet and len(aliases) > 1:
3290 if full and not ui.quiet and len(aliases) > 1:
3291 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3291 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3292 rst.append('\n')
3292 rst.append('\n')
3293
3293
3294 # description
3294 # description
3295 doc = gettext(entry[0].__doc__)
3295 doc = gettext(entry[0].__doc__)
3296 if not doc:
3296 if not doc:
3297 doc = _("(no help text available)")
3297 doc = _("(no help text available)")
3298 if util.safehasattr(entry[0], 'definition'): # aliased command
3298 if util.safehasattr(entry[0], 'definition'): # aliased command
3299 if entry[0].definition.startswith('!'): # shell alias
3299 if entry[0].definition.startswith('!'): # shell alias
3300 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3300 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3301 else:
3301 else:
3302 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3302 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3303 doc = doc.splitlines(True)
3303 doc = doc.splitlines(True)
3304 if ui.quiet or not full:
3304 if ui.quiet or not full:
3305 rst.append(doc[0])
3305 rst.append(doc[0])
3306 else:
3306 else:
3307 rst.extend(doc)
3307 rst.extend(doc)
3308 rst.append('\n')
3308 rst.append('\n')
3309
3309
3310 # check if this command shadows a non-trivial (multi-line)
3310 # check if this command shadows a non-trivial (multi-line)
3311 # extension help text
3311 # extension help text
3312 try:
3312 try:
3313 mod = extensions.find(name)
3313 mod = extensions.find(name)
3314 doc = gettext(mod.__doc__) or ''
3314 doc = gettext(mod.__doc__) or ''
3315 if '\n' in doc.strip():
3315 if '\n' in doc.strip():
3316 msg = _('use "hg help -e %s" to show help for '
3316 msg = _('use "hg help -e %s" to show help for '
3317 'the %s extension') % (name, name)
3317 'the %s extension') % (name, name)
3318 rst.append('\n%s\n' % msg)
3318 rst.append('\n%s\n' % msg)
3319 except KeyError:
3319 except KeyError:
3320 pass
3320 pass
3321
3321
3322 # options
3322 # options
3323 if not ui.quiet and entry[1]:
3323 if not ui.quiet and entry[1]:
3324 rst.append('\n%s\n\n' % _("options:"))
3324 rst.append('\n%s\n\n' % _("options:"))
3325 rst.append(help.optrst(entry[1], ui.verbose))
3325 rst.append(help.optrst(entry[1], ui.verbose))
3326
3326
3327 if ui.verbose:
3327 if ui.verbose:
3328 rst.append('\n%s\n\n' % _("global options:"))
3328 rst.append('\n%s\n\n' % _("global options:"))
3329 rst.append(help.optrst(globalopts, ui.verbose))
3329 rst.append(help.optrst(globalopts, ui.verbose))
3330
3330
3331 if not ui.verbose:
3331 if not ui.verbose:
3332 if not full:
3332 if not full:
3333 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3333 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3334 % name)
3334 % name)
3335 elif not ui.quiet:
3335 elif not ui.quiet:
3336 omitted = _('use "hg -v help %s" to show more complete'
3336 omitted = _('use "hg -v help %s" to show more complete'
3337 ' help and the global options') % name
3337 ' help and the global options') % name
3338 notomitted = _('use "hg -v help %s" to show'
3338 notomitted = _('use "hg -v help %s" to show'
3339 ' the global options') % name
3339 ' the global options') % name
3340 help.indicateomitted(rst, omitted, notomitted)
3340 help.indicateomitted(rst, omitted, notomitted)
3341
3341
3342 return rst
3342 return rst
3343
3343
3344
3344
3345 def helplist(select=None):
3345 def helplist(select=None):
3346 # list of commands
3346 # list of commands
3347 if name == "shortlist":
3347 if name == "shortlist":
3348 header = _('basic commands:\n\n')
3348 header = _('basic commands:\n\n')
3349 else:
3349 else:
3350 header = _('list of commands:\n\n')
3350 header = _('list of commands:\n\n')
3351
3351
3352 h = {}
3352 h = {}
3353 cmds = {}
3353 cmds = {}
3354 for c, e in table.iteritems():
3354 for c, e in table.iteritems():
3355 f = c.split("|", 1)[0]
3355 f = c.split("|", 1)[0]
3356 if select and not select(f):
3356 if select and not select(f):
3357 continue
3357 continue
3358 if (not select and name != 'shortlist' and
3358 if (not select and name != 'shortlist' and
3359 e[0].__module__ != __name__):
3359 e[0].__module__ != __name__):
3360 continue
3360 continue
3361 if name == "shortlist" and not f.startswith("^"):
3361 if name == "shortlist" and not f.startswith("^"):
3362 continue
3362 continue
3363 f = f.lstrip("^")
3363 f = f.lstrip("^")
3364 if not ui.debugflag and f.startswith("debug"):
3364 if not ui.debugflag and f.startswith("debug"):
3365 continue
3365 continue
3366 doc = e[0].__doc__
3366 doc = e[0].__doc__
3367 if doc and 'DEPRECATED' in doc and not ui.verbose:
3367 if doc and 'DEPRECATED' in doc and not ui.verbose:
3368 continue
3368 continue
3369 doc = gettext(doc)
3369 doc = gettext(doc)
3370 if not doc:
3370 if not doc:
3371 doc = _("(no help text available)")
3371 doc = _("(no help text available)")
3372 h[f] = doc.splitlines()[0].rstrip()
3372 h[f] = doc.splitlines()[0].rstrip()
3373 cmds[f] = c.lstrip("^")
3373 cmds[f] = c.lstrip("^")
3374
3374
3375 rst = []
3375 rst = []
3376 if not h:
3376 if not h:
3377 if not ui.quiet:
3377 if not ui.quiet:
3378 rst.append(_('no commands defined\n'))
3378 rst.append(_('no commands defined\n'))
3379 return rst
3379 return rst
3380
3380
3381 if not ui.quiet:
3381 if not ui.quiet:
3382 rst.append(header)
3382 rst.append(header)
3383 fns = sorted(h)
3383 fns = sorted(h)
3384 for f in fns:
3384 for f in fns:
3385 if ui.verbose:
3385 if ui.verbose:
3386 commands = cmds[f].replace("|",", ")
3386 commands = cmds[f].replace("|",", ")
3387 rst.append(" :%s: %s\n" % (commands, h[f]))
3387 rst.append(" :%s: %s\n" % (commands, h[f]))
3388 else:
3388 else:
3389 rst.append(' :%s: %s\n' % (f, h[f]))
3389 rst.append(' :%s: %s\n' % (f, h[f]))
3390
3390
3391 if not name:
3391 if not name:
3392 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3392 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3393 if exts:
3393 if exts:
3394 rst.append('\n')
3394 rst.append('\n')
3395 rst.extend(exts)
3395 rst.extend(exts)
3396
3396
3397 rst.append(_("\nadditional help topics:\n\n"))
3397 rst.append(_("\nadditional help topics:\n\n"))
3398 topics = []
3398 topics = []
3399 for names, header, doc in help.helptable:
3399 for names, header, doc in help.helptable:
3400 topics.append((names[0], header))
3400 topics.append((names[0], header))
3401 for t, desc in topics:
3401 for t, desc in topics:
3402 rst.append(" :%s: %s\n" % (t, desc))
3402 rst.append(" :%s: %s\n" % (t, desc))
3403
3403
3404 optlist = []
3404 optlist = []
3405 if not ui.quiet:
3405 if not ui.quiet:
3406 if ui.verbose:
3406 if ui.verbose:
3407 optlist.append((_("global options:"), globalopts))
3407 optlist.append((_("global options:"), globalopts))
3408 if name == 'shortlist':
3408 if name == 'shortlist':
3409 optlist.append((_('use "hg help" for the full list '
3409 optlist.append((_('use "hg help" for the full list '
3410 'of commands'), ()))
3410 'of commands'), ()))
3411 else:
3411 else:
3412 if name == 'shortlist':
3412 if name == 'shortlist':
3413 msg = _('use "hg help" for the full list of commands '
3413 msg = _('use "hg help" for the full list of commands '
3414 'or "hg -v" for details')
3414 'or "hg -v" for details')
3415 elif name and not full:
3415 elif name and not full:
3416 msg = _('use "hg help %s" to show the full help '
3416 msg = _('use "hg help %s" to show the full help '
3417 'text') % name
3417 'text') % name
3418 else:
3418 else:
3419 msg = _('use "hg -v help%s" to show builtin aliases and '
3419 msg = _('use "hg -v help%s" to show builtin aliases and '
3420 'global options') % (name and " " + name or "")
3420 'global options') % (name and " " + name or "")
3421 optlist.append((msg, ()))
3421 optlist.append((msg, ()))
3422
3422
3423 if optlist:
3423 if optlist:
3424 for title, options in optlist:
3424 for title, options in optlist:
3425 rst.append('\n%s\n' % title)
3425 rst.append('\n%s\n' % title)
3426 if options:
3426 if options:
3427 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3427 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3428 return rst
3428 return rst
3429
3429
3430 def helptopic(name):
3430 def helptopic(name):
3431 for names, header, doc in help.helptable:
3431 for names, header, doc in help.helptable:
3432 if name in names:
3432 if name in names:
3433 break
3433 break
3434 else:
3434 else:
3435 raise error.UnknownCommand(name)
3435 raise error.UnknownCommand(name)
3436
3436
3437 rst = ["%s\n\n" % header]
3437 rst = ["%s\n\n" % header]
3438 # description
3438 # description
3439 if not doc:
3439 if not doc:
3440 rst.append(" %s\n" % _("(no help text available)"))
3440 rst.append(" %s\n" % _("(no help text available)"))
3441 if util.safehasattr(doc, '__call__'):
3441 if util.safehasattr(doc, '__call__'):
3442 rst += [" %s\n" % l for l in doc().splitlines()]
3442 rst += [" %s\n" % l for l in doc().splitlines()]
3443
3443
3444 if not ui.verbose:
3444 if not ui.verbose:
3445 omitted = (_('use "hg help -v %s" to show more complete help') %
3445 omitted = (_('use "hg help -v %s" to show more complete help') %
3446 name)
3446 name)
3447 help.indicateomitted(rst, omitted)
3447 help.indicateomitted(rst, omitted)
3448
3448
3449 try:
3449 try:
3450 cmdutil.findcmd(name, table)
3450 cmdutil.findcmd(name, table)
3451 rst.append(_('\nuse "hg help -c %s" to see help for '
3451 rst.append(_('\nuse "hg help -c %s" to see help for '
3452 'the %s command\n') % (name, name))
3452 'the %s command\n') % (name, name))
3453 except error.UnknownCommand:
3453 except error.UnknownCommand:
3454 pass
3454 pass
3455 return rst
3455 return rst
3456
3456
3457 def helpext(name):
3457 def helpext(name):
3458 try:
3458 try:
3459 mod = extensions.find(name)
3459 mod = extensions.find(name)
3460 doc = gettext(mod.__doc__) or _('no help text available')
3460 doc = gettext(mod.__doc__) or _('no help text available')
3461 except KeyError:
3461 except KeyError:
3462 mod = None
3462 mod = None
3463 doc = extensions.disabledext(name)
3463 doc = extensions.disabledext(name)
3464 if not doc:
3464 if not doc:
3465 raise error.UnknownCommand(name)
3465 raise error.UnknownCommand(name)
3466
3466
3467 if '\n' not in doc:
3467 if '\n' not in doc:
3468 head, tail = doc, ""
3468 head, tail = doc, ""
3469 else:
3469 else:
3470 head, tail = doc.split('\n', 1)
3470 head, tail = doc.split('\n', 1)
3471 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3471 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3472 if tail:
3472 if tail:
3473 rst.extend(tail.splitlines(True))
3473 rst.extend(tail.splitlines(True))
3474 rst.append('\n')
3474 rst.append('\n')
3475
3475
3476 if not ui.verbose:
3476 if not ui.verbose:
3477 omitted = (_('use "hg help -v %s" to show more complete help') %
3477 omitted = (_('use "hg help -v %s" to show more complete help') %
3478 name)
3478 name)
3479 help.indicateomitted(rst, omitted)
3479 help.indicateomitted(rst, omitted)
3480
3480
3481 if mod:
3481 if mod:
3482 try:
3482 try:
3483 ct = mod.cmdtable
3483 ct = mod.cmdtable
3484 except AttributeError:
3484 except AttributeError:
3485 ct = {}
3485 ct = {}
3486 modcmds = set([c.split('|', 1)[0] for c in ct])
3486 modcmds = set([c.split('|', 1)[0] for c in ct])
3487 rst.extend(helplist(modcmds.__contains__))
3487 rst.extend(helplist(modcmds.__contains__))
3488 else:
3488 else:
3489 rst.append(_('use "hg help extensions" for information on enabling '
3489 rst.append(_('use "hg help extensions" for information on enabling '
3490 'extensions\n'))
3490 'extensions\n'))
3491 return rst
3491 return rst
3492
3492
3493 def helpextcmd(name):
3493 def helpextcmd(name):
3494 cmd, ext, mod = extensions.disabledcmd(ui, name,
3494 cmd, ext, mod = extensions.disabledcmd(ui, name,
3495 ui.configbool('ui', 'strict'))
3495 ui.configbool('ui', 'strict'))
3496 doc = gettext(mod.__doc__).splitlines()[0]
3496 doc = gettext(mod.__doc__).splitlines()[0]
3497
3497
3498 rst = help.listexts(_("'%s' is provided by the following "
3498 rst = help.listexts(_("'%s' is provided by the following "
3499 "extension:") % cmd, {ext: doc}, indent=4)
3499 "extension:") % cmd, {ext: doc}, indent=4)
3500 rst.append('\n')
3500 rst.append('\n')
3501 rst.append(_('use "hg help extensions" for information on enabling '
3501 rst.append(_('use "hg help extensions" for information on enabling '
3502 'extensions\n'))
3502 'extensions\n'))
3503 return rst
3503 return rst
3504
3504
3505
3505
3506 rst = []
3506 rst = []
3507 kw = opts.get('keyword')
3507 kw = opts.get('keyword')
3508 if kw:
3508 if kw:
3509 matches = help.topicmatch(kw)
3509 matches = help.topicmatch(kw)
3510 for t, title in (('topics', _('Topics')),
3510 for t, title in (('topics', _('Topics')),
3511 ('commands', _('Commands')),
3511 ('commands', _('Commands')),
3512 ('extensions', _('Extensions')),
3512 ('extensions', _('Extensions')),
3513 ('extensioncommands', _('Extension Commands'))):
3513 ('extensioncommands', _('Extension Commands'))):
3514 if matches[t]:
3514 if matches[t]:
3515 rst.append('%s:\n\n' % title)
3515 rst.append('%s:\n\n' % title)
3516 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3516 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3517 rst.append('\n')
3517 rst.append('\n')
3518 elif name and name != 'shortlist':
3518 elif name and name != 'shortlist':
3519 i = None
3519 i = None
3520 if unknowncmd:
3520 if unknowncmd:
3521 queries = (helpextcmd,)
3521 queries = (helpextcmd,)
3522 elif opts.get('extension'):
3522 elif opts.get('extension'):
3523 queries = (helpext,)
3523 queries = (helpext,)
3524 elif opts.get('command'):
3524 elif opts.get('command'):
3525 queries = (helpcmd,)
3525 queries = (helpcmd,)
3526 else:
3526 else:
3527 queries = (helptopic, helpcmd, helpext, helpextcmd)
3527 queries = (helptopic, helpcmd, helpext, helpextcmd)
3528 for f in queries:
3528 for f in queries:
3529 try:
3529 try:
3530 rst = f(name)
3530 rst = f(name)
3531 i = None
3531 i = None
3532 break
3532 break
3533 except error.UnknownCommand, inst:
3533 except error.UnknownCommand, inst:
3534 i = inst
3534 i = inst
3535 if i:
3535 if i:
3536 raise i
3536 raise i
3537 else:
3537 else:
3538 # program name
3538 # program name
3539 if not ui.quiet:
3539 if not ui.quiet:
3540 rst = [_("Mercurial Distributed SCM\n"), '\n']
3540 rst = [_("Mercurial Distributed SCM\n"), '\n']
3541 rst.extend(helplist())
3541 rst.extend(helplist())
3542
3542
3543 keep = ui.verbose and ['verbose'] or []
3543 keep = ui.verbose and ['verbose'] or []
3544 text = ''.join(rst)
3544 text = ''.join(rst)
3545 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3545 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3546 if 'verbose' in pruned:
3546 if 'verbose' in pruned:
3547 keep.append('omitted')
3547 keep.append('omitted')
3548 else:
3548 else:
3549 keep.append('notomitted')
3549 keep.append('notomitted')
3550 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3550 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3551 ui.write(formatted)
3551 ui.write(formatted)
3552
3552
3553
3553
3554 @command('identify|id',
3554 @command('identify|id',
3555 [('r', 'rev', '',
3555 [('r', 'rev', '',
3556 _('identify the specified revision'), _('REV')),
3556 _('identify the specified revision'), _('REV')),
3557 ('n', 'num', None, _('show local revision number')),
3557 ('n', 'num', None, _('show local revision number')),
3558 ('i', 'id', None, _('show global revision id')),
3558 ('i', 'id', None, _('show global revision id')),
3559 ('b', 'branch', None, _('show branch')),
3559 ('b', 'branch', None, _('show branch')),
3560 ('t', 'tags', None, _('show tags')),
3560 ('t', 'tags', None, _('show tags')),
3561 ('B', 'bookmarks', None, _('show bookmarks')),
3561 ('B', 'bookmarks', None, _('show bookmarks')),
3562 ] + remoteopts,
3562 ] + remoteopts,
3563 _('[-nibtB] [-r REV] [SOURCE]'))
3563 _('[-nibtB] [-r REV] [SOURCE]'))
3564 def identify(ui, repo, source=None, rev=None,
3564 def identify(ui, repo, source=None, rev=None,
3565 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3565 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3566 """identify the working copy or specified revision
3566 """identify the working copy or specified revision
3567
3567
3568 Print a summary identifying the repository state at REV using one or
3568 Print a summary identifying the repository state at REV using one or
3569 two parent hash identifiers, followed by a "+" if the working
3569 two parent hash identifiers, followed by a "+" if the working
3570 directory has uncommitted changes, the branch name (if not default),
3570 directory has uncommitted changes, the branch name (if not default),
3571 a list of tags, and a list of bookmarks.
3571 a list of tags, and a list of bookmarks.
3572
3572
3573 When REV is not given, print a summary of the current state of the
3573 When REV is not given, print a summary of the current state of the
3574 repository.
3574 repository.
3575
3575
3576 Specifying a path to a repository root or Mercurial bundle will
3576 Specifying a path to a repository root or Mercurial bundle will
3577 cause lookup to operate on that repository/bundle.
3577 cause lookup to operate on that repository/bundle.
3578
3578
3579 .. container:: verbose
3579 .. container:: verbose
3580
3580
3581 Examples:
3581 Examples:
3582
3582
3583 - generate a build identifier for the working directory::
3583 - generate a build identifier for the working directory::
3584
3584
3585 hg id --id > build-id.dat
3585 hg id --id > build-id.dat
3586
3586
3587 - find the revision corresponding to a tag::
3587 - find the revision corresponding to a tag::
3588
3588
3589 hg id -n -r 1.3
3589 hg id -n -r 1.3
3590
3590
3591 - check the most recent revision of a remote repository::
3591 - check the most recent revision of a remote repository::
3592
3592
3593 hg id -r tip http://selenic.com/hg/
3593 hg id -r tip http://selenic.com/hg/
3594
3594
3595 Returns 0 if successful.
3595 Returns 0 if successful.
3596 """
3596 """
3597
3597
3598 if not repo and not source:
3598 if not repo and not source:
3599 raise util.Abort(_("there is no Mercurial repository here "
3599 raise util.Abort(_("there is no Mercurial repository here "
3600 "(.hg not found)"))
3600 "(.hg not found)"))
3601
3601
3602 hexfunc = ui.debugflag and hex or short
3602 hexfunc = ui.debugflag and hex or short
3603 default = not (num or id or branch or tags or bookmarks)
3603 default = not (num or id or branch or tags or bookmarks)
3604 output = []
3604 output = []
3605 revs = []
3605 revs = []
3606
3606
3607 if source:
3607 if source:
3608 source, branches = hg.parseurl(ui.expandpath(source))
3608 source, branches = hg.parseurl(ui.expandpath(source))
3609 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3609 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3610 repo = peer.local()
3610 repo = peer.local()
3611 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3611 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3612
3612
3613 if not repo:
3613 if not repo:
3614 if num or branch or tags:
3614 if num or branch or tags:
3615 raise util.Abort(
3615 raise util.Abort(
3616 _("can't query remote revision number, branch, or tags"))
3616 _("can't query remote revision number, branch, or tags"))
3617 if not rev and revs:
3617 if not rev and revs:
3618 rev = revs[0]
3618 rev = revs[0]
3619 if not rev:
3619 if not rev:
3620 rev = "tip"
3620 rev = "tip"
3621
3621
3622 remoterev = peer.lookup(rev)
3622 remoterev = peer.lookup(rev)
3623 if default or id:
3623 if default or id:
3624 output = [hexfunc(remoterev)]
3624 output = [hexfunc(remoterev)]
3625
3625
3626 def getbms():
3626 def getbms():
3627 bms = []
3627 bms = []
3628
3628
3629 if 'bookmarks' in peer.listkeys('namespaces'):
3629 if 'bookmarks' in peer.listkeys('namespaces'):
3630 hexremoterev = hex(remoterev)
3630 hexremoterev = hex(remoterev)
3631 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3631 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3632 if bmr == hexremoterev]
3632 if bmr == hexremoterev]
3633
3633
3634 return bms
3634 return bms
3635
3635
3636 if bookmarks:
3636 if bookmarks:
3637 output.extend(getbms())
3637 output.extend(getbms())
3638 elif default and not ui.quiet:
3638 elif default and not ui.quiet:
3639 # multiple bookmarks for a single parent separated by '/'
3639 # multiple bookmarks for a single parent separated by '/'
3640 bm = '/'.join(getbms())
3640 bm = '/'.join(getbms())
3641 if bm:
3641 if bm:
3642 output.append(bm)
3642 output.append(bm)
3643 else:
3643 else:
3644 if not rev:
3644 if not rev:
3645 ctx = repo[None]
3645 ctx = repo[None]
3646 parents = ctx.parents()
3646 parents = ctx.parents()
3647 changed = ""
3647 changed = ""
3648 if default or id or num:
3648 if default or id or num:
3649 if (util.any(repo.status())
3649 if (util.any(repo.status())
3650 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3650 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3651 changed = '+'
3651 changed = '+'
3652 if default or id:
3652 if default or id:
3653 output = ["%s%s" %
3653 output = ["%s%s" %
3654 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3654 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3655 if num:
3655 if num:
3656 output.append("%s%s" %
3656 output.append("%s%s" %
3657 ('+'.join([str(p.rev()) for p in parents]), changed))
3657 ('+'.join([str(p.rev()) for p in parents]), changed))
3658 else:
3658 else:
3659 ctx = scmutil.revsingle(repo, rev)
3659 ctx = scmutil.revsingle(repo, rev)
3660 if default or id:
3660 if default or id:
3661 output = [hexfunc(ctx.node())]
3661 output = [hexfunc(ctx.node())]
3662 if num:
3662 if num:
3663 output.append(str(ctx.rev()))
3663 output.append(str(ctx.rev()))
3664
3664
3665 if default and not ui.quiet:
3665 if default and not ui.quiet:
3666 b = ctx.branch()
3666 b = ctx.branch()
3667 if b != 'default':
3667 if b != 'default':
3668 output.append("(%s)" % b)
3668 output.append("(%s)" % b)
3669
3669
3670 # multiple tags for a single parent separated by '/'
3670 # multiple tags for a single parent separated by '/'
3671 t = '/'.join(ctx.tags())
3671 t = '/'.join(ctx.tags())
3672 if t:
3672 if t:
3673 output.append(t)
3673 output.append(t)
3674
3674
3675 # multiple bookmarks for a single parent separated by '/'
3675 # multiple bookmarks for a single parent separated by '/'
3676 bm = '/'.join(ctx.bookmarks())
3676 bm = '/'.join(ctx.bookmarks())
3677 if bm:
3677 if bm:
3678 output.append(bm)
3678 output.append(bm)
3679 else:
3679 else:
3680 if branch:
3680 if branch:
3681 output.append(ctx.branch())
3681 output.append(ctx.branch())
3682
3682
3683 if tags:
3683 if tags:
3684 output.extend(ctx.tags())
3684 output.extend(ctx.tags())
3685
3685
3686 if bookmarks:
3686 if bookmarks:
3687 output.extend(ctx.bookmarks())
3687 output.extend(ctx.bookmarks())
3688
3688
3689 ui.write("%s\n" % ' '.join(output))
3689 ui.write("%s\n" % ' '.join(output))
3690
3690
3691 @command('import|patch',
3691 @command('import|patch',
3692 [('p', 'strip', 1,
3692 [('p', 'strip', 1,
3693 _('directory strip option for patch. This has the same '
3693 _('directory strip option for patch. This has the same '
3694 'meaning as the corresponding patch option'), _('NUM')),
3694 'meaning as the corresponding patch option'), _('NUM')),
3695 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3695 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3696 ('e', 'edit', False, _('invoke editor on commit messages')),
3696 ('e', 'edit', False, _('invoke editor on commit messages')),
3697 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3697 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3698 ('', 'no-commit', None,
3698 ('', 'no-commit', None,
3699 _("don't commit, just update the working directory")),
3699 _("don't commit, just update the working directory")),
3700 ('', 'bypass', None,
3700 ('', 'bypass', None,
3701 _("apply patch without touching the working directory")),
3701 _("apply patch without touching the working directory")),
3702 ('', 'exact', None,
3702 ('', 'exact', None,
3703 _('apply patch to the nodes from which it was generated')),
3703 _('apply patch to the nodes from which it was generated')),
3704 ('', 'import-branch', None,
3704 ('', 'import-branch', None,
3705 _('use any branch information in patch (implied by --exact)'))] +
3705 _('use any branch information in patch (implied by --exact)'))] +
3706 commitopts + commitopts2 + similarityopts,
3706 commitopts + commitopts2 + similarityopts,
3707 _('[OPTION]... PATCH...'))
3707 _('[OPTION]... PATCH...'))
3708 def import_(ui, repo, patch1=None, *patches, **opts):
3708 def import_(ui, repo, patch1=None, *patches, **opts):
3709 """import an ordered set of patches
3709 """import an ordered set of patches
3710
3710
3711 Import a list of patches and commit them individually (unless
3711 Import a list of patches and commit them individually (unless
3712 --no-commit is specified).
3712 --no-commit is specified).
3713
3713
3714 If there are outstanding changes in the working directory, import
3714 If there are outstanding changes in the working directory, import
3715 will abort unless given the -f/--force flag.
3715 will abort unless given the -f/--force flag.
3716
3716
3717 You can import a patch straight from a mail message. Even patches
3717 You can import a patch straight from a mail message. Even patches
3718 as attachments work (to use the body part, it must have type
3718 as attachments work (to use the body part, it must have type
3719 text/plain or text/x-patch). From and Subject headers of email
3719 text/plain or text/x-patch). From and Subject headers of email
3720 message are used as default committer and commit message. All
3720 message are used as default committer and commit message. All
3721 text/plain body parts before first diff are added to commit
3721 text/plain body parts before first diff are added to commit
3722 message.
3722 message.
3723
3723
3724 If the imported patch was generated by :hg:`export`, user and
3724 If the imported patch was generated by :hg:`export`, user and
3725 description from patch override values from message headers and
3725 description from patch override values from message headers and
3726 body. Values given on command line with -m/--message and -u/--user
3726 body. Values given on command line with -m/--message and -u/--user
3727 override these.
3727 override these.
3728
3728
3729 If --exact is specified, import will set the working directory to
3729 If --exact is specified, import will set the working directory to
3730 the parent of each patch before applying it, and will abort if the
3730 the parent of each patch before applying it, and will abort if the
3731 resulting changeset has a different ID than the one recorded in
3731 resulting changeset has a different ID than the one recorded in
3732 the patch. This may happen due to character set problems or other
3732 the patch. This may happen due to character set problems or other
3733 deficiencies in the text patch format.
3733 deficiencies in the text patch format.
3734
3734
3735 Use --bypass to apply and commit patches directly to the
3735 Use --bypass to apply and commit patches directly to the
3736 repository, not touching the working directory. Without --exact,
3736 repository, not touching the working directory. Without --exact,
3737 patches will be applied on top of the working directory parent
3737 patches will be applied on top of the working directory parent
3738 revision.
3738 revision.
3739
3739
3740 With -s/--similarity, hg will attempt to discover renames and
3740 With -s/--similarity, hg will attempt to discover renames and
3741 copies in the patch in the same way as :hg:`addremove`.
3741 copies in the patch in the same way as :hg:`addremove`.
3742
3742
3743 To read a patch from standard input, use "-" as the patch name. If
3743 To read a patch from standard input, use "-" as the patch name. If
3744 a URL is specified, the patch will be downloaded from it.
3744 a URL is specified, the patch will be downloaded from it.
3745 See :hg:`help dates` for a list of formats valid for -d/--date.
3745 See :hg:`help dates` for a list of formats valid for -d/--date.
3746
3746
3747 .. container:: verbose
3747 .. container:: verbose
3748
3748
3749 Examples:
3749 Examples:
3750
3750
3751 - import a traditional patch from a website and detect renames::
3751 - import a traditional patch from a website and detect renames::
3752
3752
3753 hg import -s 80 http://example.com/bugfix.patch
3753 hg import -s 80 http://example.com/bugfix.patch
3754
3754
3755 - import a changeset from an hgweb server::
3755 - import a changeset from an hgweb server::
3756
3756
3757 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3757 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3758
3758
3759 - import all the patches in an Unix-style mbox::
3759 - import all the patches in an Unix-style mbox::
3760
3760
3761 hg import incoming-patches.mbox
3761 hg import incoming-patches.mbox
3762
3762
3763 - attempt to exactly restore an exported changeset (not always
3763 - attempt to exactly restore an exported changeset (not always
3764 possible)::
3764 possible)::
3765
3765
3766 hg import --exact proposed-fix.patch
3766 hg import --exact proposed-fix.patch
3767
3767
3768 Returns 0 on success.
3768 Returns 0 on success.
3769 """
3769 """
3770
3770
3771 if not patch1:
3771 if not patch1:
3772 raise util.Abort(_('need at least one patch to import'))
3772 raise util.Abort(_('need at least one patch to import'))
3773
3773
3774 patches = (patch1,) + patches
3774 patches = (patch1,) + patches
3775
3775
3776 date = opts.get('date')
3776 date = opts.get('date')
3777 if date:
3777 if date:
3778 opts['date'] = util.parsedate(date)
3778 opts['date'] = util.parsedate(date)
3779
3779
3780 editor = cmdutil.commiteditor
3780 editor = cmdutil.commiteditor
3781 if opts.get('edit'):
3781 if opts.get('edit'):
3782 editor = cmdutil.commitforceeditor
3782 editor = cmdutil.commitforceeditor
3783
3783
3784 update = not opts.get('bypass')
3784 update = not opts.get('bypass')
3785 if not update and opts.get('no_commit'):
3785 if not update and opts.get('no_commit'):
3786 raise util.Abort(_('cannot use --no-commit with --bypass'))
3786 raise util.Abort(_('cannot use --no-commit with --bypass'))
3787 try:
3787 try:
3788 sim = float(opts.get('similarity') or 0)
3788 sim = float(opts.get('similarity') or 0)
3789 except ValueError:
3789 except ValueError:
3790 raise util.Abort(_('similarity must be a number'))
3790 raise util.Abort(_('similarity must be a number'))
3791 if sim < 0 or sim > 100:
3791 if sim < 0 or sim > 100:
3792 raise util.Abort(_('similarity must be between 0 and 100'))
3792 raise util.Abort(_('similarity must be between 0 and 100'))
3793 if sim and not update:
3793 if sim and not update:
3794 raise util.Abort(_('cannot use --similarity with --bypass'))
3794 raise util.Abort(_('cannot use --similarity with --bypass'))
3795
3795
3796 if (opts.get('exact') or not opts.get('force')) and update:
3796 if (opts.get('exact') or not opts.get('force')) and update:
3797 cmdutil.bailifchanged(repo)
3797 cmdutil.bailifchanged(repo)
3798
3798
3799 base = opts["base"]
3799 base = opts["base"]
3800 strip = opts["strip"]
3800 strip = opts["strip"]
3801 wlock = lock = tr = None
3801 wlock = lock = tr = None
3802 msgs = []
3802 msgs = []
3803
3803
3804 def checkexact(repo, n, nodeid):
3804 def checkexact(repo, n, nodeid):
3805 if opts.get('exact') and hex(n) != nodeid:
3805 if opts.get('exact') and hex(n) != nodeid:
3806 repo.rollback()
3806 repo.rollback()
3807 raise util.Abort(_('patch is damaged or loses information'))
3807 raise util.Abort(_('patch is damaged or loses information'))
3808
3808
3809 def tryone(ui, hunk, parents):
3809 def tryone(ui, hunk, parents):
3810 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3810 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3811 patch.extract(ui, hunk)
3811 patch.extract(ui, hunk)
3812
3812
3813 if not tmpname:
3813 if not tmpname:
3814 return (None, None)
3814 return (None, None)
3815 msg = _('applied to working directory')
3815 msg = _('applied to working directory')
3816
3816
3817 try:
3817 try:
3818 cmdline_message = cmdutil.logmessage(ui, opts)
3818 cmdline_message = cmdutil.logmessage(ui, opts)
3819 if cmdline_message:
3819 if cmdline_message:
3820 # pickup the cmdline msg
3820 # pickup the cmdline msg
3821 message = cmdline_message
3821 message = cmdline_message
3822 elif message:
3822 elif message:
3823 # pickup the patch msg
3823 # pickup the patch msg
3824 message = message.strip()
3824 message = message.strip()
3825 else:
3825 else:
3826 # launch the editor
3826 # launch the editor
3827 message = None
3827 message = None
3828 ui.debug('message:\n%s\n' % message)
3828 ui.debug('message:\n%s\n' % message)
3829
3829
3830 if len(parents) == 1:
3830 if len(parents) == 1:
3831 parents.append(repo[nullid])
3831 parents.append(repo[nullid])
3832 if opts.get('exact'):
3832 if opts.get('exact'):
3833 if not nodeid or not p1:
3833 if not nodeid or not p1:
3834 raise util.Abort(_('not a Mercurial patch'))
3834 raise util.Abort(_('not a Mercurial patch'))
3835 p1 = repo[p1]
3835 p1 = repo[p1]
3836 p2 = repo[p2 or nullid]
3836 p2 = repo[p2 or nullid]
3837 elif p2:
3837 elif p2:
3838 try:
3838 try:
3839 p1 = repo[p1]
3839 p1 = repo[p1]
3840 p2 = repo[p2]
3840 p2 = repo[p2]
3841 # Without any options, consider p2 only if the
3841 # Without any options, consider p2 only if the
3842 # patch is being applied on top of the recorded
3842 # patch is being applied on top of the recorded
3843 # first parent.
3843 # first parent.
3844 if p1 != parents[0]:
3844 if p1 != parents[0]:
3845 p1 = parents[0]
3845 p1 = parents[0]
3846 p2 = repo[nullid]
3846 p2 = repo[nullid]
3847 except error.RepoError:
3847 except error.RepoError:
3848 p1, p2 = parents
3848 p1, p2 = parents
3849 else:
3849 else:
3850 p1, p2 = parents
3850 p1, p2 = parents
3851
3851
3852 n = None
3852 n = None
3853 if update:
3853 if update:
3854 if p1 != parents[0]:
3854 if p1 != parents[0]:
3855 hg.clean(repo, p1.node())
3855 hg.clean(repo, p1.node())
3856 if p2 != parents[1]:
3856 if p2 != parents[1]:
3857 repo.setparents(p1.node(), p2.node())
3857 repo.setparents(p1.node(), p2.node())
3858
3858
3859 if opts.get('exact') or opts.get('import_branch'):
3859 if opts.get('exact') or opts.get('import_branch'):
3860 repo.dirstate.setbranch(branch or 'default')
3860 repo.dirstate.setbranch(branch or 'default')
3861
3861
3862 files = set()
3862 files = set()
3863 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3863 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3864 eolmode=None, similarity=sim / 100.0)
3864 eolmode=None, similarity=sim / 100.0)
3865 files = list(files)
3865 files = list(files)
3866 if opts.get('no_commit'):
3866 if opts.get('no_commit'):
3867 if message:
3867 if message:
3868 msgs.append(message)
3868 msgs.append(message)
3869 else:
3869 else:
3870 if opts.get('exact') or p2:
3870 if opts.get('exact') or p2:
3871 # If you got here, you either use --force and know what
3871 # If you got here, you either use --force and know what
3872 # you are doing or used --exact or a merge patch while
3872 # you are doing or used --exact or a merge patch while
3873 # being updated to its first parent.
3873 # being updated to its first parent.
3874 m = None
3874 m = None
3875 else:
3875 else:
3876 m = scmutil.matchfiles(repo, files or [])
3876 m = scmutil.matchfiles(repo, files or [])
3877 n = repo.commit(message, opts.get('user') or user,
3877 n = repo.commit(message, opts.get('user') or user,
3878 opts.get('date') or date, match=m,
3878 opts.get('date') or date, match=m,
3879 editor=editor)
3879 editor=editor)
3880 checkexact(repo, n, nodeid)
3880 checkexact(repo, n, nodeid)
3881 else:
3881 else:
3882 if opts.get('exact') or opts.get('import_branch'):
3882 if opts.get('exact') or opts.get('import_branch'):
3883 branch = branch or 'default'
3883 branch = branch or 'default'
3884 else:
3884 else:
3885 branch = p1.branch()
3885 branch = p1.branch()
3886 store = patch.filestore()
3886 store = patch.filestore()
3887 try:
3887 try:
3888 files = set()
3888 files = set()
3889 try:
3889 try:
3890 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3890 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3891 files, eolmode=None)
3891 files, eolmode=None)
3892 except patch.PatchError, e:
3892 except patch.PatchError, e:
3893 raise util.Abort(str(e))
3893 raise util.Abort(str(e))
3894 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3894 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3895 message,
3895 message,
3896 opts.get('user') or user,
3896 opts.get('user') or user,
3897 opts.get('date') or date,
3897 opts.get('date') or date,
3898 branch, files, store,
3898 branch, files, store,
3899 editor=cmdutil.commiteditor)
3899 editor=cmdutil.commiteditor)
3900 repo.savecommitmessage(memctx.description())
3900 repo.savecommitmessage(memctx.description())
3901 n = memctx.commit()
3901 n = memctx.commit()
3902 checkexact(repo, n, nodeid)
3902 checkexact(repo, n, nodeid)
3903 finally:
3903 finally:
3904 store.close()
3904 store.close()
3905 if n:
3905 if n:
3906 # i18n: refers to a short changeset id
3906 # i18n: refers to a short changeset id
3907 msg = _('created %s') % short(n)
3907 msg = _('created %s') % short(n)
3908 return (msg, n)
3908 return (msg, n)
3909 finally:
3909 finally:
3910 os.unlink(tmpname)
3910 os.unlink(tmpname)
3911
3911
3912 try:
3912 try:
3913 try:
3913 try:
3914 wlock = repo.wlock()
3914 wlock = repo.wlock()
3915 if not opts.get('no_commit'):
3915 if not opts.get('no_commit'):
3916 lock = repo.lock()
3916 lock = repo.lock()
3917 tr = repo.transaction('import')
3917 tr = repo.transaction('import')
3918 parents = repo.parents()
3918 parents = repo.parents()
3919 for patchurl in patches:
3919 for patchurl in patches:
3920 if patchurl == '-':
3920 if patchurl == '-':
3921 ui.status(_('applying patch from stdin\n'))
3921 ui.status(_('applying patch from stdin\n'))
3922 patchfile = ui.fin
3922 patchfile = ui.fin
3923 patchurl = 'stdin' # for error message
3923 patchurl = 'stdin' # for error message
3924 else:
3924 else:
3925 patchurl = os.path.join(base, patchurl)
3925 patchurl = os.path.join(base, patchurl)
3926 ui.status(_('applying %s\n') % patchurl)
3926 ui.status(_('applying %s\n') % patchurl)
3927 patchfile = hg.openpath(ui, patchurl)
3927 patchfile = hg.openpath(ui, patchurl)
3928
3928
3929 haspatch = False
3929 haspatch = False
3930 for hunk in patch.split(patchfile):
3930 for hunk in patch.split(patchfile):
3931 (msg, node) = tryone(ui, hunk, parents)
3931 (msg, node) = tryone(ui, hunk, parents)
3932 if msg:
3932 if msg:
3933 haspatch = True
3933 haspatch = True
3934 ui.note(msg + '\n')
3934 ui.note(msg + '\n')
3935 if update or opts.get('exact'):
3935 if update or opts.get('exact'):
3936 parents = repo.parents()
3936 parents = repo.parents()
3937 else:
3937 else:
3938 parents = [repo[node]]
3938 parents = [repo[node]]
3939
3939
3940 if not haspatch:
3940 if not haspatch:
3941 raise util.Abort(_('%s: no diffs found') % patchurl)
3941 raise util.Abort(_('%s: no diffs found') % patchurl)
3942
3942
3943 if tr:
3943 if tr:
3944 tr.close()
3944 tr.close()
3945 if msgs:
3945 if msgs:
3946 repo.savecommitmessage('\n* * *\n'.join(msgs))
3946 repo.savecommitmessage('\n* * *\n'.join(msgs))
3947 except: # re-raises
3947 except: # re-raises
3948 # wlock.release() indirectly calls dirstate.write(): since
3948 # wlock.release() indirectly calls dirstate.write(): since
3949 # we're crashing, we do not want to change the working dir
3949 # we're crashing, we do not want to change the working dir
3950 # parent after all, so make sure it writes nothing
3950 # parent after all, so make sure it writes nothing
3951 repo.dirstate.invalidate()
3951 repo.dirstate.invalidate()
3952 raise
3952 raise
3953 finally:
3953 finally:
3954 if tr:
3954 if tr:
3955 tr.release()
3955 tr.release()
3956 release(lock, wlock)
3956 release(lock, wlock)
3957
3957
3958 @command('incoming|in',
3958 @command('incoming|in',
3959 [('f', 'force', None,
3959 [('f', 'force', None,
3960 _('run even if remote repository is unrelated')),
3960 _('run even if remote repository is unrelated')),
3961 ('n', 'newest-first', None, _('show newest record first')),
3961 ('n', 'newest-first', None, _('show newest record first')),
3962 ('', 'bundle', '',
3962 ('', 'bundle', '',
3963 _('file to store the bundles into'), _('FILE')),
3963 _('file to store the bundles into'), _('FILE')),
3964 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3964 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3965 ('B', 'bookmarks', False, _("compare bookmarks")),
3965 ('B', 'bookmarks', False, _("compare bookmarks")),
3966 ('b', 'branch', [],
3966 ('b', 'branch', [],
3967 _('a specific branch you would like to pull'), _('BRANCH')),
3967 _('a specific branch you would like to pull'), _('BRANCH')),
3968 ] + logopts + remoteopts + subrepoopts,
3968 ] + logopts + remoteopts + subrepoopts,
3969 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3969 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3970 def incoming(ui, repo, source="default", **opts):
3970 def incoming(ui, repo, source="default", **opts):
3971 """show new changesets found in source
3971 """show new changesets found in source
3972
3972
3973 Show new changesets found in the specified path/URL or the default
3973 Show new changesets found in the specified path/URL or the default
3974 pull location. These are the changesets that would have been pulled
3974 pull location. These are the changesets that would have been pulled
3975 if a pull at the time you issued this command.
3975 if a pull at the time you issued this command.
3976
3976
3977 For remote repository, using --bundle avoids downloading the
3977 For remote repository, using --bundle avoids downloading the
3978 changesets twice if the incoming is followed by a pull.
3978 changesets twice if the incoming is followed by a pull.
3979
3979
3980 See pull for valid source format details.
3980 See pull for valid source format details.
3981
3981
3982 Returns 0 if there are incoming changes, 1 otherwise.
3982 Returns 0 if there are incoming changes, 1 otherwise.
3983 """
3983 """
3984 if opts.get('graph'):
3984 if opts.get('graph'):
3985 cmdutil.checkunsupportedgraphflags([], opts)
3985 cmdutil.checkunsupportedgraphflags([], opts)
3986 def display(other, chlist, displayer):
3986 def display(other, chlist, displayer):
3987 revdag = cmdutil.graphrevs(other, chlist, opts)
3987 revdag = cmdutil.graphrevs(other, chlist, opts)
3988 showparents = [ctx.node() for ctx in repo[None].parents()]
3988 showparents = [ctx.node() for ctx in repo[None].parents()]
3989 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3989 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3990 graphmod.asciiedges)
3990 graphmod.asciiedges)
3991
3991
3992 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3992 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3993 return 0
3993 return 0
3994
3994
3995 if opts.get('bundle') and opts.get('subrepos'):
3995 if opts.get('bundle') and opts.get('subrepos'):
3996 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3996 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3997
3997
3998 if opts.get('bookmarks'):
3998 if opts.get('bookmarks'):
3999 source, branches = hg.parseurl(ui.expandpath(source),
3999 source, branches = hg.parseurl(ui.expandpath(source),
4000 opts.get('branch'))
4000 opts.get('branch'))
4001 other = hg.peer(repo, opts, source)
4001 other = hg.peer(repo, opts, source)
4002 if 'bookmarks' not in other.listkeys('namespaces'):
4002 if 'bookmarks' not in other.listkeys('namespaces'):
4003 ui.warn(_("remote doesn't support bookmarks\n"))
4003 ui.warn(_("remote doesn't support bookmarks\n"))
4004 return 0
4004 return 0
4005 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4005 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4006 return bookmarks.diff(ui, repo, other)
4006 return bookmarks.diff(ui, repo, other)
4007
4007
4008 repo._subtoppath = ui.expandpath(source)
4008 repo._subtoppath = ui.expandpath(source)
4009 try:
4009 try:
4010 return hg.incoming(ui, repo, source, opts)
4010 return hg.incoming(ui, repo, source, opts)
4011 finally:
4011 finally:
4012 del repo._subtoppath
4012 del repo._subtoppath
4013
4013
4014
4014
4015 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4015 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4016 def init(ui, dest=".", **opts):
4016 def init(ui, dest=".", **opts):
4017 """create a new repository in the given directory
4017 """create a new repository in the given directory
4018
4018
4019 Initialize a new repository in the given directory. If the given
4019 Initialize a new repository in the given directory. If the given
4020 directory does not exist, it will be created.
4020 directory does not exist, it will be created.
4021
4021
4022 If no directory is given, the current directory is used.
4022 If no directory is given, the current directory is used.
4023
4023
4024 It is possible to specify an ``ssh://`` URL as the destination.
4024 It is possible to specify an ``ssh://`` URL as the destination.
4025 See :hg:`help urls` for more information.
4025 See :hg:`help urls` for more information.
4026
4026
4027 Returns 0 on success.
4027 Returns 0 on success.
4028 """
4028 """
4029 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4029 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4030
4030
4031 @command('locate',
4031 @command('locate',
4032 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4032 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4033 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4033 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4034 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4034 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4035 ] + walkopts,
4035 ] + walkopts,
4036 _('[OPTION]... [PATTERN]...'))
4036 _('[OPTION]... [PATTERN]...'))
4037 def locate(ui, repo, *pats, **opts):
4037 def locate(ui, repo, *pats, **opts):
4038 """locate files matching specific patterns
4038 """locate files matching specific patterns
4039
4039
4040 Print files under Mercurial control in the working directory whose
4040 Print files under Mercurial control in the working directory whose
4041 names match the given patterns.
4041 names match the given patterns.
4042
4042
4043 By default, this command searches all directories in the working
4043 By default, this command searches all directories in the working
4044 directory. To search just the current directory and its
4044 directory. To search just the current directory and its
4045 subdirectories, use "--include .".
4045 subdirectories, use "--include .".
4046
4046
4047 If no patterns are given to match, this command prints the names
4047 If no patterns are given to match, this command prints the names
4048 of all files under Mercurial control in the working directory.
4048 of all files under Mercurial control in the working directory.
4049
4049
4050 If you want to feed the output of this command into the "xargs"
4050 If you want to feed the output of this command into the "xargs"
4051 command, use the -0 option to both this command and "xargs". This
4051 command, use the -0 option to both this command and "xargs". This
4052 will avoid the problem of "xargs" treating single filenames that
4052 will avoid the problem of "xargs" treating single filenames that
4053 contain whitespace as multiple filenames.
4053 contain whitespace as multiple filenames.
4054
4054
4055 Returns 0 if a match is found, 1 otherwise.
4055 Returns 0 if a match is found, 1 otherwise.
4056 """
4056 """
4057 end = opts.get('print0') and '\0' or '\n'
4057 end = opts.get('print0') and '\0' or '\n'
4058 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4058 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4059
4059
4060 ret = 1
4060 ret = 1
4061 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4061 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4062 m.bad = lambda x, y: False
4062 m.bad = lambda x, y: False
4063 for abs in repo[rev].walk(m):
4063 for abs in repo[rev].walk(m):
4064 if not rev and abs not in repo.dirstate:
4064 if not rev and abs not in repo.dirstate:
4065 continue
4065 continue
4066 if opts.get('fullpath'):
4066 if opts.get('fullpath'):
4067 ui.write(repo.wjoin(abs), end)
4067 ui.write(repo.wjoin(abs), end)
4068 else:
4068 else:
4069 ui.write(((pats and m.rel(abs)) or abs), end)
4069 ui.write(((pats and m.rel(abs)) or abs), end)
4070 ret = 0
4070 ret = 0
4071
4071
4072 return ret
4072 return ret
4073
4073
4074 @command('^log|history',
4074 @command('^log|history',
4075 [('f', 'follow', None,
4075 [('f', 'follow', None,
4076 _('follow changeset history, or file history across copies and renames')),
4076 _('follow changeset history, or file history across copies and renames')),
4077 ('', 'follow-first', None,
4077 ('', 'follow-first', None,
4078 _('only follow the first parent of merge changesets (DEPRECATED)')),
4078 _('only follow the first parent of merge changesets (DEPRECATED)')),
4079 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4079 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4080 ('C', 'copies', None, _('show copied files')),
4080 ('C', 'copies', None, _('show copied files')),
4081 ('k', 'keyword', [],
4081 ('k', 'keyword', [],
4082 _('do case-insensitive search for a given text'), _('TEXT')),
4082 _('do case-insensitive search for a given text'), _('TEXT')),
4083 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4083 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4084 ('', 'removed', None, _('include revisions where files were removed')),
4084 ('', 'removed', None, _('include revisions where files were removed')),
4085 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4085 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4086 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4086 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4087 ('', 'only-branch', [],
4087 ('', 'only-branch', [],
4088 _('show only changesets within the given named branch (DEPRECATED)'),
4088 _('show only changesets within the given named branch (DEPRECATED)'),
4089 _('BRANCH')),
4089 _('BRANCH')),
4090 ('b', 'branch', [],
4090 ('b', 'branch', [],
4091 _('show changesets within the given named branch'), _('BRANCH')),
4091 _('show changesets within the given named branch'), _('BRANCH')),
4092 ('P', 'prune', [],
4092 ('P', 'prune', [],
4093 _('do not display revision or any of its ancestors'), _('REV')),
4093 _('do not display revision or any of its ancestors'), _('REV')),
4094 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4094 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4095 ] + logopts + walkopts,
4095 ] + logopts + walkopts,
4096 _('[OPTION]... [FILE]'))
4096 _('[OPTION]... [FILE]'))
4097 def log(ui, repo, *pats, **opts):
4097 def log(ui, repo, *pats, **opts):
4098 """show revision history of entire repository or files
4098 """show revision history of entire repository or files
4099
4099
4100 Print the revision history of the specified files or the entire
4100 Print the revision history of the specified files or the entire
4101 project.
4101 project.
4102
4102
4103 If no revision range is specified, the default is ``tip:0`` unless
4103 If no revision range is specified, the default is ``tip:0`` unless
4104 --follow is set, in which case the working directory parent is
4104 --follow is set, in which case the working directory parent is
4105 used as the starting revision.
4105 used as the starting revision.
4106
4106
4107 File history is shown without following rename or copy history of
4107 File history is shown without following rename or copy history of
4108 files. Use -f/--follow with a filename to follow history across
4108 files. Use -f/--follow with a filename to follow history across
4109 renames and copies. --follow without a filename will only show
4109 renames and copies. --follow without a filename will only show
4110 ancestors or descendants of the starting revision.
4110 ancestors or descendants of the starting revision.
4111
4111
4112 By default this command prints revision number and changeset id,
4112 By default this command prints revision number and changeset id,
4113 tags, non-trivial parents, user, date and time, and a summary for
4113 tags, non-trivial parents, user, date and time, and a summary for
4114 each commit. When the -v/--verbose switch is used, the list of
4114 each commit. When the -v/--verbose switch is used, the list of
4115 changed files and full commit message are shown.
4115 changed files and full commit message are shown.
4116
4116
4117 .. note::
4117 .. note::
4118 log -p/--patch may generate unexpected diff output for merge
4118 log -p/--patch may generate unexpected diff output for merge
4119 changesets, as it will only compare the merge changeset against
4119 changesets, as it will only compare the merge changeset against
4120 its first parent. Also, only files different from BOTH parents
4120 its first parent. Also, only files different from BOTH parents
4121 will appear in files:.
4121 will appear in files:.
4122
4122
4123 .. note::
4123 .. note::
4124 for performance reasons, log FILE may omit duplicate changes
4124 for performance reasons, log FILE may omit duplicate changes
4125 made on branches and will not show deletions. To see all
4125 made on branches and will not show deletions. To see all
4126 changes including duplicates and deletions, use the --removed
4126 changes including duplicates and deletions, use the --removed
4127 switch.
4127 switch.
4128
4128
4129 .. container:: verbose
4129 .. container:: verbose
4130
4130
4131 Some examples:
4131 Some examples:
4132
4132
4133 - changesets with full descriptions and file lists::
4133 - changesets with full descriptions and file lists::
4134
4134
4135 hg log -v
4135 hg log -v
4136
4136
4137 - changesets ancestral to the working directory::
4137 - changesets ancestral to the working directory::
4138
4138
4139 hg log -f
4139 hg log -f
4140
4140
4141 - last 10 commits on the current branch::
4141 - last 10 commits on the current branch::
4142
4142
4143 hg log -l 10 -b .
4143 hg log -l 10 -b .
4144
4144
4145 - changesets showing all modifications of a file, including removals::
4145 - changesets showing all modifications of a file, including removals::
4146
4146
4147 hg log --removed file.c
4147 hg log --removed file.c
4148
4148
4149 - all changesets that touch a directory, with diffs, excluding merges::
4149 - all changesets that touch a directory, with diffs, excluding merges::
4150
4150
4151 hg log -Mp lib/
4151 hg log -Mp lib/
4152
4152
4153 - all revision numbers that match a keyword::
4153 - all revision numbers that match a keyword::
4154
4154
4155 hg log -k bug --template "{rev}\\n"
4155 hg log -k bug --template "{rev}\\n"
4156
4156
4157 - check if a given changeset is included is a tagged release::
4157 - check if a given changeset is included is a tagged release::
4158
4158
4159 hg log -r "a21ccf and ancestor(1.9)"
4159 hg log -r "a21ccf and ancestor(1.9)"
4160
4160
4161 - find all changesets by some user in a date range::
4161 - find all changesets by some user in a date range::
4162
4162
4163 hg log -k alice -d "may 2008 to jul 2008"
4163 hg log -k alice -d "may 2008 to jul 2008"
4164
4164
4165 - summary of all changesets after the last tag::
4165 - summary of all changesets after the last tag::
4166
4166
4167 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4167 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4168
4168
4169 See :hg:`help dates` for a list of formats valid for -d/--date.
4169 See :hg:`help dates` for a list of formats valid for -d/--date.
4170
4170
4171 See :hg:`help revisions` and :hg:`help revsets` for more about
4171 See :hg:`help revisions` and :hg:`help revsets` for more about
4172 specifying revisions.
4172 specifying revisions.
4173
4173
4174 See :hg:`help templates` for more about pre-packaged styles and
4174 See :hg:`help templates` for more about pre-packaged styles and
4175 specifying custom templates.
4175 specifying custom templates.
4176
4176
4177 Returns 0 on success.
4177 Returns 0 on success.
4178 """
4178 """
4179 if opts.get('graph'):
4179 if opts.get('graph'):
4180 return cmdutil.graphlog(ui, repo, *pats, **opts)
4180 return cmdutil.graphlog(ui, repo, *pats, **opts)
4181
4181
4182 matchfn = scmutil.match(repo[None], pats, opts)
4182 matchfn = scmutil.match(repo[None], pats, opts)
4183 limit = cmdutil.loglimit(opts)
4183 limit = cmdutil.loglimit(opts)
4184 count = 0
4184 count = 0
4185
4185
4186 getrenamed, endrev = None, None
4186 getrenamed, endrev = None, None
4187 if opts.get('copies'):
4187 if opts.get('copies'):
4188 if opts.get('rev'):
4188 if opts.get('rev'):
4189 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4189 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4190 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4190 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4191
4191
4192 df = False
4192 df = False
4193 if opts.get("date"):
4193 if opts.get("date"):
4194 df = util.matchdate(opts["date"])
4194 df = util.matchdate(opts["date"])
4195
4195
4196 branches = opts.get('branch', []) + opts.get('only_branch', [])
4196 branches = opts.get('branch', []) + opts.get('only_branch', [])
4197 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4197 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4198
4198
4199 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4199 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4200 def prep(ctx, fns):
4200 def prep(ctx, fns):
4201 rev = ctx.rev()
4201 rev = ctx.rev()
4202 parents = [p for p in repo.changelog.parentrevs(rev)
4202 parents = [p for p in repo.changelog.parentrevs(rev)
4203 if p != nullrev]
4203 if p != nullrev]
4204 if opts.get('no_merges') and len(parents) == 2:
4204 if opts.get('no_merges') and len(parents) == 2:
4205 return
4205 return
4206 if opts.get('only_merges') and len(parents) != 2:
4206 if opts.get('only_merges') and len(parents) != 2:
4207 return
4207 return
4208 if opts.get('branch') and ctx.branch() not in opts['branch']:
4208 if opts.get('branch') and ctx.branch() not in opts['branch']:
4209 return
4209 return
4210 if not opts.get('hidden') and ctx.hidden():
4210 if not opts.get('hidden') and ctx.hidden():
4211 return
4211 return
4212 if df and not df(ctx.date()[0]):
4212 if df and not df(ctx.date()[0]):
4213 return
4213 return
4214
4214
4215 lower = encoding.lower
4215 lower = encoding.lower
4216 if opts.get('user'):
4216 if opts.get('user'):
4217 luser = lower(ctx.user())
4217 luser = lower(ctx.user())
4218 for k in [lower(x) for x in opts['user']]:
4218 for k in [lower(x) for x in opts['user']]:
4219 if (k in luser):
4219 if (k in luser):
4220 break
4220 break
4221 else:
4221 else:
4222 return
4222 return
4223 if opts.get('keyword'):
4223 if opts.get('keyword'):
4224 luser = lower(ctx.user())
4224 luser = lower(ctx.user())
4225 ldesc = lower(ctx.description())
4225 ldesc = lower(ctx.description())
4226 lfiles = lower(" ".join(ctx.files()))
4226 lfiles = lower(" ".join(ctx.files()))
4227 for k in [lower(x) for x in opts['keyword']]:
4227 for k in [lower(x) for x in opts['keyword']]:
4228 if (k in luser or k in ldesc or k in lfiles):
4228 if (k in luser or k in ldesc or k in lfiles):
4229 break
4229 break
4230 else:
4230 else:
4231 return
4231 return
4232
4232
4233 copies = None
4233 copies = None
4234 if getrenamed is not None and rev:
4234 if getrenamed is not None and rev:
4235 copies = []
4235 copies = []
4236 for fn in ctx.files():
4236 for fn in ctx.files():
4237 rename = getrenamed(fn, rev)
4237 rename = getrenamed(fn, rev)
4238 if rename:
4238 if rename:
4239 copies.append((fn, rename[0]))
4239 copies.append((fn, rename[0]))
4240
4240
4241 revmatchfn = None
4241 revmatchfn = None
4242 if opts.get('patch') or opts.get('stat'):
4242 if opts.get('patch') or opts.get('stat'):
4243 if opts.get('follow') or opts.get('follow_first'):
4243 if opts.get('follow') or opts.get('follow_first'):
4244 # note: this might be wrong when following through merges
4244 # note: this might be wrong when following through merges
4245 revmatchfn = scmutil.match(repo[None], fns, default='path')
4245 revmatchfn = scmutil.match(repo[None], fns, default='path')
4246 else:
4246 else:
4247 revmatchfn = matchfn
4247 revmatchfn = matchfn
4248
4248
4249 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4249 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4250
4250
4251 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4251 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4252 if count == limit:
4252 if count == limit:
4253 break
4253 break
4254 if displayer.flush(ctx.rev()):
4254 if displayer.flush(ctx.rev()):
4255 count += 1
4255 count += 1
4256 displayer.close()
4256 displayer.close()
4257
4257
4258 @command('manifest',
4258 @command('manifest',
4259 [('r', 'rev', '', _('revision to display'), _('REV')),
4259 [('r', 'rev', '', _('revision to display'), _('REV')),
4260 ('', 'all', False, _("list files from all revisions"))],
4260 ('', 'all', False, _("list files from all revisions"))],
4261 _('[-r REV]'))
4261 _('[-r REV]'))
4262 def manifest(ui, repo, node=None, rev=None, **opts):
4262 def manifest(ui, repo, node=None, rev=None, **opts):
4263 """output the current or given revision of the project manifest
4263 """output the current or given revision of the project manifest
4264
4264
4265 Print a list of version controlled files for the given revision.
4265 Print a list of version controlled files for the given revision.
4266 If no revision is given, the first parent of the working directory
4266 If no revision is given, the first parent of the working directory
4267 is used, or the null revision if no revision is checked out.
4267 is used, or the null revision if no revision is checked out.
4268
4268
4269 With -v, print file permissions, symlink and executable bits.
4269 With -v, print file permissions, symlink and executable bits.
4270 With --debug, print file revision hashes.
4270 With --debug, print file revision hashes.
4271
4271
4272 If option --all is specified, the list of all files from all revisions
4272 If option --all is specified, the list of all files from all revisions
4273 is printed. This includes deleted and renamed files.
4273 is printed. This includes deleted and renamed files.
4274
4274
4275 Returns 0 on success.
4275 Returns 0 on success.
4276 """
4276 """
4277
4277
4278 fm = ui.formatter('manifest', opts)
4278 fm = ui.formatter('manifest', opts)
4279
4279
4280 if opts.get('all'):
4280 if opts.get('all'):
4281 if rev or node:
4281 if rev or node:
4282 raise util.Abort(_("can't specify a revision with --all"))
4282 raise util.Abort(_("can't specify a revision with --all"))
4283
4283
4284 res = []
4284 res = []
4285 prefix = "data/"
4285 prefix = "data/"
4286 suffix = ".i"
4286 suffix = ".i"
4287 plen = len(prefix)
4287 plen = len(prefix)
4288 slen = len(suffix)
4288 slen = len(suffix)
4289 lock = repo.lock()
4289 lock = repo.lock()
4290 try:
4290 try:
4291 for fn, b, size in repo.store.datafiles():
4291 for fn, b, size in repo.store.datafiles():
4292 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4292 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4293 res.append(fn[plen:-slen])
4293 res.append(fn[plen:-slen])
4294 finally:
4294 finally:
4295 lock.release()
4295 lock.release()
4296 for f in res:
4296 for f in res:
4297 fm.startitem()
4297 fm.startitem()
4298 fm.write("path", '%s\n', f)
4298 fm.write("path", '%s\n', f)
4299 fm.end()
4299 fm.end()
4300 return
4300 return
4301
4301
4302 if rev and node:
4302 if rev and node:
4303 raise util.Abort(_("please specify just one revision"))
4303 raise util.Abort(_("please specify just one revision"))
4304
4304
4305 if not node:
4305 if not node:
4306 node = rev
4306 node = rev
4307
4307
4308 char = {'l': '@', 'x': '*', '': ''}
4308 char = {'l': '@', 'x': '*', '': ''}
4309 mode = {'l': '644', 'x': '755', '': '644'}
4309 mode = {'l': '644', 'x': '755', '': '644'}
4310 ctx = scmutil.revsingle(repo, node)
4310 ctx = scmutil.revsingle(repo, node)
4311 mf = ctx.manifest()
4311 mf = ctx.manifest()
4312 for f in ctx:
4312 for f in ctx:
4313 fm.startitem()
4313 fm.startitem()
4314 fl = ctx[f].flags()
4314 fl = ctx[f].flags()
4315 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4315 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4316 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4316 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4317 fm.write('path', '%s\n', f)
4317 fm.write('path', '%s\n', f)
4318 fm.end()
4318 fm.end()
4319
4319
4320 @command('^merge',
4320 @command('^merge',
4321 [('f', 'force', None, _('force a merge with outstanding changes')),
4321 [('f', 'force', None, _('force a merge with outstanding changes')),
4322 ('r', 'rev', '', _('revision to merge'), _('REV')),
4322 ('r', 'rev', '', _('revision to merge'), _('REV')),
4323 ('P', 'preview', None,
4323 ('P', 'preview', None,
4324 _('review revisions to merge (no merge is performed)'))
4324 _('review revisions to merge (no merge is performed)'))
4325 ] + mergetoolopts,
4325 ] + mergetoolopts,
4326 _('[-P] [-f] [[-r] REV]'))
4326 _('[-P] [-f] [[-r] REV]'))
4327 def merge(ui, repo, node=None, **opts):
4327 def merge(ui, repo, node=None, **opts):
4328 """merge working directory with another revision
4328 """merge working directory with another revision
4329
4329
4330 The current working directory is updated with all changes made in
4330 The current working directory is updated with all changes made in
4331 the requested revision since the last common predecessor revision.
4331 the requested revision since the last common predecessor revision.
4332
4332
4333 Files that changed between either parent are marked as changed for
4333 Files that changed between either parent are marked as changed for
4334 the next commit and a commit must be performed before any further
4334 the next commit and a commit must be performed before any further
4335 updates to the repository are allowed. The next commit will have
4335 updates to the repository are allowed. The next commit will have
4336 two parents.
4336 two parents.
4337
4337
4338 ``--tool`` can be used to specify the merge tool used for file
4338 ``--tool`` can be used to specify the merge tool used for file
4339 merges. It overrides the HGMERGE environment variable and your
4339 merges. It overrides the HGMERGE environment variable and your
4340 configuration files. See :hg:`help merge-tools` for options.
4340 configuration files. See :hg:`help merge-tools` for options.
4341
4341
4342 If no revision is specified, the working directory's parent is a
4342 If no revision is specified, the working directory's parent is a
4343 head revision, and the current branch contains exactly one other
4343 head revision, and the current branch contains exactly one other
4344 head, the other head is merged with by default. Otherwise, an
4344 head, the other head is merged with by default. Otherwise, an
4345 explicit revision with which to merge with must be provided.
4345 explicit revision with which to merge with must be provided.
4346
4346
4347 :hg:`resolve` must be used to resolve unresolved files.
4347 :hg:`resolve` must be used to resolve unresolved files.
4348
4348
4349 To undo an uncommitted merge, use :hg:`update --clean .` which
4349 To undo an uncommitted merge, use :hg:`update --clean .` which
4350 will check out a clean copy of the original merge parent, losing
4350 will check out a clean copy of the original merge parent, losing
4351 all changes.
4351 all changes.
4352
4352
4353 Returns 0 on success, 1 if there are unresolved files.
4353 Returns 0 on success, 1 if there are unresolved files.
4354 """
4354 """
4355
4355
4356 if opts.get('rev') and node:
4356 if opts.get('rev') and node:
4357 raise util.Abort(_("please specify just one revision"))
4357 raise util.Abort(_("please specify just one revision"))
4358 if not node:
4358 if not node:
4359 node = opts.get('rev')
4359 node = opts.get('rev')
4360
4360
4361 if node:
4361 if node:
4362 node = scmutil.revsingle(repo, node).node()
4362 node = scmutil.revsingle(repo, node).node()
4363
4363
4364 if not node and repo._bookmarkcurrent:
4364 if not node and repo._bookmarkcurrent:
4365 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4365 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4366 curhead = repo[repo._bookmarkcurrent].node()
4366 curhead = repo[repo._bookmarkcurrent].node()
4367 if len(bmheads) == 2:
4367 if len(bmheads) == 2:
4368 if curhead == bmheads[0]:
4368 if curhead == bmheads[0]:
4369 node = bmheads[1]
4369 node = bmheads[1]
4370 else:
4370 else:
4371 node = bmheads[0]
4371 node = bmheads[0]
4372 elif len(bmheads) > 2:
4372 elif len(bmheads) > 2:
4373 raise util.Abort(_("multiple matching bookmarks to merge - "
4373 raise util.Abort(_("multiple matching bookmarks to merge - "
4374 "please merge with an explicit rev or bookmark"),
4374 "please merge with an explicit rev or bookmark"),
4375 hint=_("run 'hg heads' to see all heads"))
4375 hint=_("run 'hg heads' to see all heads"))
4376 elif len(bmheads) <= 1:
4376 elif len(bmheads) <= 1:
4377 raise util.Abort(_("no matching bookmark to merge - "
4377 raise util.Abort(_("no matching bookmark to merge - "
4378 "please merge with an explicit rev or bookmark"),
4378 "please merge with an explicit rev or bookmark"),
4379 hint=_("run 'hg heads' to see all heads"))
4379 hint=_("run 'hg heads' to see all heads"))
4380
4380
4381 if not node and not repo._bookmarkcurrent:
4381 if not node and not repo._bookmarkcurrent:
4382 branch = repo[None].branch()
4382 branch = repo[None].branch()
4383 bheads = repo.branchheads(branch)
4383 bheads = repo.branchheads(branch)
4384 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4384 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4385
4385
4386 if len(nbhs) > 2:
4386 if len(nbhs) > 2:
4387 raise util.Abort(_("branch '%s' has %d heads - "
4387 raise util.Abort(_("branch '%s' has %d heads - "
4388 "please merge with an explicit rev")
4388 "please merge with an explicit rev")
4389 % (branch, len(bheads)),
4389 % (branch, len(bheads)),
4390 hint=_("run 'hg heads .' to see heads"))
4390 hint=_("run 'hg heads .' to see heads"))
4391
4391
4392 parent = repo.dirstate.p1()
4392 parent = repo.dirstate.p1()
4393 if len(nbhs) <= 1:
4393 if len(nbhs) <= 1:
4394 if len(bheads) > 1:
4394 if len(bheads) > 1:
4395 raise util.Abort(_("heads are bookmarked - "
4395 raise util.Abort(_("heads are bookmarked - "
4396 "please merge with an explicit rev"),
4396 "please merge with an explicit rev"),
4397 hint=_("run 'hg heads' to see all heads"))
4397 hint=_("run 'hg heads' to see all heads"))
4398 if len(repo.heads()) > 1:
4398 if len(repo.heads()) > 1:
4399 raise util.Abort(_("branch '%s' has one head - "
4399 raise util.Abort(_("branch '%s' has one head - "
4400 "please merge with an explicit rev")
4400 "please merge with an explicit rev")
4401 % branch,
4401 % branch,
4402 hint=_("run 'hg heads' to see all heads"))
4402 hint=_("run 'hg heads' to see all heads"))
4403 msg, hint = _('nothing to merge'), None
4403 msg, hint = _('nothing to merge'), None
4404 if parent != repo.lookup(branch):
4404 if parent != repo.lookup(branch):
4405 hint = _("use 'hg update' instead")
4405 hint = _("use 'hg update' instead")
4406 raise util.Abort(msg, hint=hint)
4406 raise util.Abort(msg, hint=hint)
4407
4407
4408 if parent not in bheads:
4408 if parent not in bheads:
4409 raise util.Abort(_('working directory not at a head revision'),
4409 raise util.Abort(_('working directory not at a head revision'),
4410 hint=_("use 'hg update' or merge with an "
4410 hint=_("use 'hg update' or merge with an "
4411 "explicit revision"))
4411 "explicit revision"))
4412 if parent == nbhs[0]:
4412 if parent == nbhs[0]:
4413 node = nbhs[-1]
4413 node = nbhs[-1]
4414 else:
4414 else:
4415 node = nbhs[0]
4415 node = nbhs[0]
4416
4416
4417 if opts.get('preview'):
4417 if opts.get('preview'):
4418 # find nodes that are ancestors of p2 but not of p1
4418 # find nodes that are ancestors of p2 but not of p1
4419 p1 = repo.lookup('.')
4419 p1 = repo.lookup('.')
4420 p2 = repo.lookup(node)
4420 p2 = repo.lookup(node)
4421 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4421 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4422
4422
4423 displayer = cmdutil.show_changeset(ui, repo, opts)
4423 displayer = cmdutil.show_changeset(ui, repo, opts)
4424 for node in nodes:
4424 for node in nodes:
4425 displayer.show(repo[node])
4425 displayer.show(repo[node])
4426 displayer.close()
4426 displayer.close()
4427 return 0
4427 return 0
4428
4428
4429 try:
4429 try:
4430 # ui.forcemerge is an internal variable, do not document
4430 # ui.forcemerge is an internal variable, do not document
4431 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4431 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4432 return hg.merge(repo, node, force=opts.get('force'))
4432 return hg.merge(repo, node, force=opts.get('force'))
4433 finally:
4433 finally:
4434 ui.setconfig('ui', 'forcemerge', '')
4434 ui.setconfig('ui', 'forcemerge', '')
4435
4435
4436 @command('outgoing|out',
4436 @command('outgoing|out',
4437 [('f', 'force', None, _('run even when the destination is unrelated')),
4437 [('f', 'force', None, _('run even when the destination is unrelated')),
4438 ('r', 'rev', [],
4438 ('r', 'rev', [],
4439 _('a changeset intended to be included in the destination'), _('REV')),
4439 _('a changeset intended to be included in the destination'), _('REV')),
4440 ('n', 'newest-first', None, _('show newest record first')),
4440 ('n', 'newest-first', None, _('show newest record first')),
4441 ('B', 'bookmarks', False, _('compare bookmarks')),
4441 ('B', 'bookmarks', False, _('compare bookmarks')),
4442 ('b', 'branch', [], _('a specific branch you would like to push'),
4442 ('b', 'branch', [], _('a specific branch you would like to push'),
4443 _('BRANCH')),
4443 _('BRANCH')),
4444 ] + logopts + remoteopts + subrepoopts,
4444 ] + logopts + remoteopts + subrepoopts,
4445 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4445 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4446 def outgoing(ui, repo, dest=None, **opts):
4446 def outgoing(ui, repo, dest=None, **opts):
4447 """show changesets not found in the destination
4447 """show changesets not found in the destination
4448
4448
4449 Show changesets not found in the specified destination repository
4449 Show changesets not found in the specified destination repository
4450 or the default push location. These are the changesets that would
4450 or the default push location. These are the changesets that would
4451 be pushed if a push was requested.
4451 be pushed if a push was requested.
4452
4452
4453 See pull for details of valid destination formats.
4453 See pull for details of valid destination formats.
4454
4454
4455 Returns 0 if there are outgoing changes, 1 otherwise.
4455 Returns 0 if there are outgoing changes, 1 otherwise.
4456 """
4456 """
4457 if opts.get('graph'):
4457 if opts.get('graph'):
4458 cmdutil.checkunsupportedgraphflags([], opts)
4458 cmdutil.checkunsupportedgraphflags([], opts)
4459 o = hg._outgoing(ui, repo, dest, opts)
4459 o = hg._outgoing(ui, repo, dest, opts)
4460 if o is None:
4460 if o is None:
4461 return
4461 return
4462
4462
4463 revdag = cmdutil.graphrevs(repo, o, opts)
4463 revdag = cmdutil.graphrevs(repo, o, opts)
4464 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4464 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4465 showparents = [ctx.node() for ctx in repo[None].parents()]
4465 showparents = [ctx.node() for ctx in repo[None].parents()]
4466 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4466 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4467 graphmod.asciiedges)
4467 graphmod.asciiedges)
4468 return 0
4468 return 0
4469
4469
4470 if opts.get('bookmarks'):
4470 if opts.get('bookmarks'):
4471 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4471 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4472 dest, branches = hg.parseurl(dest, opts.get('branch'))
4472 dest, branches = hg.parseurl(dest, opts.get('branch'))
4473 other = hg.peer(repo, opts, dest)
4473 other = hg.peer(repo, opts, dest)
4474 if 'bookmarks' not in other.listkeys('namespaces'):
4474 if 'bookmarks' not in other.listkeys('namespaces'):
4475 ui.warn(_("remote doesn't support bookmarks\n"))
4475 ui.warn(_("remote doesn't support bookmarks\n"))
4476 return 0
4476 return 0
4477 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4477 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4478 return bookmarks.diff(ui, other, repo)
4478 return bookmarks.diff(ui, other, repo)
4479
4479
4480 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4480 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4481 try:
4481 try:
4482 return hg.outgoing(ui, repo, dest, opts)
4482 return hg.outgoing(ui, repo, dest, opts)
4483 finally:
4483 finally:
4484 del repo._subtoppath
4484 del repo._subtoppath
4485
4485
4486 @command('parents',
4486 @command('parents',
4487 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4487 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4488 ] + templateopts,
4488 ] + templateopts,
4489 _('[-r REV] [FILE]'))
4489 _('[-r REV] [FILE]'))
4490 def parents(ui, repo, file_=None, **opts):
4490 def parents(ui, repo, file_=None, **opts):
4491 """show the parents of the working directory or revision
4491 """show the parents of the working directory or revision
4492
4492
4493 Print the working directory's parent revisions. If a revision is
4493 Print the working directory's parent revisions. If a revision is
4494 given via -r/--rev, the parent of that revision will be printed.
4494 given via -r/--rev, the parent of that revision will be printed.
4495 If a file argument is given, the revision in which the file was
4495 If a file argument is given, the revision in which the file was
4496 last changed (before the working directory revision or the
4496 last changed (before the working directory revision or the
4497 argument to --rev if given) is printed.
4497 argument to --rev if given) is printed.
4498
4498
4499 Returns 0 on success.
4499 Returns 0 on success.
4500 """
4500 """
4501
4501
4502 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4502 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4503
4503
4504 if file_:
4504 if file_:
4505 m = scmutil.match(ctx, (file_,), opts)
4505 m = scmutil.match(ctx, (file_,), opts)
4506 if m.anypats() or len(m.files()) != 1:
4506 if m.anypats() or len(m.files()) != 1:
4507 raise util.Abort(_('can only specify an explicit filename'))
4507 raise util.Abort(_('can only specify an explicit filename'))
4508 file_ = m.files()[0]
4508 file_ = m.files()[0]
4509 filenodes = []
4509 filenodes = []
4510 for cp in ctx.parents():
4510 for cp in ctx.parents():
4511 if not cp:
4511 if not cp:
4512 continue
4512 continue
4513 try:
4513 try:
4514 filenodes.append(cp.filenode(file_))
4514 filenodes.append(cp.filenode(file_))
4515 except error.LookupError:
4515 except error.LookupError:
4516 pass
4516 pass
4517 if not filenodes:
4517 if not filenodes:
4518 raise util.Abort(_("'%s' not found in manifest!") % file_)
4518 raise util.Abort(_("'%s' not found in manifest!") % file_)
4519 fl = repo.file(file_)
4519 fl = repo.file(file_)
4520 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4520 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4521 else:
4521 else:
4522 p = [cp.node() for cp in ctx.parents()]
4522 p = [cp.node() for cp in ctx.parents()]
4523
4523
4524 displayer = cmdutil.show_changeset(ui, repo, opts)
4524 displayer = cmdutil.show_changeset(ui, repo, opts)
4525 for n in p:
4525 for n in p:
4526 if n != nullid:
4526 if n != nullid:
4527 displayer.show(repo[n])
4527 displayer.show(repo[n])
4528 displayer.close()
4528 displayer.close()
4529
4529
4530 @command('paths', [], _('[NAME]'))
4530 @command('paths', [], _('[NAME]'))
4531 def paths(ui, repo, search=None):
4531 def paths(ui, repo, search=None):
4532 """show aliases for remote repositories
4532 """show aliases for remote repositories
4533
4533
4534 Show definition of symbolic path name NAME. If no name is given,
4534 Show definition of symbolic path name NAME. If no name is given,
4535 show definition of all available names.
4535 show definition of all available names.
4536
4536
4537 Option -q/--quiet suppresses all output when searching for NAME
4537 Option -q/--quiet suppresses all output when searching for NAME
4538 and shows only the path names when listing all definitions.
4538 and shows only the path names when listing all definitions.
4539
4539
4540 Path names are defined in the [paths] section of your
4540 Path names are defined in the [paths] section of your
4541 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4541 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4542 repository, ``.hg/hgrc`` is used, too.
4542 repository, ``.hg/hgrc`` is used, too.
4543
4543
4544 The path names ``default`` and ``default-push`` have a special
4544 The path names ``default`` and ``default-push`` have a special
4545 meaning. When performing a push or pull operation, they are used
4545 meaning. When performing a push or pull operation, they are used
4546 as fallbacks if no location is specified on the command-line.
4546 as fallbacks if no location is specified on the command-line.
4547 When ``default-push`` is set, it will be used for push and
4547 When ``default-push`` is set, it will be used for push and
4548 ``default`` will be used for pull; otherwise ``default`` is used
4548 ``default`` will be used for pull; otherwise ``default`` is used
4549 as the fallback for both. When cloning a repository, the clone
4549 as the fallback for both. When cloning a repository, the clone
4550 source is written as ``default`` in ``.hg/hgrc``. Note that
4550 source is written as ``default`` in ``.hg/hgrc``. Note that
4551 ``default`` and ``default-push`` apply to all inbound (e.g.
4551 ``default`` and ``default-push`` apply to all inbound (e.g.
4552 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4552 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4553 :hg:`bundle`) operations.
4553 :hg:`bundle`) operations.
4554
4554
4555 See :hg:`help urls` for more information.
4555 See :hg:`help urls` for more information.
4556
4556
4557 Returns 0 on success.
4557 Returns 0 on success.
4558 """
4558 """
4559 if search:
4559 if search:
4560 for name, path in ui.configitems("paths"):
4560 for name, path in ui.configitems("paths"):
4561 if name == search:
4561 if name == search:
4562 ui.status("%s\n" % util.hidepassword(path))
4562 ui.status("%s\n" % util.hidepassword(path))
4563 return
4563 return
4564 if not ui.quiet:
4564 if not ui.quiet:
4565 ui.warn(_("not found!\n"))
4565 ui.warn(_("not found!\n"))
4566 return 1
4566 return 1
4567 else:
4567 else:
4568 for name, path in ui.configitems("paths"):
4568 for name, path in ui.configitems("paths"):
4569 if ui.quiet:
4569 if ui.quiet:
4570 ui.write("%s\n" % name)
4570 ui.write("%s\n" % name)
4571 else:
4571 else:
4572 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4572 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4573
4573
4574 @command('phase',
4574 @command('phase',
4575 [('p', 'public', False, _('set changeset phase to public')),
4575 [('p', 'public', False, _('set changeset phase to public')),
4576 ('d', 'draft', False, _('set changeset phase to draft')),
4576 ('d', 'draft', False, _('set changeset phase to draft')),
4577 ('s', 'secret', False, _('set changeset phase to secret')),
4577 ('s', 'secret', False, _('set changeset phase to secret')),
4578 ('f', 'force', False, _('allow to move boundary backward')),
4578 ('f', 'force', False, _('allow to move boundary backward')),
4579 ('r', 'rev', [], _('target revision'), _('REV')),
4579 ('r', 'rev', [], _('target revision'), _('REV')),
4580 ],
4580 ],
4581 _('[-p|-d|-s] [-f] [-r] REV...'))
4581 _('[-p|-d|-s] [-f] [-r] REV...'))
4582 def phase(ui, repo, *revs, **opts):
4582 def phase(ui, repo, *revs, **opts):
4583 """set or show the current phase name
4583 """set or show the current phase name
4584
4584
4585 With no argument, show the phase name of specified revisions.
4585 With no argument, show the phase name of specified revisions.
4586
4586
4587 With one of -p/--public, -d/--draft or -s/--secret, change the
4587 With one of -p/--public, -d/--draft or -s/--secret, change the
4588 phase value of the specified revisions.
4588 phase value of the specified revisions.
4589
4589
4590 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4590 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4591 lower phase to an higher phase. Phases are ordered as follows::
4591 lower phase to an higher phase. Phases are ordered as follows::
4592
4592
4593 public < draft < secret
4593 public < draft < secret
4594
4594
4595 Return 0 on success, 1 if no phases were changed or some could not
4595 Return 0 on success, 1 if no phases were changed or some could not
4596 be changed.
4596 be changed.
4597 """
4597 """
4598 # search for a unique phase argument
4598 # search for a unique phase argument
4599 targetphase = None
4599 targetphase = None
4600 for idx, name in enumerate(phases.phasenames):
4600 for idx, name in enumerate(phases.phasenames):
4601 if opts[name]:
4601 if opts[name]:
4602 if targetphase is not None:
4602 if targetphase is not None:
4603 raise util.Abort(_('only one phase can be specified'))
4603 raise util.Abort(_('only one phase can be specified'))
4604 targetphase = idx
4604 targetphase = idx
4605
4605
4606 # look for specified revision
4606 # look for specified revision
4607 revs = list(revs)
4607 revs = list(revs)
4608 revs.extend(opts['rev'])
4608 revs.extend(opts['rev'])
4609 if not revs:
4609 if not revs:
4610 raise util.Abort(_('no revisions specified'))
4610 raise util.Abort(_('no revisions specified'))
4611
4611
4612 revs = scmutil.revrange(repo, revs)
4612 revs = scmutil.revrange(repo, revs)
4613
4613
4614 lock = None
4614 lock = None
4615 ret = 0
4615 ret = 0
4616 if targetphase is None:
4616 if targetphase is None:
4617 # display
4617 # display
4618 for r in revs:
4618 for r in revs:
4619 ctx = repo[r]
4619 ctx = repo[r]
4620 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4620 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4621 else:
4621 else:
4622 lock = repo.lock()
4622 lock = repo.lock()
4623 try:
4623 try:
4624 # set phase
4624 # set phase
4625 if not revs:
4625 if not revs:
4626 raise util.Abort(_('empty revision set'))
4626 raise util.Abort(_('empty revision set'))
4627 nodes = [repo[r].node() for r in revs]
4627 nodes = [repo[r].node() for r in revs]
4628 olddata = repo._phasecache.getphaserevs(repo)[:]
4628 olddata = repo._phasecache.getphaserevs(repo)[:]
4629 phases.advanceboundary(repo, targetphase, nodes)
4629 phases.advanceboundary(repo, targetphase, nodes)
4630 if opts['force']:
4630 if opts['force']:
4631 phases.retractboundary(repo, targetphase, nodes)
4631 phases.retractboundary(repo, targetphase, nodes)
4632 finally:
4632 finally:
4633 lock.release()
4633 lock.release()
4634 # moving revision from public to draft may hide them
4634 # moving revision from public to draft may hide them
4635 # We have to check result on an unfiltered repository
4635 # We have to check result on an unfiltered repository
4636 unfi = repo.unfiltered()
4636 unfi = repo.unfiltered()
4637 newdata = repo._phasecache.getphaserevs(unfi)
4637 newdata = repo._phasecache.getphaserevs(unfi)
4638 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4638 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4639 cl = unfi.changelog
4639 cl = unfi.changelog
4640 rejected = [n for n in nodes
4640 rejected = [n for n in nodes
4641 if newdata[cl.rev(n)] < targetphase]
4641 if newdata[cl.rev(n)] < targetphase]
4642 if rejected:
4642 if rejected:
4643 ui.warn(_('cannot move %i changesets to a more permissive '
4643 ui.warn(_('cannot move %i changesets to a more permissive '
4644 'phase, use --force\n') % len(rejected))
4644 'phase, use --force\n') % len(rejected))
4645 ret = 1
4645 ret = 1
4646 if changes:
4646 if changes:
4647 msg = _('phase changed for %i changesets\n') % changes
4647 msg = _('phase changed for %i changesets\n') % changes
4648 if ret:
4648 if ret:
4649 ui.status(msg)
4649 ui.status(msg)
4650 else:
4650 else:
4651 ui.note(msg)
4651 ui.note(msg)
4652 else:
4652 else:
4653 ui.warn(_('no phases changed\n'))
4653 ui.warn(_('no phases changed\n'))
4654 ret = 1
4654 ret = 1
4655 return ret
4655 return ret
4656
4656
4657 def postincoming(ui, repo, modheads, optupdate, checkout):
4657 def postincoming(ui, repo, modheads, optupdate, checkout):
4658 if modheads == 0:
4658 if modheads == 0:
4659 return
4659 return
4660 if optupdate:
4660 if optupdate:
4661 movemarkfrom = repo['.'].node()
4661 movemarkfrom = repo['.'].node()
4662 try:
4662 try:
4663 ret = hg.update(repo, checkout)
4663 ret = hg.update(repo, checkout)
4664 except util.Abort, inst:
4664 except util.Abort, inst:
4665 ui.warn(_("not updating: %s\n") % str(inst))
4665 ui.warn(_("not updating: %s\n") % str(inst))
4666 return 0
4666 return 0
4667 if not ret and not checkout:
4667 if not ret and not checkout:
4668 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4668 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4669 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4669 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4670 return ret
4670 return ret
4671 if modheads > 1:
4671 if modheads > 1:
4672 currentbranchheads = len(repo.branchheads())
4672 currentbranchheads = len(repo.branchheads())
4673 if currentbranchheads == modheads:
4673 if currentbranchheads == modheads:
4674 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4674 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4675 elif currentbranchheads > 1:
4675 elif currentbranchheads > 1:
4676 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4676 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4677 "merge)\n"))
4677 "merge)\n"))
4678 else:
4678 else:
4679 ui.status(_("(run 'hg heads' to see heads)\n"))
4679 ui.status(_("(run 'hg heads' to see heads)\n"))
4680 else:
4680 else:
4681 ui.status(_("(run 'hg update' to get a working copy)\n"))
4681 ui.status(_("(run 'hg update' to get a working copy)\n"))
4682
4682
4683 @command('^pull',
4683 @command('^pull',
4684 [('u', 'update', None,
4684 [('u', 'update', None,
4685 _('update to new branch head if changesets were pulled')),
4685 _('update to new branch head if changesets were pulled')),
4686 ('f', 'force', None, _('run even when remote repository is unrelated')),
4686 ('f', 'force', None, _('run even when remote repository is unrelated')),
4687 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4687 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4688 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4688 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4689 ('b', 'branch', [], _('a specific branch you would like to pull'),
4689 ('b', 'branch', [], _('a specific branch you would like to pull'),
4690 _('BRANCH')),
4690 _('BRANCH')),
4691 ] + remoteopts,
4691 ] + remoteopts,
4692 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4692 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4693 def pull(ui, repo, source="default", **opts):
4693 def pull(ui, repo, source="default", **opts):
4694 """pull changes from the specified source
4694 """pull changes from the specified source
4695
4695
4696 Pull changes from a remote repository to a local one.
4696 Pull changes from a remote repository to a local one.
4697
4697
4698 This finds all changes from the repository at the specified path
4698 This finds all changes from the repository at the specified path
4699 or URL and adds them to a local repository (the current one unless
4699 or URL and adds them to a local repository (the current one unless
4700 -R is specified). By default, this does not update the copy of the
4700 -R is specified). By default, this does not update the copy of the
4701 project in the working directory.
4701 project in the working directory.
4702
4702
4703 Use :hg:`incoming` if you want to see what would have been added
4703 Use :hg:`incoming` if you want to see what would have been added
4704 by a pull at the time you issued this command. If you then decide
4704 by a pull at the time you issued this command. If you then decide
4705 to add those changes to the repository, you should use :hg:`pull
4705 to add those changes to the repository, you should use :hg:`pull
4706 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4706 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4707
4707
4708 If SOURCE is omitted, the 'default' path will be used.
4708 If SOURCE is omitted, the 'default' path will be used.
4709 See :hg:`help urls` for more information.
4709 See :hg:`help urls` for more information.
4710
4710
4711 Returns 0 on success, 1 if an update had unresolved files.
4711 Returns 0 on success, 1 if an update had unresolved files.
4712 """
4712 """
4713 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4713 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4714 other = hg.peer(repo, opts, source)
4714 other = hg.peer(repo, opts, source)
4715 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4715 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4716 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4716 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4717
4717
4718 if opts.get('bookmark'):
4718 if opts.get('bookmark'):
4719 if not revs:
4719 if not revs:
4720 revs = []
4720 revs = []
4721 rb = other.listkeys('bookmarks')
4721 rb = other.listkeys('bookmarks')
4722 for b in opts['bookmark']:
4722 for b in opts['bookmark']:
4723 if b not in rb:
4723 if b not in rb:
4724 raise util.Abort(_('remote bookmark %s not found!') % b)
4724 raise util.Abort(_('remote bookmark %s not found!') % b)
4725 revs.append(rb[b])
4725 revs.append(rb[b])
4726
4726
4727 if revs:
4727 if revs:
4728 try:
4728 try:
4729 revs = [other.lookup(rev) for rev in revs]
4729 revs = [other.lookup(rev) for rev in revs]
4730 except error.CapabilityError:
4730 except error.CapabilityError:
4731 err = _("other repository doesn't support revision lookup, "
4731 err = _("other repository doesn't support revision lookup, "
4732 "so a rev cannot be specified.")
4732 "so a rev cannot be specified.")
4733 raise util.Abort(err)
4733 raise util.Abort(err)
4734
4734
4735 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4735 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4736 bookmarks.updatefromremote(ui, repo, other, source)
4736 bookmarks.updatefromremote(ui, repo, other, source)
4737 if checkout:
4737 if checkout:
4738 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4738 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4739 repo._subtoppath = source
4739 repo._subtoppath = source
4740 try:
4740 try:
4741 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4741 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4742
4742
4743 finally:
4743 finally:
4744 del repo._subtoppath
4744 del repo._subtoppath
4745
4745
4746 # update specified bookmarks
4746 # update specified bookmarks
4747 if opts.get('bookmark'):
4747 if opts.get('bookmark'):
4748 marks = repo._bookmarks
4748 marks = repo._bookmarks
4749 for b in opts['bookmark']:
4749 for b in opts['bookmark']:
4750 # explicit pull overrides local bookmark if any
4750 # explicit pull overrides local bookmark if any
4751 ui.status(_("importing bookmark %s\n") % b)
4751 ui.status(_("importing bookmark %s\n") % b)
4752 marks[b] = repo[rb[b]].node()
4752 marks[b] = repo[rb[b]].node()
4753 marks.write()
4753 marks.write()
4754
4754
4755 return ret
4755 return ret
4756
4756
4757 @command('^push',
4757 @command('^push',
4758 [('f', 'force', None, _('force push')),
4758 [('f', 'force', None, _('force push')),
4759 ('r', 'rev', [],
4759 ('r', 'rev', [],
4760 _('a changeset intended to be included in the destination'),
4760 _('a changeset intended to be included in the destination'),
4761 _('REV')),
4761 _('REV')),
4762 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4762 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4763 ('b', 'branch', [],
4763 ('b', 'branch', [],
4764 _('a specific branch you would like to push'), _('BRANCH')),
4764 _('a specific branch you would like to push'), _('BRANCH')),
4765 ('', 'new-branch', False, _('allow pushing a new branch')),
4765 ('', 'new-branch', False, _('allow pushing a new branch')),
4766 ] + remoteopts,
4766 ] + remoteopts,
4767 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4767 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4768 def push(ui, repo, dest=None, **opts):
4768 def push(ui, repo, dest=None, **opts):
4769 """push changes to the specified destination
4769 """push changes to the specified destination
4770
4770
4771 Push changesets from the local repository to the specified
4771 Push changesets from the local repository to the specified
4772 destination.
4772 destination.
4773
4773
4774 This operation is symmetrical to pull: it is identical to a pull
4774 This operation is symmetrical to pull: it is identical to a pull
4775 in the destination repository from the current one.
4775 in the destination repository from the current one.
4776
4776
4777 By default, push will not allow creation of new heads at the
4777 By default, push will not allow creation of new heads at the
4778 destination, since multiple heads would make it unclear which head
4778 destination, since multiple heads would make it unclear which head
4779 to use. In this situation, it is recommended to pull and merge
4779 to use. In this situation, it is recommended to pull and merge
4780 before pushing.
4780 before pushing.
4781
4781
4782 Use --new-branch if you want to allow push to create a new named
4782 Use --new-branch if you want to allow push to create a new named
4783 branch that is not present at the destination. This allows you to
4783 branch that is not present at the destination. This allows you to
4784 only create a new branch without forcing other changes.
4784 only create a new branch without forcing other changes.
4785
4785
4786 Use -f/--force to override the default behavior and push all
4786 Use -f/--force to override the default behavior and push all
4787 changesets on all branches.
4787 changesets on all branches.
4788
4788
4789 If -r/--rev is used, the specified revision and all its ancestors
4789 If -r/--rev is used, the specified revision and all its ancestors
4790 will be pushed to the remote repository.
4790 will be pushed to the remote repository.
4791
4791
4792 If -B/--bookmark is used, the specified bookmarked revision, its
4792 If -B/--bookmark is used, the specified bookmarked revision, its
4793 ancestors, and the bookmark will be pushed to the remote
4793 ancestors, and the bookmark will be pushed to the remote
4794 repository.
4794 repository.
4795
4795
4796 Please see :hg:`help urls` for important details about ``ssh://``
4796 Please see :hg:`help urls` for important details about ``ssh://``
4797 URLs. If DESTINATION is omitted, a default path will be used.
4797 URLs. If DESTINATION is omitted, a default path will be used.
4798
4798
4799 Returns 0 if push was successful, 1 if nothing to push.
4799 Returns 0 if push was successful, 1 if nothing to push.
4800 """
4800 """
4801
4801
4802 if opts.get('bookmark'):
4802 if opts.get('bookmark'):
4803 for b in opts['bookmark']:
4803 for b in opts['bookmark']:
4804 # translate -B options to -r so changesets get pushed
4804 # translate -B options to -r so changesets get pushed
4805 if b in repo._bookmarks:
4805 if b in repo._bookmarks:
4806 opts.setdefault('rev', []).append(b)
4806 opts.setdefault('rev', []).append(b)
4807 else:
4807 else:
4808 # if we try to push a deleted bookmark, translate it to null
4808 # if we try to push a deleted bookmark, translate it to null
4809 # this lets simultaneous -r, -b options continue working
4809 # this lets simultaneous -r, -b options continue working
4810 opts.setdefault('rev', []).append("null")
4810 opts.setdefault('rev', []).append("null")
4811
4811
4812 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4812 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4813 dest, branches = hg.parseurl(dest, opts.get('branch'))
4813 dest, branches = hg.parseurl(dest, opts.get('branch'))
4814 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4814 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4815 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4815 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4816 other = hg.peer(repo, opts, dest)
4816 other = hg.peer(repo, opts, dest)
4817 if revs:
4817 if revs:
4818 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4818 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4819
4819
4820 repo._subtoppath = dest
4820 repo._subtoppath = dest
4821 try:
4821 try:
4822 # push subrepos depth-first for coherent ordering
4822 # push subrepos depth-first for coherent ordering
4823 c = repo['']
4823 c = repo['']
4824 subs = c.substate # only repos that are committed
4824 subs = c.substate # only repos that are committed
4825 for s in sorted(subs):
4825 for s in sorted(subs):
4826 if c.sub(s).push(opts) == 0:
4826 if c.sub(s).push(opts) == 0:
4827 return False
4827 return False
4828 finally:
4828 finally:
4829 del repo._subtoppath
4829 del repo._subtoppath
4830 result = repo.push(other, opts.get('force'), revs=revs,
4830 result = repo.push(other, opts.get('force'), revs=revs,
4831 newbranch=opts.get('new_branch'))
4831 newbranch=opts.get('new_branch'))
4832
4832
4833 result = not result
4833 result = not result
4834
4834
4835 if opts.get('bookmark'):
4835 if opts.get('bookmark'):
4836 rb = other.listkeys('bookmarks')
4836 rb = other.listkeys('bookmarks')
4837 for b in opts['bookmark']:
4837 for b in opts['bookmark']:
4838 # explicit push overrides remote bookmark if any
4838 # explicit push overrides remote bookmark if any
4839 if b in repo._bookmarks:
4839 if b in repo._bookmarks:
4840 ui.status(_("exporting bookmark %s\n") % b)
4840 ui.status(_("exporting bookmark %s\n") % b)
4841 new = repo[b].hex()
4841 new = repo[b].hex()
4842 elif b in rb:
4842 elif b in rb:
4843 ui.status(_("deleting remote bookmark %s\n") % b)
4843 ui.status(_("deleting remote bookmark %s\n") % b)
4844 new = '' # delete
4844 new = '' # delete
4845 else:
4845 else:
4846 ui.warn(_('bookmark %s does not exist on the local '
4846 ui.warn(_('bookmark %s does not exist on the local '
4847 'or remote repository!\n') % b)
4847 'or remote repository!\n') % b)
4848 return 2
4848 return 2
4849 old = rb.get(b, '')
4849 old = rb.get(b, '')
4850 r = other.pushkey('bookmarks', b, old, new)
4850 r = other.pushkey('bookmarks', b, old, new)
4851 if not r:
4851 if not r:
4852 ui.warn(_('updating bookmark %s failed!\n') % b)
4852 ui.warn(_('updating bookmark %s failed!\n') % b)
4853 if not result:
4853 if not result:
4854 result = 2
4854 result = 2
4855
4855
4856 return result
4856 return result
4857
4857
4858 @command('recover', [])
4858 @command('recover', [])
4859 def recover(ui, repo):
4859 def recover(ui, repo):
4860 """roll back an interrupted transaction
4860 """roll back an interrupted transaction
4861
4861
4862 Recover from an interrupted commit or pull.
4862 Recover from an interrupted commit or pull.
4863
4863
4864 This command tries to fix the repository status after an
4864 This command tries to fix the repository status after an
4865 interrupted operation. It should only be necessary when Mercurial
4865 interrupted operation. It should only be necessary when Mercurial
4866 suggests it.
4866 suggests it.
4867
4867
4868 Returns 0 if successful, 1 if nothing to recover or verify fails.
4868 Returns 0 if successful, 1 if nothing to recover or verify fails.
4869 """
4869 """
4870 if repo.recover():
4870 if repo.recover():
4871 return hg.verify(repo)
4871 return hg.verify(repo)
4872 return 1
4872 return 1
4873
4873
4874 @command('^remove|rm',
4874 @command('^remove|rm',
4875 [('A', 'after', None, _('record delete for missing files')),
4875 [('A', 'after', None, _('record delete for missing files')),
4876 ('f', 'force', None,
4876 ('f', 'force', None,
4877 _('remove (and delete) file even if added or modified')),
4877 _('remove (and delete) file even if added or modified')),
4878 ] + walkopts,
4878 ] + walkopts,
4879 _('[OPTION]... FILE...'))
4879 _('[OPTION]... FILE...'))
4880 def remove(ui, repo, *pats, **opts):
4880 def remove(ui, repo, *pats, **opts):
4881 """remove the specified files on the next commit
4881 """remove the specified files on the next commit
4882
4882
4883 Schedule the indicated files for removal from the current branch.
4883 Schedule the indicated files for removal from the current branch.
4884
4884
4885 This command schedules the files to be removed at the next commit.
4885 This command schedules the files to be removed at the next commit.
4886 To undo a remove before that, see :hg:`revert`. To undo added
4886 To undo a remove before that, see :hg:`revert`. To undo added
4887 files, see :hg:`forget`.
4887 files, see :hg:`forget`.
4888
4888
4889 .. container:: verbose
4889 .. container:: verbose
4890
4890
4891 -A/--after can be used to remove only files that have already
4891 -A/--after can be used to remove only files that have already
4892 been deleted, -f/--force can be used to force deletion, and -Af
4892 been deleted, -f/--force can be used to force deletion, and -Af
4893 can be used to remove files from the next revision without
4893 can be used to remove files from the next revision without
4894 deleting them from the working directory.
4894 deleting them from the working directory.
4895
4895
4896 The following table details the behavior of remove for different
4896 The following table details the behavior of remove for different
4897 file states (columns) and option combinations (rows). The file
4897 file states (columns) and option combinations (rows). The file
4898 states are Added [A], Clean [C], Modified [M] and Missing [!]
4898 states are Added [A], Clean [C], Modified [M] and Missing [!]
4899 (as reported by :hg:`status`). The actions are Warn, Remove
4899 (as reported by :hg:`status`). The actions are Warn, Remove
4900 (from branch) and Delete (from disk):
4900 (from branch) and Delete (from disk):
4901
4901
4902 ======= == == == ==
4902 ======= == == == ==
4903 A C M !
4903 A C M !
4904 ======= == == == ==
4904 ======= == == == ==
4905 none W RD W R
4905 none W RD W R
4906 -f R RD RD R
4906 -f R RD RD R
4907 -A W W W R
4907 -A W W W R
4908 -Af R R R R
4908 -Af R R R R
4909 ======= == == == ==
4909 ======= == == == ==
4910
4910
4911 Note that remove never deletes files in Added [A] state from the
4911 Note that remove never deletes files in Added [A] state from the
4912 working directory, not even if option --force is specified.
4912 working directory, not even if option --force is specified.
4913
4913
4914 Returns 0 on success, 1 if any warnings encountered.
4914 Returns 0 on success, 1 if any warnings encountered.
4915 """
4915 """
4916
4916
4917 ret = 0
4917 ret = 0
4918 after, force = opts.get('after'), opts.get('force')
4918 after, force = opts.get('after'), opts.get('force')
4919 if not pats and not after:
4919 if not pats and not after:
4920 raise util.Abort(_('no files specified'))
4920 raise util.Abort(_('no files specified'))
4921
4921
4922 m = scmutil.match(repo[None], pats, opts)
4922 m = scmutil.match(repo[None], pats, opts)
4923 s = repo.status(match=m, clean=True)
4923 s = repo.status(match=m, clean=True)
4924 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4924 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4925
4925
4926 # warn about failure to delete explicit files/dirs
4926 # warn about failure to delete explicit files/dirs
4927 wctx = repo[None]
4927 wctx = repo[None]
4928 for f in m.files():
4928 for f in m.files():
4929 if f in repo.dirstate or f in wctx.dirs():
4929 if f in repo.dirstate or f in wctx.dirs():
4930 continue
4930 continue
4931 if os.path.exists(m.rel(f)):
4931 if os.path.exists(m.rel(f)):
4932 if os.path.isdir(m.rel(f)):
4932 if os.path.isdir(m.rel(f)):
4933 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4933 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4934 else:
4934 else:
4935 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4935 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4936 # missing files will generate a warning elsewhere
4936 # missing files will generate a warning elsewhere
4937 ret = 1
4937 ret = 1
4938
4938
4939 if force:
4939 if force:
4940 list = modified + deleted + clean + added
4940 list = modified + deleted + clean + added
4941 elif after:
4941 elif after:
4942 list = deleted
4942 list = deleted
4943 for f in modified + added + clean:
4943 for f in modified + added + clean:
4944 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4944 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4945 ret = 1
4945 ret = 1
4946 else:
4946 else:
4947 list = deleted + clean
4947 list = deleted + clean
4948 for f in modified:
4948 for f in modified:
4949 ui.warn(_('not removing %s: file is modified (use -f'
4949 ui.warn(_('not removing %s: file is modified (use -f'
4950 ' to force removal)\n') % m.rel(f))
4950 ' to force removal)\n') % m.rel(f))
4951 ret = 1
4951 ret = 1
4952 for f in added:
4952 for f in added:
4953 ui.warn(_('not removing %s: file has been marked for add'
4953 ui.warn(_('not removing %s: file has been marked for add'
4954 ' (use forget to undo)\n') % m.rel(f))
4954 ' (use forget to undo)\n') % m.rel(f))
4955 ret = 1
4955 ret = 1
4956
4956
4957 for f in sorted(list):
4957 for f in sorted(list):
4958 if ui.verbose or not m.exact(f):
4958 if ui.verbose or not m.exact(f):
4959 ui.status(_('removing %s\n') % m.rel(f))
4959 ui.status(_('removing %s\n') % m.rel(f))
4960
4960
4961 wlock = repo.wlock()
4961 wlock = repo.wlock()
4962 try:
4962 try:
4963 if not after:
4963 if not after:
4964 for f in list:
4964 for f in list:
4965 if f in added:
4965 if f in added:
4966 continue # we never unlink added files on remove
4966 continue # we never unlink added files on remove
4967 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4967 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4968 repo[None].forget(list)
4968 repo[None].forget(list)
4969 finally:
4969 finally:
4970 wlock.release()
4970 wlock.release()
4971
4971
4972 return ret
4972 return ret
4973
4973
4974 @command('rename|move|mv',
4974 @command('rename|move|mv',
4975 [('A', 'after', None, _('record a rename that has already occurred')),
4975 [('A', 'after', None, _('record a rename that has already occurred')),
4976 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4976 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4977 ] + walkopts + dryrunopts,
4977 ] + walkopts + dryrunopts,
4978 _('[OPTION]... SOURCE... DEST'))
4978 _('[OPTION]... SOURCE... DEST'))
4979 def rename(ui, repo, *pats, **opts):
4979 def rename(ui, repo, *pats, **opts):
4980 """rename files; equivalent of copy + remove
4980 """rename files; equivalent of copy + remove
4981
4981
4982 Mark dest as copies of sources; mark sources for deletion. If dest
4982 Mark dest as copies of sources; mark sources for deletion. If dest
4983 is a directory, copies are put in that directory. If dest is a
4983 is a directory, copies are put in that directory. If dest is a
4984 file, there can only be one source.
4984 file, there can only be one source.
4985
4985
4986 By default, this command copies the contents of files as they
4986 By default, this command copies the contents of files as they
4987 exist in the working directory. If invoked with -A/--after, the
4987 exist in the working directory. If invoked with -A/--after, the
4988 operation is recorded, but no copying is performed.
4988 operation is recorded, but no copying is performed.
4989
4989
4990 This command takes effect at the next commit. To undo a rename
4990 This command takes effect at the next commit. To undo a rename
4991 before that, see :hg:`revert`.
4991 before that, see :hg:`revert`.
4992
4992
4993 Returns 0 on success, 1 if errors are encountered.
4993 Returns 0 on success, 1 if errors are encountered.
4994 """
4994 """
4995 wlock = repo.wlock(False)
4995 wlock = repo.wlock(False)
4996 try:
4996 try:
4997 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4997 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4998 finally:
4998 finally:
4999 wlock.release()
4999 wlock.release()
5000
5000
5001 @command('resolve',
5001 @command('resolve',
5002 [('a', 'all', None, _('select all unresolved files')),
5002 [('a', 'all', None, _('select all unresolved files')),
5003 ('l', 'list', None, _('list state of files needing merge')),
5003 ('l', 'list', None, _('list state of files needing merge')),
5004 ('m', 'mark', None, _('mark files as resolved')),
5004 ('m', 'mark', None, _('mark files as resolved')),
5005 ('u', 'unmark', None, _('mark files as unresolved')),
5005 ('u', 'unmark', None, _('mark files as unresolved')),
5006 ('n', 'no-status', None, _('hide status prefix'))]
5006 ('n', 'no-status', None, _('hide status prefix'))]
5007 + mergetoolopts + walkopts,
5007 + mergetoolopts + walkopts,
5008 _('[OPTION]... [FILE]...'))
5008 _('[OPTION]... [FILE]...'))
5009 def resolve(ui, repo, *pats, **opts):
5009 def resolve(ui, repo, *pats, **opts):
5010 """redo merges or set/view the merge status of files
5010 """redo merges or set/view the merge status of files
5011
5011
5012 Merges with unresolved conflicts are often the result of
5012 Merges with unresolved conflicts are often the result of
5013 non-interactive merging using the ``internal:merge`` configuration
5013 non-interactive merging using the ``internal:merge`` configuration
5014 setting, or a command-line merge tool like ``diff3``. The resolve
5014 setting, or a command-line merge tool like ``diff3``. The resolve
5015 command is used to manage the files involved in a merge, after
5015 command is used to manage the files involved in a merge, after
5016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5017 working directory must have two parents). See :hg:`help
5017 working directory must have two parents). See :hg:`help
5018 merge-tools` for information on configuring merge tools.
5018 merge-tools` for information on configuring merge tools.
5019
5019
5020 The resolve command can be used in the following ways:
5020 The resolve command can be used in the following ways:
5021
5021
5022 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5022 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5023 files, discarding any previous merge attempts. Re-merging is not
5023 files, discarding any previous merge attempts. Re-merging is not
5024 performed for files already marked as resolved. Use ``--all/-a``
5024 performed for files already marked as resolved. Use ``--all/-a``
5025 to select all unresolved files. ``--tool`` can be used to specify
5025 to select all unresolved files. ``--tool`` can be used to specify
5026 the merge tool used for the given files. It overrides the HGMERGE
5026 the merge tool used for the given files. It overrides the HGMERGE
5027 environment variable and your configuration files. Previous file
5027 environment variable and your configuration files. Previous file
5028 contents are saved with a ``.orig`` suffix.
5028 contents are saved with a ``.orig`` suffix.
5029
5029
5030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5031 (e.g. after having manually fixed-up the files). The default is
5031 (e.g. after having manually fixed-up the files). The default is
5032 to mark all unresolved files.
5032 to mark all unresolved files.
5033
5033
5034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5035 default is to mark all resolved files.
5035 default is to mark all resolved files.
5036
5036
5037 - :hg:`resolve -l`: list files which had or still have conflicts.
5037 - :hg:`resolve -l`: list files which had or still have conflicts.
5038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5039
5039
5040 Note that Mercurial will not let you commit files with unresolved
5040 Note that Mercurial will not let you commit files with unresolved
5041 merge conflicts. You must use :hg:`resolve -m ...` before you can
5041 merge conflicts. You must use :hg:`resolve -m ...` before you can
5042 commit after a conflicting merge.
5042 commit after a conflicting merge.
5043
5043
5044 Returns 0 on success, 1 if any files fail a resolve attempt.
5044 Returns 0 on success, 1 if any files fail a resolve attempt.
5045 """
5045 """
5046
5046
5047 all, mark, unmark, show, nostatus = \
5047 all, mark, unmark, show, nostatus = \
5048 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5048 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5049
5049
5050 if (show and (mark or unmark)) or (mark and unmark):
5050 if (show and (mark or unmark)) or (mark and unmark):
5051 raise util.Abort(_("too many options specified"))
5051 raise util.Abort(_("too many options specified"))
5052 if pats and all:
5052 if pats and all:
5053 raise util.Abort(_("can't specify --all and patterns"))
5053 raise util.Abort(_("can't specify --all and patterns"))
5054 if not (all or pats or show or mark or unmark):
5054 if not (all or pats or show or mark or unmark):
5055 raise util.Abort(_('no files or directories specified; '
5055 raise util.Abort(_('no files or directories specified; '
5056 'use --all to remerge all files'))
5056 'use --all to remerge all files'))
5057
5057
5058 ms = mergemod.mergestate(repo)
5058 ms = mergemod.mergestate(repo)
5059 m = scmutil.match(repo[None], pats, opts)
5059 m = scmutil.match(repo[None], pats, opts)
5060 ret = 0
5060 ret = 0
5061
5061
5062 for f in ms:
5062 for f in ms:
5063 if m(f):
5063 if m(f):
5064 if show:
5064 if show:
5065 if nostatus:
5065 if nostatus:
5066 ui.write("%s\n" % f)
5066 ui.write("%s\n" % f)
5067 else:
5067 else:
5068 ui.write("%s %s\n" % (ms[f].upper(), f),
5068 ui.write("%s %s\n" % (ms[f].upper(), f),
5069 label='resolve.' +
5069 label='resolve.' +
5070 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5070 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5071 elif mark:
5071 elif mark:
5072 ms.mark(f, "r")
5072 ms.mark(f, "r")
5073 elif unmark:
5073 elif unmark:
5074 ms.mark(f, "u")
5074 ms.mark(f, "u")
5075 else:
5075 else:
5076 wctx = repo[None]
5076 wctx = repo[None]
5077 mctx = wctx.parents()[-1]
5077 mctx = wctx.parents()[-1]
5078
5078
5079 # backup pre-resolve (merge uses .orig for its own purposes)
5079 # backup pre-resolve (merge uses .orig for its own purposes)
5080 a = repo.wjoin(f)
5080 a = repo.wjoin(f)
5081 util.copyfile(a, a + ".resolve")
5081 util.copyfile(a, a + ".resolve")
5082
5082
5083 try:
5083 try:
5084 # resolve file
5084 # resolve file
5085 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5085 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5086 if ms.resolve(f, wctx, mctx):
5086 if ms.resolve(f, wctx, mctx):
5087 ret = 1
5087 ret = 1
5088 finally:
5088 finally:
5089 ui.setconfig('ui', 'forcemerge', '')
5089 ui.setconfig('ui', 'forcemerge', '')
5090 ms.commit()
5090 ms.commit()
5091
5091
5092 # replace filemerge's .orig file with our resolve file
5092 # replace filemerge's .orig file with our resolve file
5093 util.rename(a + ".resolve", a + ".orig")
5093 util.rename(a + ".resolve", a + ".orig")
5094
5094
5095 ms.commit()
5095 ms.commit()
5096 return ret
5096 return ret
5097
5097
5098 @command('revert',
5098 @command('revert',
5099 [('a', 'all', None, _('revert all changes when no arguments given')),
5099 [('a', 'all', None, _('revert all changes when no arguments given')),
5100 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5100 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5101 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5101 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5102 ('C', 'no-backup', None, _('do not save backup copies of files')),
5102 ('C', 'no-backup', None, _('do not save backup copies of files')),
5103 ] + walkopts + dryrunopts,
5103 ] + walkopts + dryrunopts,
5104 _('[OPTION]... [-r REV] [NAME]...'))
5104 _('[OPTION]... [-r REV] [NAME]...'))
5105 def revert(ui, repo, *pats, **opts):
5105 def revert(ui, repo, *pats, **opts):
5106 """restore files to their checkout state
5106 """restore files to their checkout state
5107
5107
5108 .. note::
5108 .. note::
5109
5109
5110 To check out earlier revisions, you should use :hg:`update REV`.
5110 To check out earlier revisions, you should use :hg:`update REV`.
5111 To cancel an uncommitted merge (and lose your changes), use
5111 To cancel an uncommitted merge (and lose your changes), use
5112 :hg:`update --clean .`.
5112 :hg:`update --clean .`.
5113
5113
5114 With no revision specified, revert the specified files or directories
5114 With no revision specified, revert the specified files or directories
5115 to the contents they had in the parent of the working directory.
5115 to the contents they had in the parent of the working directory.
5116 This restores the contents of files to an unmodified
5116 This restores the contents of files to an unmodified
5117 state and unschedules adds, removes, copies, and renames. If the
5117 state and unschedules adds, removes, copies, and renames. If the
5118 working directory has two parents, you must explicitly specify a
5118 working directory has two parents, you must explicitly specify a
5119 revision.
5119 revision.
5120
5120
5121 Using the -r/--rev or -d/--date options, revert the given files or
5121 Using the -r/--rev or -d/--date options, revert the given files or
5122 directories to their states as of a specific revision. Because
5122 directories to their states as of a specific revision. Because
5123 revert does not change the working directory parents, this will
5123 revert does not change the working directory parents, this will
5124 cause these files to appear modified. This can be helpful to "back
5124 cause these files to appear modified. This can be helpful to "back
5125 out" some or all of an earlier change. See :hg:`backout` for a
5125 out" some or all of an earlier change. See :hg:`backout` for a
5126 related method.
5126 related method.
5127
5127
5128 Modified files are saved with a .orig suffix before reverting.
5128 Modified files are saved with a .orig suffix before reverting.
5129 To disable these backups, use --no-backup.
5129 To disable these backups, use --no-backup.
5130
5130
5131 See :hg:`help dates` for a list of formats valid for -d/--date.
5131 See :hg:`help dates` for a list of formats valid for -d/--date.
5132
5132
5133 Returns 0 on success.
5133 Returns 0 on success.
5134 """
5134 """
5135
5135
5136 if opts.get("date"):
5136 if opts.get("date"):
5137 if opts.get("rev"):
5137 if opts.get("rev"):
5138 raise util.Abort(_("you can't specify a revision and a date"))
5138 raise util.Abort(_("you can't specify a revision and a date"))
5139 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5139 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5140
5140
5141 parent, p2 = repo.dirstate.parents()
5141 parent, p2 = repo.dirstate.parents()
5142 if not opts.get('rev') and p2 != nullid:
5142 if not opts.get('rev') and p2 != nullid:
5143 # revert after merge is a trap for new users (issue2915)
5143 # revert after merge is a trap for new users (issue2915)
5144 raise util.Abort(_('uncommitted merge with no revision specified'),
5144 raise util.Abort(_('uncommitted merge with no revision specified'),
5145 hint=_('use "hg update" or see "hg help revert"'))
5145 hint=_('use "hg update" or see "hg help revert"'))
5146
5146
5147 ctx = scmutil.revsingle(repo, opts.get('rev'))
5147 ctx = scmutil.revsingle(repo, opts.get('rev'))
5148
5148
5149 if not pats and not opts.get('all'):
5149 if not pats and not opts.get('all'):
5150 msg = _("no files or directories specified")
5150 msg = _("no files or directories specified")
5151 if p2 != nullid:
5151 if p2 != nullid:
5152 hint = _("uncommitted merge, use --all to discard all changes,"
5152 hint = _("uncommitted merge, use --all to discard all changes,"
5153 " or 'hg update -C .' to abort the merge")
5153 " or 'hg update -C .' to abort the merge")
5154 raise util.Abort(msg, hint=hint)
5154 raise util.Abort(msg, hint=hint)
5155 dirty = util.any(repo.status())
5155 dirty = util.any(repo.status())
5156 node = ctx.node()
5156 node = ctx.node()
5157 if node != parent:
5157 if node != parent:
5158 if dirty:
5158 if dirty:
5159 hint = _("uncommitted changes, use --all to discard all"
5159 hint = _("uncommitted changes, use --all to discard all"
5160 " changes, or 'hg update %s' to update") % ctx.rev()
5160 " changes, or 'hg update %s' to update") % ctx.rev()
5161 else:
5161 else:
5162 hint = _("use --all to revert all files,"
5162 hint = _("use --all to revert all files,"
5163 " or 'hg update %s' to update") % ctx.rev()
5163 " or 'hg update %s' to update") % ctx.rev()
5164 elif dirty:
5164 elif dirty:
5165 hint = _("uncommitted changes, use --all to discard all changes")
5165 hint = _("uncommitted changes, use --all to discard all changes")
5166 else:
5166 else:
5167 hint = _("use --all to revert all files")
5167 hint = _("use --all to revert all files")
5168 raise util.Abort(msg, hint=hint)
5168 raise util.Abort(msg, hint=hint)
5169
5169
5170 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5170 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5171
5171
5172 @command('rollback', dryrunopts +
5172 @command('rollback', dryrunopts +
5173 [('f', 'force', False, _('ignore safety measures'))])
5173 [('f', 'force', False, _('ignore safety measures'))])
5174 def rollback(ui, repo, **opts):
5174 def rollback(ui, repo, **opts):
5175 """roll back the last transaction (dangerous)
5175 """roll back the last transaction (dangerous)
5176
5176
5177 This command should be used with care. There is only one level of
5177 This command should be used with care. There is only one level of
5178 rollback, and there is no way to undo a rollback. It will also
5178 rollback, and there is no way to undo a rollback. It will also
5179 restore the dirstate at the time of the last transaction, losing
5179 restore the dirstate at the time of the last transaction, losing
5180 any dirstate changes since that time. This command does not alter
5180 any dirstate changes since that time. This command does not alter
5181 the working directory.
5181 the working directory.
5182
5182
5183 Transactions are used to encapsulate the effects of all commands
5183 Transactions are used to encapsulate the effects of all commands
5184 that create new changesets or propagate existing changesets into a
5184 that create new changesets or propagate existing changesets into a
5185 repository.
5185 repository.
5186
5186
5187 .. container:: verbose
5187 .. container:: verbose
5188
5188
5189 For example, the following commands are transactional, and their
5189 For example, the following commands are transactional, and their
5190 effects can be rolled back:
5190 effects can be rolled back:
5191
5191
5192 - commit
5192 - commit
5193 - import
5193 - import
5194 - pull
5194 - pull
5195 - push (with this repository as the destination)
5195 - push (with this repository as the destination)
5196 - unbundle
5196 - unbundle
5197
5197
5198 To avoid permanent data loss, rollback will refuse to rollback a
5198 To avoid permanent data loss, rollback will refuse to rollback a
5199 commit transaction if it isn't checked out. Use --force to
5199 commit transaction if it isn't checked out. Use --force to
5200 override this protection.
5200 override this protection.
5201
5201
5202 This command is not intended for use on public repositories. Once
5202 This command is not intended for use on public repositories. Once
5203 changes are visible for pull by other users, rolling a transaction
5203 changes are visible for pull by other users, rolling a transaction
5204 back locally is ineffective (someone else may already have pulled
5204 back locally is ineffective (someone else may already have pulled
5205 the changes). Furthermore, a race is possible with readers of the
5205 the changes). Furthermore, a race is possible with readers of the
5206 repository; for example an in-progress pull from the repository
5206 repository; for example an in-progress pull from the repository
5207 may fail if a rollback is performed.
5207 may fail if a rollback is performed.
5208
5208
5209 Returns 0 on success, 1 if no rollback data is available.
5209 Returns 0 on success, 1 if no rollback data is available.
5210 """
5210 """
5211 return repo.rollback(dryrun=opts.get('dry_run'),
5211 return repo.rollback(dryrun=opts.get('dry_run'),
5212 force=opts.get('force'))
5212 force=opts.get('force'))
5213
5213
5214 @command('root', [])
5214 @command('root', [])
5215 def root(ui, repo):
5215 def root(ui, repo):
5216 """print the root (top) of the current working directory
5216 """print the root (top) of the current working directory
5217
5217
5218 Print the root directory of the current repository.
5218 Print the root directory of the current repository.
5219
5219
5220 Returns 0 on success.
5220 Returns 0 on success.
5221 """
5221 """
5222 ui.write(repo.root + "\n")
5222 ui.write(repo.root + "\n")
5223
5223
5224 @command('^serve',
5224 @command('^serve',
5225 [('A', 'accesslog', '', _('name of access log file to write to'),
5225 [('A', 'accesslog', '', _('name of access log file to write to'),
5226 _('FILE')),
5226 _('FILE')),
5227 ('d', 'daemon', None, _('run server in background')),
5227 ('d', 'daemon', None, _('run server in background')),
5228 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5228 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5229 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5229 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5230 # use string type, then we can check if something was passed
5230 # use string type, then we can check if something was passed
5231 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5231 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5232 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5232 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5233 _('ADDR')),
5233 _('ADDR')),
5234 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5234 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5235 _('PREFIX')),
5235 _('PREFIX')),
5236 ('n', 'name', '',
5236 ('n', 'name', '',
5237 _('name to show in web pages (default: working directory)'), _('NAME')),
5237 _('name to show in web pages (default: working directory)'), _('NAME')),
5238 ('', 'web-conf', '',
5238 ('', 'web-conf', '',
5239 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5239 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5240 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5240 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5241 _('FILE')),
5241 _('FILE')),
5242 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5242 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5243 ('', 'stdio', None, _('for remote clients')),
5243 ('', 'stdio', None, _('for remote clients')),
5244 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5244 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5245 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5245 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5246 ('', 'style', '', _('template style to use'), _('STYLE')),
5246 ('', 'style', '', _('template style to use'), _('STYLE')),
5247 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5247 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5248 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5248 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5249 _('[OPTION]...'))
5249 _('[OPTION]...'))
5250 def serve(ui, repo, **opts):
5250 def serve(ui, repo, **opts):
5251 """start stand-alone webserver
5251 """start stand-alone webserver
5252
5252
5253 Start a local HTTP repository browser and pull server. You can use
5253 Start a local HTTP repository browser and pull server. You can use
5254 this for ad-hoc sharing and browsing of repositories. It is
5254 this for ad-hoc sharing and browsing of repositories. It is
5255 recommended to use a real web server to serve a repository for
5255 recommended to use a real web server to serve a repository for
5256 longer periods of time.
5256 longer periods of time.
5257
5257
5258 Please note that the server does not implement access control.
5258 Please note that the server does not implement access control.
5259 This means that, by default, anybody can read from the server and
5259 This means that, by default, anybody can read from the server and
5260 nobody can write to it by default. Set the ``web.allow_push``
5260 nobody can write to it by default. Set the ``web.allow_push``
5261 option to ``*`` to allow everybody to push to the server. You
5261 option to ``*`` to allow everybody to push to the server. You
5262 should use a real web server if you need to authenticate users.
5262 should use a real web server if you need to authenticate users.
5263
5263
5264 By default, the server logs accesses to stdout and errors to
5264 By default, the server logs accesses to stdout and errors to
5265 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5265 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5266 files.
5266 files.
5267
5267
5268 To have the server choose a free port number to listen on, specify
5268 To have the server choose a free port number to listen on, specify
5269 a port number of 0; in this case, the server will print the port
5269 a port number of 0; in this case, the server will print the port
5270 number it uses.
5270 number it uses.
5271
5271
5272 Returns 0 on success.
5272 Returns 0 on success.
5273 """
5273 """
5274
5274
5275 if opts["stdio"] and opts["cmdserver"]:
5275 if opts["stdio"] and opts["cmdserver"]:
5276 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5276 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5277
5277
5278 def checkrepo():
5278 def checkrepo():
5279 if repo is None:
5279 if repo is None:
5280 raise error.RepoError(_("there is no Mercurial repository here"
5280 raise error.RepoError(_("there is no Mercurial repository here"
5281 " (.hg not found)"))
5281 " (.hg not found)"))
5282
5282
5283 if opts["stdio"]:
5283 if opts["stdio"]:
5284 checkrepo()
5284 checkrepo()
5285 s = sshserver.sshserver(ui, repo)
5285 s = sshserver.sshserver(ui, repo)
5286 s.serve_forever()
5286 s.serve_forever()
5287
5287
5288 if opts["cmdserver"]:
5288 if opts["cmdserver"]:
5289 checkrepo()
5289 checkrepo()
5290 s = commandserver.server(ui, repo, opts["cmdserver"])
5290 s = commandserver.server(ui, repo, opts["cmdserver"])
5291 return s.serve()
5291 return s.serve()
5292
5292
5293 # this way we can check if something was given in the command-line
5293 # this way we can check if something was given in the command-line
5294 if opts.get('port'):
5294 if opts.get('port'):
5295 opts['port'] = util.getport(opts.get('port'))
5295 opts['port'] = util.getport(opts.get('port'))
5296
5296
5297 baseui = repo and repo.baseui or ui
5297 baseui = repo and repo.baseui or ui
5298 optlist = ("name templates style address port prefix ipv6"
5298 optlist = ("name templates style address port prefix ipv6"
5299 " accesslog errorlog certificate encoding")
5299 " accesslog errorlog certificate encoding")
5300 for o in optlist.split():
5300 for o in optlist.split():
5301 val = opts.get(o, '')
5301 val = opts.get(o, '')
5302 if val in (None, ''): # should check against default options instead
5302 if val in (None, ''): # should check against default options instead
5303 continue
5303 continue
5304 baseui.setconfig("web", o, val)
5304 baseui.setconfig("web", o, val)
5305 if repo and repo.ui != baseui:
5305 if repo and repo.ui != baseui:
5306 repo.ui.setconfig("web", o, val)
5306 repo.ui.setconfig("web", o, val)
5307
5307
5308 o = opts.get('web_conf') or opts.get('webdir_conf')
5308 o = opts.get('web_conf') or opts.get('webdir_conf')
5309 if not o:
5309 if not o:
5310 if not repo:
5310 if not repo:
5311 raise error.RepoError(_("there is no Mercurial repository"
5311 raise error.RepoError(_("there is no Mercurial repository"
5312 " here (.hg not found)"))
5312 " here (.hg not found)"))
5313 o = repo.root
5313 o = repo.root
5314
5314
5315 app = hgweb.hgweb(o, baseui=ui)
5315 app = hgweb.hgweb(o, baseui=ui)
5316
5316
5317 class service(object):
5317 class service(object):
5318 def init(self):
5318 def init(self):
5319 util.setsignalhandler()
5319 util.setsignalhandler()
5320 self.httpd = hgweb.server.create_server(ui, app)
5320 self.httpd = hgweb.server.create_server(ui, app)
5321
5321
5322 if opts['port'] and not ui.verbose:
5322 if opts['port'] and not ui.verbose:
5323 return
5323 return
5324
5324
5325 if self.httpd.prefix:
5325 if self.httpd.prefix:
5326 prefix = self.httpd.prefix.strip('/') + '/'
5326 prefix = self.httpd.prefix.strip('/') + '/'
5327 else:
5327 else:
5328 prefix = ''
5328 prefix = ''
5329
5329
5330 port = ':%d' % self.httpd.port
5330 port = ':%d' % self.httpd.port
5331 if port == ':80':
5331 if port == ':80':
5332 port = ''
5332 port = ''
5333
5333
5334 bindaddr = self.httpd.addr
5334 bindaddr = self.httpd.addr
5335 if bindaddr == '0.0.0.0':
5335 if bindaddr == '0.0.0.0':
5336 bindaddr = '*'
5336 bindaddr = '*'
5337 elif ':' in bindaddr: # IPv6
5337 elif ':' in bindaddr: # IPv6
5338 bindaddr = '[%s]' % bindaddr
5338 bindaddr = '[%s]' % bindaddr
5339
5339
5340 fqaddr = self.httpd.fqaddr
5340 fqaddr = self.httpd.fqaddr
5341 if ':' in fqaddr:
5341 if ':' in fqaddr:
5342 fqaddr = '[%s]' % fqaddr
5342 fqaddr = '[%s]' % fqaddr
5343 if opts['port']:
5343 if opts['port']:
5344 write = ui.status
5344 write = ui.status
5345 else:
5345 else:
5346 write = ui.write
5346 write = ui.write
5347 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5347 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5348 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5348 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5349
5349
5350 def run(self):
5350 def run(self):
5351 self.httpd.serve_forever()
5351 self.httpd.serve_forever()
5352
5352
5353 service = service()
5353 service = service()
5354
5354
5355 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5355 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5356
5356
5357 @command('showconfig|debugconfig',
5357 @command('showconfig|debugconfig',
5358 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5358 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5359 _('[-u] [NAME]...'))
5359 _('[-u] [NAME]...'))
5360 def showconfig(ui, repo, *values, **opts):
5360 def showconfig(ui, repo, *values, **opts):
5361 """show combined config settings from all hgrc files
5361 """show combined config settings from all hgrc files
5362
5362
5363 With no arguments, print names and values of all config items.
5363 With no arguments, print names and values of all config items.
5364
5364
5365 With one argument of the form section.name, print just the value
5365 With one argument of the form section.name, print just the value
5366 of that config item.
5366 of that config item.
5367
5367
5368 With multiple arguments, print names and values of all config
5368 With multiple arguments, print names and values of all config
5369 items with matching section names.
5369 items with matching section names.
5370
5370
5371 With --debug, the source (filename and line number) is printed
5371 With --debug, the source (filename and line number) is printed
5372 for each config item.
5372 for each config item.
5373
5373
5374 Returns 0 on success.
5374 Returns 0 on success.
5375 """
5375 """
5376
5376
5377 for f in scmutil.rcpath():
5377 for f in scmutil.rcpath():
5378 ui.debug('read config from: %s\n' % f)
5378 ui.debug('read config from: %s\n' % f)
5379 untrusted = bool(opts.get('untrusted'))
5379 untrusted = bool(opts.get('untrusted'))
5380 if values:
5380 if values:
5381 sections = [v for v in values if '.' not in v]
5381 sections = [v for v in values if '.' not in v]
5382 items = [v for v in values if '.' in v]
5382 items = [v for v in values if '.' in v]
5383 if len(items) > 1 or items and sections:
5383 if len(items) > 1 or items and sections:
5384 raise util.Abort(_('only one config item permitted'))
5384 raise util.Abort(_('only one config item permitted'))
5385 for section, name, value in ui.walkconfig(untrusted=untrusted):
5385 for section, name, value in ui.walkconfig(untrusted=untrusted):
5386 value = str(value).replace('\n', '\\n')
5386 value = str(value).replace('\n', '\\n')
5387 sectname = section + '.' + name
5387 sectname = section + '.' + name
5388 if values:
5388 if values:
5389 for v in values:
5389 for v in values:
5390 if v == section:
5390 if v == section:
5391 ui.debug('%s: ' %
5391 ui.debug('%s: ' %
5392 ui.configsource(section, name, untrusted))
5392 ui.configsource(section, name, untrusted))
5393 ui.write('%s=%s\n' % (sectname, value))
5393 ui.write('%s=%s\n' % (sectname, value))
5394 elif v == sectname:
5394 elif v == sectname:
5395 ui.debug('%s: ' %
5395 ui.debug('%s: ' %
5396 ui.configsource(section, name, untrusted))
5396 ui.configsource(section, name, untrusted))
5397 ui.write(value, '\n')
5397 ui.write(value, '\n')
5398 else:
5398 else:
5399 ui.debug('%s: ' %
5399 ui.debug('%s: ' %
5400 ui.configsource(section, name, untrusted))
5400 ui.configsource(section, name, untrusted))
5401 ui.write('%s=%s\n' % (sectname, value))
5401 ui.write('%s=%s\n' % (sectname, value))
5402
5402
5403 @command('^status|st',
5403 @command('^status|st',
5404 [('A', 'all', None, _('show status of all files')),
5404 [('A', 'all', None, _('show status of all files')),
5405 ('m', 'modified', None, _('show only modified files')),
5405 ('m', 'modified', None, _('show only modified files')),
5406 ('a', 'added', None, _('show only added files')),
5406 ('a', 'added', None, _('show only added files')),
5407 ('r', 'removed', None, _('show only removed files')),
5407 ('r', 'removed', None, _('show only removed files')),
5408 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5408 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5409 ('c', 'clean', None, _('show only files without changes')),
5409 ('c', 'clean', None, _('show only files without changes')),
5410 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5410 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5411 ('i', 'ignored', None, _('show only ignored files')),
5411 ('i', 'ignored', None, _('show only ignored files')),
5412 ('n', 'no-status', None, _('hide status prefix')),
5412 ('n', 'no-status', None, _('hide status prefix')),
5413 ('C', 'copies', None, _('show source of copied files')),
5413 ('C', 'copies', None, _('show source of copied files')),
5414 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5414 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5415 ('', 'rev', [], _('show difference from revision'), _('REV')),
5415 ('', 'rev', [], _('show difference from revision'), _('REV')),
5416 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5416 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5417 ] + walkopts + subrepoopts,
5417 ] + walkopts + subrepoopts,
5418 _('[OPTION]... [FILE]...'))
5418 _('[OPTION]... [FILE]...'))
5419 def status(ui, repo, *pats, **opts):
5419 def status(ui, repo, *pats, **opts):
5420 """show changed files in the working directory
5420 """show changed files in the working directory
5421
5421
5422 Show status of files in the repository. If names are given, only
5422 Show status of files in the repository. If names are given, only
5423 files that match are shown. Files that are clean or ignored or
5423 files that match are shown. Files that are clean or ignored or
5424 the source of a copy/move operation, are not listed unless
5424 the source of a copy/move operation, are not listed unless
5425 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5425 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5426 Unless options described with "show only ..." are given, the
5426 Unless options described with "show only ..." are given, the
5427 options -mardu are used.
5427 options -mardu are used.
5428
5428
5429 Option -q/--quiet hides untracked (unknown and ignored) files
5429 Option -q/--quiet hides untracked (unknown and ignored) files
5430 unless explicitly requested with -u/--unknown or -i/--ignored.
5430 unless explicitly requested with -u/--unknown or -i/--ignored.
5431
5431
5432 .. note::
5432 .. note::
5433 status may appear to disagree with diff if permissions have
5433 status may appear to disagree with diff if permissions have
5434 changed or a merge has occurred. The standard diff format does
5434 changed or a merge has occurred. The standard diff format does
5435 not report permission changes and diff only reports changes
5435 not report permission changes and diff only reports changes
5436 relative to one merge parent.
5436 relative to one merge parent.
5437
5437
5438 If one revision is given, it is used as the base revision.
5438 If one revision is given, it is used as the base revision.
5439 If two revisions are given, the differences between them are
5439 If two revisions are given, the differences between them are
5440 shown. The --change option can also be used as a shortcut to list
5440 shown. The --change option can also be used as a shortcut to list
5441 the changed files of a revision from its first parent.
5441 the changed files of a revision from its first parent.
5442
5442
5443 The codes used to show the status of files are::
5443 The codes used to show the status of files are::
5444
5444
5445 M = modified
5445 M = modified
5446 A = added
5446 A = added
5447 R = removed
5447 R = removed
5448 C = clean
5448 C = clean
5449 ! = missing (deleted by non-hg command, but still tracked)
5449 ! = missing (deleted by non-hg command, but still tracked)
5450 ? = not tracked
5450 ? = not tracked
5451 I = ignored
5451 I = ignored
5452 = origin of the previous file listed as A (added)
5452 = origin of the previous file listed as A (added)
5453
5453
5454 .. container:: verbose
5454 .. container:: verbose
5455
5455
5456 Examples:
5456 Examples:
5457
5457
5458 - show changes in the working directory relative to a
5458 - show changes in the working directory relative to a
5459 changeset::
5459 changeset::
5460
5460
5461 hg status --rev 9353
5461 hg status --rev 9353
5462
5462
5463 - show all changes including copies in an existing changeset::
5463 - show all changes including copies in an existing changeset::
5464
5464
5465 hg status --copies --change 9353
5465 hg status --copies --change 9353
5466
5466
5467 - get a NUL separated list of added files, suitable for xargs::
5467 - get a NUL separated list of added files, suitable for xargs::
5468
5468
5469 hg status -an0
5469 hg status -an0
5470
5470
5471 Returns 0 on success.
5471 Returns 0 on success.
5472 """
5472 """
5473
5473
5474 revs = opts.get('rev')
5474 revs = opts.get('rev')
5475 change = opts.get('change')
5475 change = opts.get('change')
5476
5476
5477 if revs and change:
5477 if revs and change:
5478 msg = _('cannot specify --rev and --change at the same time')
5478 msg = _('cannot specify --rev and --change at the same time')
5479 raise util.Abort(msg)
5479 raise util.Abort(msg)
5480 elif change:
5480 elif change:
5481 node2 = scmutil.revsingle(repo, change, None).node()
5481 node2 = scmutil.revsingle(repo, change, None).node()
5482 node1 = repo[node2].p1().node()
5482 node1 = repo[node2].p1().node()
5483 else:
5483 else:
5484 node1, node2 = scmutil.revpair(repo, revs)
5484 node1, node2 = scmutil.revpair(repo, revs)
5485
5485
5486 cwd = (pats and repo.getcwd()) or ''
5486 cwd = (pats and repo.getcwd()) or ''
5487 end = opts.get('print0') and '\0' or '\n'
5487 end = opts.get('print0') and '\0' or '\n'
5488 copy = {}
5488 copy = {}
5489 states = 'modified added removed deleted unknown ignored clean'.split()
5489 states = 'modified added removed deleted unknown ignored clean'.split()
5490 show = [k for k in states if opts.get(k)]
5490 show = [k for k in states if opts.get(k)]
5491 if opts.get('all'):
5491 if opts.get('all'):
5492 show += ui.quiet and (states[:4] + ['clean']) or states
5492 show += ui.quiet and (states[:4] + ['clean']) or states
5493 if not show:
5493 if not show:
5494 show = ui.quiet and states[:4] or states[:5]
5494 show = ui.quiet and states[:4] or states[:5]
5495
5495
5496 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5496 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5497 'ignored' in show, 'clean' in show, 'unknown' in show,
5497 'ignored' in show, 'clean' in show, 'unknown' in show,
5498 opts.get('subrepos'))
5498 opts.get('subrepos'))
5499 changestates = zip(states, 'MAR!?IC', stat)
5499 changestates = zip(states, 'MAR!?IC', stat)
5500
5500
5501 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5501 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5502 copy = copies.pathcopies(repo[node1], repo[node2])
5502 copy = copies.pathcopies(repo[node1], repo[node2])
5503
5503
5504 fm = ui.formatter('status', opts)
5504 fm = ui.formatter('status', opts)
5505 fmt = '%s' + end
5505 fmt = '%s' + end
5506 showchar = not opts.get('no_status')
5506 showchar = not opts.get('no_status')
5507
5507
5508 for state, char, files in changestates:
5508 for state, char, files in changestates:
5509 if state in show:
5509 if state in show:
5510 label = 'status.' + state
5510 label = 'status.' + state
5511 for f in files:
5511 for f in files:
5512 fm.startitem()
5512 fm.startitem()
5513 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5513 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5514 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5514 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5515 if f in copy:
5515 if f in copy:
5516 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5516 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5517 label='status.copied')
5517 label='status.copied')
5518 fm.end()
5518 fm.end()
5519
5519
5520 @command('^summary|sum',
5520 @command('^summary|sum',
5521 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5521 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5522 def summary(ui, repo, **opts):
5522 def summary(ui, repo, **opts):
5523 """summarize working directory state
5523 """summarize working directory state
5524
5524
5525 This generates a brief summary of the working directory state,
5525 This generates a brief summary of the working directory state,
5526 including parents, branch, commit status, and available updates.
5526 including parents, branch, commit status, and available updates.
5527
5527
5528 With the --remote option, this will check the default paths for
5528 With the --remote option, this will check the default paths for
5529 incoming and outgoing changes. This can be time-consuming.
5529 incoming and outgoing changes. This can be time-consuming.
5530
5530
5531 Returns 0 on success.
5531 Returns 0 on success.
5532 """
5532 """
5533
5533
5534 ctx = repo[None]
5534 ctx = repo[None]
5535 parents = ctx.parents()
5535 parents = ctx.parents()
5536 pnode = parents[0].node()
5536 pnode = parents[0].node()
5537 marks = []
5537 marks = []
5538
5538
5539 for p in parents:
5539 for p in parents:
5540 # label with log.changeset (instead of log.parent) since this
5540 # label with log.changeset (instead of log.parent) since this
5541 # shows a working directory parent *changeset*:
5541 # shows a working directory parent *changeset*:
5542 # i18n: column positioning for "hg summary"
5542 # i18n: column positioning for "hg summary"
5543 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5543 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5544 label='log.changeset changeset.%s' % p.phasestr())
5544 label='log.changeset changeset.%s' % p.phasestr())
5545 ui.write(' '.join(p.tags()), label='log.tag')
5545 ui.write(' '.join(p.tags()), label='log.tag')
5546 if p.bookmarks():
5546 if p.bookmarks():
5547 marks.extend(p.bookmarks())
5547 marks.extend(p.bookmarks())
5548 if p.rev() == -1:
5548 if p.rev() == -1:
5549 if not len(repo):
5549 if not len(repo):
5550 ui.write(_(' (empty repository)'))
5550 ui.write(_(' (empty repository)'))
5551 else:
5551 else:
5552 ui.write(_(' (no revision checked out)'))
5552 ui.write(_(' (no revision checked out)'))
5553 ui.write('\n')
5553 ui.write('\n')
5554 if p.description():
5554 if p.description():
5555 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5555 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5556 label='log.summary')
5556 label='log.summary')
5557
5557
5558 branch = ctx.branch()
5558 branch = ctx.branch()
5559 bheads = repo.branchheads(branch)
5559 bheads = repo.branchheads(branch)
5560 # i18n: column positioning for "hg summary"
5560 # i18n: column positioning for "hg summary"
5561 m = _('branch: %s\n') % branch
5561 m = _('branch: %s\n') % branch
5562 if branch != 'default':
5562 if branch != 'default':
5563 ui.write(m, label='log.branch')
5563 ui.write(m, label='log.branch')
5564 else:
5564 else:
5565 ui.status(m, label='log.branch')
5565 ui.status(m, label='log.branch')
5566
5566
5567 if marks:
5567 if marks:
5568 current = repo._bookmarkcurrent
5568 current = repo._bookmarkcurrent
5569 # i18n: column positioning for "hg summary"
5569 # i18n: column positioning for "hg summary"
5570 ui.write(_('bookmarks:'), label='log.bookmark')
5570 ui.write(_('bookmarks:'), label='log.bookmark')
5571 if current is not None:
5571 if current is not None:
5572 try:
5572 try:
5573 marks.remove(current)
5573 marks.remove(current)
5574 ui.write(' *' + current, label='bookmarks.current')
5574 ui.write(' *' + current, label='bookmarks.current')
5575 except ValueError:
5575 except ValueError:
5576 # current bookmark not in parent ctx marks
5576 # current bookmark not in parent ctx marks
5577 pass
5577 pass
5578 for m in marks:
5578 for m in marks:
5579 ui.write(' ' + m, label='log.bookmark')
5579 ui.write(' ' + m, label='log.bookmark')
5580 ui.write('\n', label='log.bookmark')
5580 ui.write('\n', label='log.bookmark')
5581
5581
5582 st = list(repo.status(unknown=True))[:6]
5582 st = list(repo.status(unknown=True))[:6]
5583
5583
5584 c = repo.dirstate.copies()
5584 c = repo.dirstate.copies()
5585 copied, renamed = [], []
5585 copied, renamed = [], []
5586 for d, s in c.iteritems():
5586 for d, s in c.iteritems():
5587 if s in st[2]:
5587 if s in st[2]:
5588 st[2].remove(s)
5588 st[2].remove(s)
5589 renamed.append(d)
5589 renamed.append(d)
5590 else:
5590 else:
5591 copied.append(d)
5591 copied.append(d)
5592 if d in st[1]:
5592 if d in st[1]:
5593 st[1].remove(d)
5593 st[1].remove(d)
5594 st.insert(3, renamed)
5594 st.insert(3, renamed)
5595 st.insert(4, copied)
5595 st.insert(4, copied)
5596
5596
5597 ms = mergemod.mergestate(repo)
5597 ms = mergemod.mergestate(repo)
5598 st.append([f for f in ms if ms[f] == 'u'])
5598 st.append([f for f in ms if ms[f] == 'u'])
5599
5599
5600 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5600 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5601 st.append(subs)
5601 st.append(subs)
5602
5602
5603 labels = [ui.label(_('%d modified'), 'status.modified'),
5603 labels = [ui.label(_('%d modified'), 'status.modified'),
5604 ui.label(_('%d added'), 'status.added'),
5604 ui.label(_('%d added'), 'status.added'),
5605 ui.label(_('%d removed'), 'status.removed'),
5605 ui.label(_('%d removed'), 'status.removed'),
5606 ui.label(_('%d renamed'), 'status.copied'),
5606 ui.label(_('%d renamed'), 'status.copied'),
5607 ui.label(_('%d copied'), 'status.copied'),
5607 ui.label(_('%d copied'), 'status.copied'),
5608 ui.label(_('%d deleted'), 'status.deleted'),
5608 ui.label(_('%d deleted'), 'status.deleted'),
5609 ui.label(_('%d unknown'), 'status.unknown'),
5609 ui.label(_('%d unknown'), 'status.unknown'),
5610 ui.label(_('%d ignored'), 'status.ignored'),
5610 ui.label(_('%d ignored'), 'status.ignored'),
5611 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5611 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5612 ui.label(_('%d subrepos'), 'status.modified')]
5612 ui.label(_('%d subrepos'), 'status.modified')]
5613 t = []
5613 t = []
5614 for s, l in zip(st, labels):
5614 for s, l in zip(st, labels):
5615 if s:
5615 if s:
5616 t.append(l % len(s))
5616 t.append(l % len(s))
5617
5617
5618 t = ', '.join(t)
5618 t = ', '.join(t)
5619 cleanworkdir = False
5619 cleanworkdir = False
5620
5620
5621 if len(parents) > 1:
5621 if len(parents) > 1:
5622 t += _(' (merge)')
5622 t += _(' (merge)')
5623 elif branch != parents[0].branch():
5623 elif branch != parents[0].branch():
5624 t += _(' (new branch)')
5624 t += _(' (new branch)')
5625 elif (parents[0].closesbranch() and
5625 elif (parents[0].closesbranch() and
5626 pnode in repo.branchheads(branch, closed=True)):
5626 pnode in repo.branchheads(branch, closed=True)):
5627 t += _(' (head closed)')
5627 t += _(' (head closed)')
5628 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5628 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5629 t += _(' (clean)')
5629 t += _(' (clean)')
5630 cleanworkdir = True
5630 cleanworkdir = True
5631 elif pnode not in bheads:
5631 elif pnode not in bheads:
5632 t += _(' (new branch head)')
5632 t += _(' (new branch head)')
5633
5633
5634 if cleanworkdir:
5634 if cleanworkdir:
5635 # i18n: column positioning for "hg summary"
5635 # i18n: column positioning for "hg summary"
5636 ui.status(_('commit: %s\n') % t.strip())
5636 ui.status(_('commit: %s\n') % t.strip())
5637 else:
5637 else:
5638 # i18n: column positioning for "hg summary"
5638 # i18n: column positioning for "hg summary"
5639 ui.write(_('commit: %s\n') % t.strip())
5639 ui.write(_('commit: %s\n') % t.strip())
5640
5640
5641 # all ancestors of branch heads - all ancestors of parent = new csets
5641 # all ancestors of branch heads - all ancestors of parent = new csets
5642 new = [0] * len(repo)
5642 new = [0] * len(repo)
5643 cl = repo.changelog
5643 cl = repo.changelog
5644 for a in [cl.rev(n) for n in bheads]:
5644 for a in [cl.rev(n) for n in bheads]:
5645 new[a] = 1
5645 new[a] = 1
5646 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5646 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5647 new[a] = 1
5647 new[a] = 1
5648 for a in [p.rev() for p in parents]:
5648 for a in [p.rev() for p in parents]:
5649 if a >= 0:
5649 if a >= 0:
5650 new[a] = 0
5650 new[a] = 0
5651 for a in cl.ancestors([p.rev() for p in parents]):
5651 for a in cl.ancestors([p.rev() for p in parents]):
5652 new[a] = 0
5652 new[a] = 0
5653 new = sum(new)
5653 new = sum(new)
5654
5654
5655 if new == 0:
5655 if new == 0:
5656 # i18n: column positioning for "hg summary"
5656 # i18n: column positioning for "hg summary"
5657 ui.status(_('update: (current)\n'))
5657 ui.status(_('update: (current)\n'))
5658 elif pnode not in bheads:
5658 elif pnode not in bheads:
5659 # i18n: column positioning for "hg summary"
5659 # i18n: column positioning for "hg summary"
5660 ui.write(_('update: %d new changesets (update)\n') % new)
5660 ui.write(_('update: %d new changesets (update)\n') % new)
5661 else:
5661 else:
5662 # i18n: column positioning for "hg summary"
5662 # i18n: column positioning for "hg summary"
5663 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5663 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5664 (new, len(bheads)))
5664 (new, len(bheads)))
5665
5665
5666 if opts.get('remote'):
5666 if opts.get('remote'):
5667 t = []
5667 t = []
5668 source, branches = hg.parseurl(ui.expandpath('default'))
5668 source, branches = hg.parseurl(ui.expandpath('default'))
5669 other = hg.peer(repo, {}, source)
5669 other = hg.peer(repo, {}, source)
5670 revs, checkout = hg.addbranchrevs(repo, other, branches,
5670 revs, checkout = hg.addbranchrevs(repo, other, branches,
5671 opts.get('rev'))
5671 opts.get('rev'))
5672 ui.debug('comparing with %s\n' % util.hidepassword(source))
5672 ui.debug('comparing with %s\n' % util.hidepassword(source))
5673 repo.ui.pushbuffer()
5673 repo.ui.pushbuffer()
5674 commoninc = discovery.findcommonincoming(repo, other)
5674 commoninc = discovery.findcommonincoming(repo, other)
5675 _common, incoming, _rheads = commoninc
5675 _common, incoming, _rheads = commoninc
5676 repo.ui.popbuffer()
5676 repo.ui.popbuffer()
5677 if incoming:
5677 if incoming:
5678 t.append(_('1 or more incoming'))
5678 t.append(_('1 or more incoming'))
5679
5679
5680 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5680 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5681 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5681 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5682 if source != dest:
5682 if source != dest:
5683 other = hg.peer(repo, {}, dest)
5683 other = hg.peer(repo, {}, dest)
5684 commoninc = None
5684 commoninc = None
5685 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5685 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5686 repo.ui.pushbuffer()
5686 repo.ui.pushbuffer()
5687 outgoing = discovery.findcommonoutgoing(repo, other,
5687 outgoing = discovery.findcommonoutgoing(repo, other,
5688 commoninc=commoninc)
5688 commoninc=commoninc)
5689 repo.ui.popbuffer()
5689 repo.ui.popbuffer()
5690 o = outgoing.missing
5690 o = outgoing.missing
5691 if o:
5691 if o:
5692 t.append(_('%d outgoing') % len(o))
5692 t.append(_('%d outgoing') % len(o))
5693 if 'bookmarks' in other.listkeys('namespaces'):
5693 if 'bookmarks' in other.listkeys('namespaces'):
5694 lmarks = repo.listkeys('bookmarks')
5694 lmarks = repo.listkeys('bookmarks')
5695 rmarks = other.listkeys('bookmarks')
5695 rmarks = other.listkeys('bookmarks')
5696 diff = set(rmarks) - set(lmarks)
5696 diff = set(rmarks) - set(lmarks)
5697 if len(diff) > 0:
5697 if len(diff) > 0:
5698 t.append(_('%d incoming bookmarks') % len(diff))
5698 t.append(_('%d incoming bookmarks') % len(diff))
5699 diff = set(lmarks) - set(rmarks)
5699 diff = set(lmarks) - set(rmarks)
5700 if len(diff) > 0:
5700 if len(diff) > 0:
5701 t.append(_('%d outgoing bookmarks') % len(diff))
5701 t.append(_('%d outgoing bookmarks') % len(diff))
5702
5702
5703 if t:
5703 if t:
5704 # i18n: column positioning for "hg summary"
5704 # i18n: column positioning for "hg summary"
5705 ui.write(_('remote: %s\n') % (', '.join(t)))
5705 ui.write(_('remote: %s\n') % (', '.join(t)))
5706 else:
5706 else:
5707 # i18n: column positioning for "hg summary"
5707 # i18n: column positioning for "hg summary"
5708 ui.status(_('remote: (synced)\n'))
5708 ui.status(_('remote: (synced)\n'))
5709
5709
5710 @command('tag',
5710 @command('tag',
5711 [('f', 'force', None, _('force tag')),
5711 [('f', 'force', None, _('force tag')),
5712 ('l', 'local', None, _('make the tag local')),
5712 ('l', 'local', None, _('make the tag local')),
5713 ('r', 'rev', '', _('revision to tag'), _('REV')),
5713 ('r', 'rev', '', _('revision to tag'), _('REV')),
5714 ('', 'remove', None, _('remove a tag')),
5714 ('', 'remove', None, _('remove a tag')),
5715 # -l/--local is already there, commitopts cannot be used
5715 # -l/--local is already there, commitopts cannot be used
5716 ('e', 'edit', None, _('edit commit message')),
5716 ('e', 'edit', None, _('edit commit message')),
5717 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5717 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5718 ] + commitopts2,
5718 ] + commitopts2,
5719 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5719 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5720 def tag(ui, repo, name1, *names, **opts):
5720 def tag(ui, repo, name1, *names, **opts):
5721 """add one or more tags for the current or given revision
5721 """add one or more tags for the current or given revision
5722
5722
5723 Name a particular revision using <name>.
5723 Name a particular revision using <name>.
5724
5724
5725 Tags are used to name particular revisions of the repository and are
5725 Tags are used to name particular revisions of the repository and are
5726 very useful to compare different revisions, to go back to significant
5726 very useful to compare different revisions, to go back to significant
5727 earlier versions or to mark branch points as releases, etc. Changing
5727 earlier versions or to mark branch points as releases, etc. Changing
5728 an existing tag is normally disallowed; use -f/--force to override.
5728 an existing tag is normally disallowed; use -f/--force to override.
5729
5729
5730 If no revision is given, the parent of the working directory is
5730 If no revision is given, the parent of the working directory is
5731 used, or tip if no revision is checked out.
5731 used, or tip if no revision is checked out.
5732
5732
5733 To facilitate version control, distribution, and merging of tags,
5733 To facilitate version control, distribution, and merging of tags,
5734 they are stored as a file named ".hgtags" which is managed similarly
5734 they are stored as a file named ".hgtags" which is managed similarly
5735 to other project files and can be hand-edited if necessary. This
5735 to other project files and can be hand-edited if necessary. This
5736 also means that tagging creates a new commit. The file
5736 also means that tagging creates a new commit. The file
5737 ".hg/localtags" is used for local tags (not shared among
5737 ".hg/localtags" is used for local tags (not shared among
5738 repositories).
5738 repositories).
5739
5739
5740 Tag commits are usually made at the head of a branch. If the parent
5740 Tag commits are usually made at the head of a branch. If the parent
5741 of the working directory is not a branch head, :hg:`tag` aborts; use
5741 of the working directory is not a branch head, :hg:`tag` aborts; use
5742 -f/--force to force the tag commit to be based on a non-head
5742 -f/--force to force the tag commit to be based on a non-head
5743 changeset.
5743 changeset.
5744
5744
5745 See :hg:`help dates` for a list of formats valid for -d/--date.
5745 See :hg:`help dates` for a list of formats valid for -d/--date.
5746
5746
5747 Since tag names have priority over branch names during revision
5747 Since tag names have priority over branch names during revision
5748 lookup, using an existing branch name as a tag name is discouraged.
5748 lookup, using an existing branch name as a tag name is discouraged.
5749
5749
5750 Returns 0 on success.
5750 Returns 0 on success.
5751 """
5751 """
5752 wlock = lock = None
5752 wlock = lock = None
5753 try:
5753 try:
5754 wlock = repo.wlock()
5754 wlock = repo.wlock()
5755 lock = repo.lock()
5755 lock = repo.lock()
5756 rev_ = "."
5756 rev_ = "."
5757 names = [t.strip() for t in (name1,) + names]
5757 names = [t.strip() for t in (name1,) + names]
5758 if len(names) != len(set(names)):
5758 if len(names) != len(set(names)):
5759 raise util.Abort(_('tag names must be unique'))
5759 raise util.Abort(_('tag names must be unique'))
5760 for n in names:
5760 for n in names:
5761 scmutil.checknewlabel(repo, n, 'tag')
5761 scmutil.checknewlabel(repo, n, 'tag')
5762 if not n:
5762 if not n:
5763 raise util.Abort(_('tag names cannot consist entirely of '
5763 raise util.Abort(_('tag names cannot consist entirely of '
5764 'whitespace'))
5764 'whitespace'))
5765 if opts.get('rev') and opts.get('remove'):
5765 if opts.get('rev') and opts.get('remove'):
5766 raise util.Abort(_("--rev and --remove are incompatible"))
5766 raise util.Abort(_("--rev and --remove are incompatible"))
5767 if opts.get('rev'):
5767 if opts.get('rev'):
5768 rev_ = opts['rev']
5768 rev_ = opts['rev']
5769 message = opts.get('message')
5769 message = opts.get('message')
5770 if opts.get('remove'):
5770 if opts.get('remove'):
5771 expectedtype = opts.get('local') and 'local' or 'global'
5771 expectedtype = opts.get('local') and 'local' or 'global'
5772 for n in names:
5772 for n in names:
5773 if not repo.tagtype(n):
5773 if not repo.tagtype(n):
5774 raise util.Abort(_("tag '%s' does not exist") % n)
5774 raise util.Abort(_("tag '%s' does not exist") % n)
5775 if repo.tagtype(n) != expectedtype:
5775 if repo.tagtype(n) != expectedtype:
5776 if expectedtype == 'global':
5776 if expectedtype == 'global':
5777 raise util.Abort(_("tag '%s' is not a global tag") % n)
5777 raise util.Abort(_("tag '%s' is not a global tag") % n)
5778 else:
5778 else:
5779 raise util.Abort(_("tag '%s' is not a local tag") % n)
5779 raise util.Abort(_("tag '%s' is not a local tag") % n)
5780 rev_ = nullid
5780 rev_ = nullid
5781 if not message:
5781 if not message:
5782 # we don't translate commit messages
5782 # we don't translate commit messages
5783 message = 'Removed tag %s' % ', '.join(names)
5783 message = 'Removed tag %s' % ', '.join(names)
5784 elif not opts.get('force'):
5784 elif not opts.get('force'):
5785 for n in names:
5785 for n in names:
5786 if n in repo.tags():
5786 if n in repo.tags():
5787 raise util.Abort(_("tag '%s' already exists "
5787 raise util.Abort(_("tag '%s' already exists "
5788 "(use -f to force)") % n)
5788 "(use -f to force)") % n)
5789 if not opts.get('local'):
5789 if not opts.get('local'):
5790 p1, p2 = repo.dirstate.parents()
5790 p1, p2 = repo.dirstate.parents()
5791 if p2 != nullid:
5791 if p2 != nullid:
5792 raise util.Abort(_('uncommitted merge'))
5792 raise util.Abort(_('uncommitted merge'))
5793 bheads = repo.branchheads()
5793 bheads = repo.branchheads()
5794 if not opts.get('force') and bheads and p1 not in bheads:
5794 if not opts.get('force') and bheads and p1 not in bheads:
5795 raise util.Abort(_('not at a branch head (use -f to force)'))
5795 raise util.Abort(_('not at a branch head (use -f to force)'))
5796 r = scmutil.revsingle(repo, rev_).node()
5796 r = scmutil.revsingle(repo, rev_).node()
5797
5797
5798 if not message:
5798 if not message:
5799 # we don't translate commit messages
5799 # we don't translate commit messages
5800 message = ('Added tag %s for changeset %s' %
5800 message = ('Added tag %s for changeset %s' %
5801 (', '.join(names), short(r)))
5801 (', '.join(names), short(r)))
5802
5802
5803 date = opts.get('date')
5803 date = opts.get('date')
5804 if date:
5804 if date:
5805 date = util.parsedate(date)
5805 date = util.parsedate(date)
5806
5806
5807 if opts.get('edit'):
5807 if opts.get('edit'):
5808 message = ui.edit(message, ui.username())
5808 message = ui.edit(message, ui.username())
5809
5809
5810 # don't allow tagging the null rev
5810 # don't allow tagging the null rev
5811 if (not opts.get('remove') and
5811 if (not opts.get('remove') and
5812 scmutil.revsingle(repo, rev_).rev() == nullrev):
5812 scmutil.revsingle(repo, rev_).rev() == nullrev):
5813 raise util.Abort(_("null revision specified"))
5813 raise util.Abort(_("null revision specified"))
5814
5814
5815 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5815 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5816 finally:
5816 finally:
5817 release(lock, wlock)
5817 release(lock, wlock)
5818
5818
5819 @command('tags', [], '')
5819 @command('tags', [], '')
5820 def tags(ui, repo, **opts):
5820 def tags(ui, repo, **opts):
5821 """list repository tags
5821 """list repository tags
5822
5822
5823 This lists both regular and local tags. When the -v/--verbose
5823 This lists both regular and local tags. When the -v/--verbose
5824 switch is used, a third column "local" is printed for local tags.
5824 switch is used, a third column "local" is printed for local tags.
5825
5825
5826 Returns 0 on success.
5826 Returns 0 on success.
5827 """
5827 """
5828
5828
5829 fm = ui.formatter('tags', opts)
5829 fm = ui.formatter('tags', opts)
5830 hexfunc = ui.debugflag and hex or short
5830 hexfunc = ui.debugflag and hex or short
5831 tagtype = ""
5831 tagtype = ""
5832
5832
5833 for t, n in reversed(repo.tagslist()):
5833 for t, n in reversed(repo.tagslist()):
5834 hn = hexfunc(n)
5834 hn = hexfunc(n)
5835 label = 'tags.normal'
5835 label = 'tags.normal'
5836 tagtype = ''
5836 tagtype = ''
5837 if repo.tagtype(t) == 'local':
5837 if repo.tagtype(t) == 'local':
5838 label = 'tags.local'
5838 label = 'tags.local'
5839 tagtype = 'local'
5839 tagtype = 'local'
5840
5840
5841 fm.startitem()
5841 fm.startitem()
5842 fm.write('tag', '%s', t, label=label)
5842 fm.write('tag', '%s', t, label=label)
5843 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5843 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5844 fm.condwrite(not ui.quiet, 'rev id', fmt,
5844 fm.condwrite(not ui.quiet, 'rev id', fmt,
5845 repo.changelog.rev(n), hn, label=label)
5845 repo.changelog.rev(n), hn, label=label)
5846 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5846 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5847 tagtype, label=label)
5847 tagtype, label=label)
5848 fm.plain('\n')
5848 fm.plain('\n')
5849 fm.end()
5849 fm.end()
5850
5850
5851 @command('tip',
5851 @command('tip',
5852 [('p', 'patch', None, _('show patch')),
5852 [('p', 'patch', None, _('show patch')),
5853 ('g', 'git', None, _('use git extended diff format')),
5853 ('g', 'git', None, _('use git extended diff format')),
5854 ] + templateopts,
5854 ] + templateopts,
5855 _('[-p] [-g]'))
5855 _('[-p] [-g]'))
5856 def tip(ui, repo, **opts):
5856 def tip(ui, repo, **opts):
5857 """show the tip revision
5857 """show the tip revision
5858
5858
5859 The tip revision (usually just called the tip) is the changeset
5859 The tip revision (usually just called the tip) is the changeset
5860 most recently added to the repository (and therefore the most
5860 most recently added to the repository (and therefore the most
5861 recently changed head).
5861 recently changed head).
5862
5862
5863 If you have just made a commit, that commit will be the tip. If
5863 If you have just made a commit, that commit will be the tip. If
5864 you have just pulled changes from another repository, the tip of
5864 you have just pulled changes from another repository, the tip of
5865 that repository becomes the current tip. The "tip" tag is special
5865 that repository becomes the current tip. The "tip" tag is special
5866 and cannot be renamed or assigned to a different changeset.
5866 and cannot be renamed or assigned to a different changeset.
5867
5867
5868 Returns 0 on success.
5868 Returns 0 on success.
5869 """
5869 """
5870 displayer = cmdutil.show_changeset(ui, repo, opts)
5870 displayer = cmdutil.show_changeset(ui, repo, opts)
5871 displayer.show(repo[len(repo) - 1])
5871 displayer.show(repo[len(repo) - 1])
5872 displayer.close()
5872 displayer.close()
5873
5873
5874 @command('unbundle',
5874 @command('unbundle',
5875 [('u', 'update', None,
5875 [('u', 'update', None,
5876 _('update to new branch head if changesets were unbundled'))],
5876 _('update to new branch head if changesets were unbundled'))],
5877 _('[-u] FILE...'))
5877 _('[-u] FILE...'))
5878 def unbundle(ui, repo, fname1, *fnames, **opts):
5878 def unbundle(ui, repo, fname1, *fnames, **opts):
5879 """apply one or more changegroup files
5879 """apply one or more changegroup files
5880
5880
5881 Apply one or more compressed changegroup files generated by the
5881 Apply one or more compressed changegroup files generated by the
5882 bundle command.
5882 bundle command.
5883
5883
5884 Returns 0 on success, 1 if an update has unresolved files.
5884 Returns 0 on success, 1 if an update has unresolved files.
5885 """
5885 """
5886 fnames = (fname1,) + fnames
5886 fnames = (fname1,) + fnames
5887
5887
5888 lock = repo.lock()
5888 lock = repo.lock()
5889 wc = repo['.']
5889 wc = repo['.']
5890 try:
5890 try:
5891 for fname in fnames:
5891 for fname in fnames:
5892 f = hg.openpath(ui, fname)
5892 f = hg.openpath(ui, fname)
5893 gen = changegroup.readbundle(f, fname)
5893 gen = changegroup.readbundle(f, fname)
5894 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5894 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5895 finally:
5895 finally:
5896 lock.release()
5896 lock.release()
5897 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5897 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5898 return postincoming(ui, repo, modheads, opts.get('update'), None)
5898 return postincoming(ui, repo, modheads, opts.get('update'), None)
5899
5899
5900 @command('^update|up|checkout|co',
5900 @command('^update|up|checkout|co',
5901 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5901 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5902 ('c', 'check', None,
5902 ('c', 'check', None,
5903 _('update across branches if no uncommitted changes')),
5903 _('update across branches if no uncommitted changes')),
5904 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5904 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5905 ('r', 'rev', '', _('revision'), _('REV'))],
5905 ('r', 'rev', '', _('revision'), _('REV'))],
5906 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5906 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5907 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5907 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5908 """update working directory (or switch revisions)
5908 """update working directory (or switch revisions)
5909
5909
5910 Update the repository's working directory to the specified
5910 Update the repository's working directory to the specified
5911 changeset. If no changeset is specified, update to the tip of the
5911 changeset. If no changeset is specified, update to the tip of the
5912 current named branch and move the current bookmark (see :hg:`help
5912 current named branch and move the current bookmark (see :hg:`help
5913 bookmarks`).
5913 bookmarks`).
5914
5914
5915 Update sets the working directory's parent revision to the specified
5915 Update sets the working directory's parent revision to the specified
5916 changeset (see :hg:`help parents`).
5916 changeset (see :hg:`help parents`).
5917
5917
5918 If the changeset is not a descendant or ancestor of the working
5918 If the changeset is not a descendant or ancestor of the working
5919 directory's parent, the update is aborted. With the -c/--check
5919 directory's parent, the update is aborted. With the -c/--check
5920 option, the working directory is checked for uncommitted changes; if
5920 option, the working directory is checked for uncommitted changes; if
5921 none are found, the working directory is updated to the specified
5921 none are found, the working directory is updated to the specified
5922 changeset.
5922 changeset.
5923
5923
5924 .. container:: verbose
5924 .. container:: verbose
5925
5925
5926 The following rules apply when the working directory contains
5926 The following rules apply when the working directory contains
5927 uncommitted changes:
5927 uncommitted changes:
5928
5928
5929 1. If neither -c/--check nor -C/--clean is specified, and if
5929 1. If neither -c/--check nor -C/--clean is specified, and if
5930 the requested changeset is an ancestor or descendant of
5930 the requested changeset is an ancestor or descendant of
5931 the working directory's parent, the uncommitted changes
5931 the working directory's parent, the uncommitted changes
5932 are merged into the requested changeset and the merged
5932 are merged into the requested changeset and the merged
5933 result is left uncommitted. If the requested changeset is
5933 result is left uncommitted. If the requested changeset is
5934 not an ancestor or descendant (that is, it is on another
5934 not an ancestor or descendant (that is, it is on another
5935 branch), the update is aborted and the uncommitted changes
5935 branch), the update is aborted and the uncommitted changes
5936 are preserved.
5936 are preserved.
5937
5937
5938 2. With the -c/--check option, the update is aborted and the
5938 2. With the -c/--check option, the update is aborted and the
5939 uncommitted changes are preserved.
5939 uncommitted changes are preserved.
5940
5940
5941 3. With the -C/--clean option, uncommitted changes are discarded and
5941 3. With the -C/--clean option, uncommitted changes are discarded and
5942 the working directory is updated to the requested changeset.
5942 the working directory is updated to the requested changeset.
5943
5943
5944 To cancel an uncommitted merge (and lose your changes), use
5944 To cancel an uncommitted merge (and lose your changes), use
5945 :hg:`update --clean .`.
5945 :hg:`update --clean .`.
5946
5946
5947 Use null as the changeset to remove the working directory (like
5947 Use null as the changeset to remove the working directory (like
5948 :hg:`clone -U`).
5948 :hg:`clone -U`).
5949
5949
5950 If you want to revert just one file to an older revision, use
5950 If you want to revert just one file to an older revision, use
5951 :hg:`revert [-r REV] NAME`.
5951 :hg:`revert [-r REV] NAME`.
5952
5952
5953 See :hg:`help dates` for a list of formats valid for -d/--date.
5953 See :hg:`help dates` for a list of formats valid for -d/--date.
5954
5954
5955 Returns 0 on success, 1 if there are unresolved files.
5955 Returns 0 on success, 1 if there are unresolved files.
5956 """
5956 """
5957 if rev and node:
5957 if rev and node:
5958 raise util.Abort(_("please specify just one revision"))
5958 raise util.Abort(_("please specify just one revision"))
5959
5959
5960 if rev is None or rev == '':
5960 if rev is None or rev == '':
5961 rev = node
5961 rev = node
5962
5962
5963 # with no argument, we also move the current bookmark, if any
5963 # with no argument, we also move the current bookmark, if any
5964 movemarkfrom = None
5964 movemarkfrom = None
5965 if rev is None:
5965 if rev is None:
5966 movemarkfrom = repo['.'].node()
5966 movemarkfrom = repo['.'].node()
5967
5967
5968 # if we defined a bookmark, we have to remember the original bookmark name
5968 # if we defined a bookmark, we have to remember the original bookmark name
5969 brev = rev
5969 brev = rev
5970 rev = scmutil.revsingle(repo, rev, rev).rev()
5970 rev = scmutil.revsingle(repo, rev, rev).rev()
5971
5971
5972 if check and clean:
5972 if check and clean:
5973 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5973 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5974
5974
5975 if date:
5975 if date:
5976 if rev is not None:
5976 if rev is not None:
5977 raise util.Abort(_("you can't specify a revision and a date"))
5977 raise util.Abort(_("you can't specify a revision and a date"))
5978 rev = cmdutil.finddate(ui, repo, date)
5978 rev = cmdutil.finddate(ui, repo, date)
5979
5979
5980 if check:
5980 if check:
5981 c = repo[None]
5981 c = repo[None]
5982 if c.dirty(merge=False, branch=False, missing=True):
5982 if c.dirty(merge=False, branch=False, missing=True):
5983 raise util.Abort(_("uncommitted local changes"))
5983 raise util.Abort(_("uncommitted local changes"))
5984 if rev is None:
5984 if rev is None:
5985 rev = repo[repo[None].branch()].rev()
5985 rev = repo[repo[None].branch()].rev()
5986 mergemod._checkunknown(repo, repo[None], repo[rev])
5986 mergemod._checkunknown(repo, repo[None], repo[rev])
5987
5987
5988 if clean:
5988 if clean:
5989 ret = hg.clean(repo, rev)
5989 ret = hg.clean(repo, rev)
5990 else:
5990 else:
5991 ret = hg.update(repo, rev)
5991 ret = hg.update(repo, rev)
5992
5992
5993 if not ret and movemarkfrom:
5993 if not ret and movemarkfrom:
5994 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5994 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5995 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5995 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5996 elif brev in repo._bookmarks:
5996 elif brev in repo._bookmarks:
5997 bookmarks.setcurrent(repo, brev)
5997 bookmarks.setcurrent(repo, brev)
5998 elif brev:
5998 elif brev:
5999 bookmarks.unsetcurrent(repo)
5999 bookmarks.unsetcurrent(repo)
6000
6000
6001 return ret
6001 return ret
6002
6002
6003 @command('verify', [])
6003 @command('verify', [])
6004 def verify(ui, repo):
6004 def verify(ui, repo):
6005 """verify the integrity of the repository
6005 """verify the integrity of the repository
6006
6006
6007 Verify the integrity of the current repository.
6007 Verify the integrity of the current repository.
6008
6008
6009 This will perform an extensive check of the repository's
6009 This will perform an extensive check of the repository's
6010 integrity, validating the hashes and checksums of each entry in
6010 integrity, validating the hashes and checksums of each entry in
6011 the changelog, manifest, and tracked files, as well as the
6011 the changelog, manifest, and tracked files, as well as the
6012 integrity of their crosslinks and indices.
6012 integrity of their crosslinks and indices.
6013
6013
6014 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6014 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6015 for more information about recovery from corruption of the
6015 for more information about recovery from corruption of the
6016 repository.
6016 repository.
6017
6017
6018 Returns 0 on success, 1 if errors are encountered.
6018 Returns 0 on success, 1 if errors are encountered.
6019 """
6019 """
6020 return hg.verify(repo)
6020 return hg.verify(repo)
6021
6021
6022 @command('version', [])
6022 @command('version', [])
6023 def version_(ui):
6023 def version_(ui):
6024 """output version and copyright information"""
6024 """output version and copyright information"""
6025 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6025 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6026 % util.version())
6026 % util.version())
6027 ui.status(_(
6027 ui.status(_(
6028 "(see http://mercurial.selenic.com for more information)\n"
6028 "(see http://mercurial.selenic.com for more information)\n"
6029 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6029 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6030 "This is free software; see the source for copying conditions. "
6030 "This is free software; see the source for copying conditions. "
6031 "There is NO\nwarranty; "
6031 "There is NO\nwarranty; "
6032 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6032 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6033 ))
6033 ))
6034
6034
6035 norepo = ("clone init version help debugcommands debugcomplete"
6035 norepo = ("clone init version help debugcommands debugcomplete"
6036 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6036 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6037 " debugknown debuggetbundle debugbundle")
6037 " debugknown debuggetbundle debugbundle")
6038 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6038 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6039 " debugdata debugindex debugindexdot debugrevlog")
6039 " debugdata debugindex debugindexdot debugrevlog")
6040 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6040 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6041 " remove resolve status debugwalk")
6041 " remove resolve status debugwalk")
@@ -1,383 +1,383 b''
1 $ "$TESTDIR/hghave" serve || exit 80
1 $ "$TESTDIR/hghave" serve || exit 80
2
2
3 $ cat << EOF >> $HGRCPATH
3 $ cat << EOF >> $HGRCPATH
4 > [ui]
4 > [ui]
5 > logtemplate={rev}:{node|short} {desc|firstline}
5 > logtemplate={rev}:{node|short} {desc|firstline}
6 > [phases]
6 > [phases]
7 > publish=False
7 > publish=False
8 > [extensions]
8 > [extensions]
9 > EOF
9 > EOF
10 $ cat > obs.py << EOF
10 $ cat > obs.py << EOF
11 > import mercurial.obsolete
11 > import mercurial.obsolete
12 > mercurial.obsolete._enabled = True
12 > mercurial.obsolete._enabled = True
13 > EOF
13 > EOF
14 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
14 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
15
15
16 initialize
16 initialize
17
17
18 $ hg init a
18 $ hg init a
19 $ cd a
19 $ cd a
20 $ echo 'test' > test
20 $ echo 'test' > test
21 $ hg commit -Am'test'
21 $ hg commit -Am'test'
22 adding test
22 adding test
23
23
24 set bookmarks
24 set bookmarks
25
25
26 $ hg bookmark X
26 $ hg bookmark X
27 $ hg bookmark Y
27 $ hg bookmark Y
28 $ hg bookmark Z
28 $ hg bookmark Z
29
29
30 import bookmark by name
30 import bookmark by name
31
31
32 $ hg init ../b
32 $ hg init ../b
33 $ cd ../b
33 $ cd ../b
34 $ hg book Y
34 $ hg book Y
35 $ hg book
35 $ hg book
36 * Y -1:000000000000
36 * Y -1:000000000000
37 $ hg pull ../a
37 $ hg pull ../a
38 pulling from ../a
38 pulling from ../a
39 requesting all changes
39 requesting all changes
40 adding changesets
40 adding changesets
41 adding manifests
41 adding manifests
42 adding file changes
42 adding file changes
43 added 1 changesets with 1 changes to 1 files
43 added 1 changesets with 1 changes to 1 files
44 updating bookmark Y
44 updating bookmark Y
45 adding remote bookmark X
45 adding remote bookmark X
46 adding remote bookmark Z
46 adding remote bookmark Z
47 (run 'hg update' to get a working copy)
47 (run 'hg update' to get a working copy)
48 $ hg bookmarks
48 $ hg bookmarks
49 X 0:4e3505fd9583
49 X 0:4e3505fd9583
50 Y 0:4e3505fd9583
50 Y 0:4e3505fd9583
51 Z 0:4e3505fd9583
51 Z 0:4e3505fd9583
52 $ hg debugpushkey ../a namespaces
52 $ hg debugpushkey ../a namespaces
53 bookmarks
53 bookmarks
54 phases
55 namespaces
54 namespaces
56 obsolete
55 obsolete
56 phases
57 $ hg debugpushkey ../a bookmarks
57 $ hg debugpushkey ../a bookmarks
58 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
58 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
59 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
59 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
60 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
60 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
61 $ hg pull -B X ../a
61 $ hg pull -B X ../a
62 pulling from ../a
62 pulling from ../a
63 no changes found
63 no changes found
64 importing bookmark X
64 importing bookmark X
65 $ hg bookmark
65 $ hg bookmark
66 X 0:4e3505fd9583
66 X 0:4e3505fd9583
67 Y 0:4e3505fd9583
67 Y 0:4e3505fd9583
68 Z 0:4e3505fd9583
68 Z 0:4e3505fd9583
69
69
70 export bookmark by name
70 export bookmark by name
71
71
72 $ hg bookmark W
72 $ hg bookmark W
73 $ hg bookmark foo
73 $ hg bookmark foo
74 $ hg bookmark foobar
74 $ hg bookmark foobar
75 $ hg push -B W ../a
75 $ hg push -B W ../a
76 pushing to ../a
76 pushing to ../a
77 searching for changes
77 searching for changes
78 no changes found
78 no changes found
79 exporting bookmark W
79 exporting bookmark W
80 [1]
80 [1]
81 $ hg -R ../a bookmarks
81 $ hg -R ../a bookmarks
82 W -1:000000000000
82 W -1:000000000000
83 X 0:4e3505fd9583
83 X 0:4e3505fd9583
84 Y 0:4e3505fd9583
84 Y 0:4e3505fd9583
85 * Z 0:4e3505fd9583
85 * Z 0:4e3505fd9583
86
86
87 delete a remote bookmark
87 delete a remote bookmark
88
88
89 $ hg book -d W
89 $ hg book -d W
90 $ hg push -B W ../a
90 $ hg push -B W ../a
91 pushing to ../a
91 pushing to ../a
92 searching for changes
92 searching for changes
93 no changes found
93 no changes found
94 deleting remote bookmark W
94 deleting remote bookmark W
95 [1]
95 [1]
96
96
97 push/pull name that doesn't exist
97 push/pull name that doesn't exist
98
98
99 $ hg push -B badname ../a
99 $ hg push -B badname ../a
100 pushing to ../a
100 pushing to ../a
101 searching for changes
101 searching for changes
102 no changes found
102 no changes found
103 bookmark badname does not exist on the local or remote repository!
103 bookmark badname does not exist on the local or remote repository!
104 [2]
104 [2]
105 $ hg pull -B anotherbadname ../a
105 $ hg pull -B anotherbadname ../a
106 pulling from ../a
106 pulling from ../a
107 abort: remote bookmark anotherbadname not found!
107 abort: remote bookmark anotherbadname not found!
108 [255]
108 [255]
109
109
110 divergent bookmarks
110 divergent bookmarks
111
111
112 $ cd ../a
112 $ cd ../a
113 $ echo c1 > f1
113 $ echo c1 > f1
114 $ hg ci -Am1
114 $ hg ci -Am1
115 adding f1
115 adding f1
116 $ hg book -f @
116 $ hg book -f @
117 $ hg book -f X
117 $ hg book -f X
118 $ hg book
118 $ hg book
119 @ 1:0d2164f0ce0d
119 @ 1:0d2164f0ce0d
120 * X 1:0d2164f0ce0d
120 * X 1:0d2164f0ce0d
121 Y 0:4e3505fd9583
121 Y 0:4e3505fd9583
122 Z 1:0d2164f0ce0d
122 Z 1:0d2164f0ce0d
123
123
124 $ cd ../b
124 $ cd ../b
125 $ hg up
125 $ hg up
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 updating bookmark foobar
127 updating bookmark foobar
128 $ echo c2 > f2
128 $ echo c2 > f2
129 $ hg ci -Am2
129 $ hg ci -Am2
130 adding f2
130 adding f2
131 $ hg book -f @
131 $ hg book -f @
132 $ hg book -f X
132 $ hg book -f X
133 $ hg book
133 $ hg book
134 @ 1:9b140be10808
134 @ 1:9b140be10808
135 * X 1:9b140be10808
135 * X 1:9b140be10808
136 Y 0:4e3505fd9583
136 Y 0:4e3505fd9583
137 Z 0:4e3505fd9583
137 Z 0:4e3505fd9583
138 foo -1:000000000000
138 foo -1:000000000000
139 foobar 1:9b140be10808
139 foobar 1:9b140be10808
140
140
141 $ hg pull --config paths.foo=../a foo
141 $ hg pull --config paths.foo=../a foo
142 pulling from $TESTTMP/a (glob)
142 pulling from $TESTTMP/a (glob)
143 searching for changes
143 searching for changes
144 adding changesets
144 adding changesets
145 adding manifests
145 adding manifests
146 adding file changes
146 adding file changes
147 added 1 changesets with 1 changes to 1 files (+1 heads)
147 added 1 changesets with 1 changes to 1 files (+1 heads)
148 divergent bookmark X stored as X@foo
148 divergent bookmark X stored as X@foo
149 updating bookmark Z
149 updating bookmark Z
150 divergent bookmark @ stored as @foo
150 divergent bookmark @ stored as @foo
151 (run 'hg heads' to see heads, 'hg merge' to merge)
151 (run 'hg heads' to see heads, 'hg merge' to merge)
152 $ hg book
152 $ hg book
153 @ 1:9b140be10808
153 @ 1:9b140be10808
154 @foo 2:0d2164f0ce0d
154 @foo 2:0d2164f0ce0d
155 * X 1:9b140be10808
155 * X 1:9b140be10808
156 X@foo 2:0d2164f0ce0d
156 X@foo 2:0d2164f0ce0d
157 Y 0:4e3505fd9583
157 Y 0:4e3505fd9583
158 Z 2:0d2164f0ce0d
158 Z 2:0d2164f0ce0d
159 foo -1:000000000000
159 foo -1:000000000000
160 foobar 1:9b140be10808
160 foobar 1:9b140be10808
161 $ hg push -f ../a
161 $ hg push -f ../a
162 pushing to ../a
162 pushing to ../a
163 searching for changes
163 searching for changes
164 adding changesets
164 adding changesets
165 adding manifests
165 adding manifests
166 adding file changes
166 adding file changes
167 added 1 changesets with 1 changes to 1 files (+1 heads)
167 added 1 changesets with 1 changes to 1 files (+1 heads)
168 $ hg -R ../a book
168 $ hg -R ../a book
169 @ 1:0d2164f0ce0d
169 @ 1:0d2164f0ce0d
170 * X 1:0d2164f0ce0d
170 * X 1:0d2164f0ce0d
171 Y 0:4e3505fd9583
171 Y 0:4e3505fd9583
172 Z 1:0d2164f0ce0d
172 Z 1:0d2164f0ce0d
173
173
174 update a remote bookmark from a non-head to a head
174 update a remote bookmark from a non-head to a head
175
175
176 $ hg up -q Y
176 $ hg up -q Y
177 $ echo c3 > f2
177 $ echo c3 > f2
178 $ hg ci -Am3
178 $ hg ci -Am3
179 adding f2
179 adding f2
180 created new head
180 created new head
181 $ hg push ../a
181 $ hg push ../a
182 pushing to ../a
182 pushing to ../a
183 searching for changes
183 searching for changes
184 adding changesets
184 adding changesets
185 adding manifests
185 adding manifests
186 adding file changes
186 adding file changes
187 added 1 changesets with 1 changes to 1 files (+1 heads)
187 added 1 changesets with 1 changes to 1 files (+1 heads)
188 updating bookmark Y
188 updating bookmark Y
189 $ hg -R ../a book
189 $ hg -R ../a book
190 @ 1:0d2164f0ce0d
190 @ 1:0d2164f0ce0d
191 * X 1:0d2164f0ce0d
191 * X 1:0d2164f0ce0d
192 Y 3:f6fc62dde3c0
192 Y 3:f6fc62dde3c0
193 Z 1:0d2164f0ce0d
193 Z 1:0d2164f0ce0d
194
194
195 diverging a remote bookmark fails
195 diverging a remote bookmark fails
196
196
197 $ hg up -q 4e3505fd9583
197 $ hg up -q 4e3505fd9583
198 $ echo c4 > f2
198 $ echo c4 > f2
199 $ hg ci -Am4
199 $ hg ci -Am4
200 adding f2
200 adding f2
201 created new head
201 created new head
202 $ echo c5 > f2
202 $ echo c5 > f2
203 $ hg ci -Am5
203 $ hg ci -Am5
204 $ hg log -G
204 $ hg log -G
205 @ 5:c922c0139ca0 5
205 @ 5:c922c0139ca0 5
206 |
206 |
207 o 4:4efff6d98829 4
207 o 4:4efff6d98829 4
208 |
208 |
209 | o 3:f6fc62dde3c0 3
209 | o 3:f6fc62dde3c0 3
210 |/
210 |/
211 | o 2:0d2164f0ce0d 1
211 | o 2:0d2164f0ce0d 1
212 |/
212 |/
213 | o 1:9b140be10808 2
213 | o 1:9b140be10808 2
214 |/
214 |/
215 o 0:4e3505fd9583 test
215 o 0:4e3505fd9583 test
216
216
217
217
218 $ hg book -f Y
218 $ hg book -f Y
219
219
220 $ cat <<EOF > ../a/.hg/hgrc
220 $ cat <<EOF > ../a/.hg/hgrc
221 > [web]
221 > [web]
222 > push_ssl = false
222 > push_ssl = false
223 > allow_push = *
223 > allow_push = *
224 > EOF
224 > EOF
225
225
226 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
226 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
227 $ cat ../hg2.pid >> $DAEMON_PIDS
227 $ cat ../hg2.pid >> $DAEMON_PIDS
228
228
229 $ hg push http://localhost:$HGPORT2/
229 $ hg push http://localhost:$HGPORT2/
230 pushing to http://localhost:$HGPORT2/
230 pushing to http://localhost:$HGPORT2/
231 searching for changes
231 searching for changes
232 abort: push creates new remote head c922c0139ca0!
232 abort: push creates new remote head c922c0139ca0!
233 (did you forget to merge? use push -f to force)
233 (did you forget to merge? use push -f to force)
234 [255]
234 [255]
235 $ hg -R ../a book
235 $ hg -R ../a book
236 @ 1:0d2164f0ce0d
236 @ 1:0d2164f0ce0d
237 * X 1:0d2164f0ce0d
237 * X 1:0d2164f0ce0d
238 Y 3:f6fc62dde3c0
238 Y 3:f6fc62dde3c0
239 Z 1:0d2164f0ce0d
239 Z 1:0d2164f0ce0d
240
240
241
241
242 Unrelated marker does not alter the decision
242 Unrelated marker does not alter the decision
243
243
244 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
244 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
245 $ hg push http://localhost:$HGPORT2/
245 $ hg push http://localhost:$HGPORT2/
246 pushing to http://localhost:$HGPORT2/
246 pushing to http://localhost:$HGPORT2/
247 searching for changes
247 searching for changes
248 abort: push creates new remote head c922c0139ca0!
248 abort: push creates new remote head c922c0139ca0!
249 (did you forget to merge? use push -f to force)
249 (did you forget to merge? use push -f to force)
250 [255]
250 [255]
251 $ hg -R ../a book
251 $ hg -R ../a book
252 @ 1:0d2164f0ce0d
252 @ 1:0d2164f0ce0d
253 * X 1:0d2164f0ce0d
253 * X 1:0d2164f0ce0d
254 Y 3:f6fc62dde3c0
254 Y 3:f6fc62dde3c0
255 Z 1:0d2164f0ce0d
255 Z 1:0d2164f0ce0d
256
256
257 Update to a successor works
257 Update to a successor works
258
258
259 $ hg id --debug -r 3
259 $ hg id --debug -r 3
260 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
260 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
261 $ hg id --debug -r 4
261 $ hg id --debug -r 4
262 4efff6d98829d9c824c621afd6e3f01865f5439f
262 4efff6d98829d9c824c621afd6e3f01865f5439f
263 $ hg id --debug -r 5
263 $ hg id --debug -r 5
264 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
264 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
265 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
265 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
266 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
266 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
267 $ hg push http://localhost:$HGPORT2/
267 $ hg push http://localhost:$HGPORT2/
268 pushing to http://localhost:$HGPORT2/
268 pushing to http://localhost:$HGPORT2/
269 searching for changes
269 searching for changes
270 remote: adding changesets
270 remote: adding changesets
271 remote: adding manifests
271 remote: adding manifests
272 remote: adding file changes
272 remote: adding file changes
273 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
273 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
274 updating bookmark Y
274 updating bookmark Y
275 $ hg -R ../a book
275 $ hg -R ../a book
276 @ 1:0d2164f0ce0d
276 @ 1:0d2164f0ce0d
277 * X 1:0d2164f0ce0d
277 * X 1:0d2164f0ce0d
278 Y 5:c922c0139ca0
278 Y 5:c922c0139ca0
279 Z 1:0d2164f0ce0d
279 Z 1:0d2164f0ce0d
280
280
281 hgweb
281 hgweb
282
282
283 $ cat <<EOF > .hg/hgrc
283 $ cat <<EOF > .hg/hgrc
284 > [web]
284 > [web]
285 > push_ssl = false
285 > push_ssl = false
286 > allow_push = *
286 > allow_push = *
287 > EOF
287 > EOF
288
288
289 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
289 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
290 $ cat ../hg.pid >> $DAEMON_PIDS
290 $ cat ../hg.pid >> $DAEMON_PIDS
291 $ cd ../a
291 $ cd ../a
292
292
293 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
293 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
294 bookmarks
294 bookmarks
295 phases
296 namespaces
295 namespaces
297 obsolete
296 obsolete
297 phases
298 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
298 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
299 @ 9b140be1080824d768c5a4691a564088eede71f9
299 @ 9b140be1080824d768c5a4691a564088eede71f9
300 X 9b140be1080824d768c5a4691a564088eede71f9
301 Y c922c0139ca03858f655e4a2af4dd02796a63969
302 Z 0d2164f0ce0d8f1d6f94351eba04b794909be66c
300 foo 0000000000000000000000000000000000000000
303 foo 0000000000000000000000000000000000000000
301 foobar 9b140be1080824d768c5a4691a564088eede71f9
304 foobar 9b140be1080824d768c5a4691a564088eede71f9
302 Y c922c0139ca03858f655e4a2af4dd02796a63969
303 X 9b140be1080824d768c5a4691a564088eede71f9
304 Z 0d2164f0ce0d8f1d6f94351eba04b794909be66c
305 $ hg out -B http://localhost:$HGPORT/
305 $ hg out -B http://localhost:$HGPORT/
306 comparing with http://localhost:$HGPORT/
306 comparing with http://localhost:$HGPORT/
307 searching for changed bookmarks
307 searching for changed bookmarks
308 no changed bookmarks found
308 no changed bookmarks found
309 [1]
309 [1]
310 $ hg push -B Z http://localhost:$HGPORT/
310 $ hg push -B Z http://localhost:$HGPORT/
311 pushing to http://localhost:$HGPORT/
311 pushing to http://localhost:$HGPORT/
312 searching for changes
312 searching for changes
313 no changes found
313 no changes found
314 exporting bookmark Z
314 exporting bookmark Z
315 [1]
315 [1]
316 $ hg book -d Z
316 $ hg book -d Z
317 $ hg in -B http://localhost:$HGPORT/
317 $ hg in -B http://localhost:$HGPORT/
318 comparing with http://localhost:$HGPORT/
318 comparing with http://localhost:$HGPORT/
319 searching for changed bookmarks
319 searching for changed bookmarks
320 Z 0d2164f0ce0d
320 Z 0d2164f0ce0d
321 foo 000000000000
321 foo 000000000000
322 foobar 9b140be10808
322 foobar 9b140be10808
323 $ hg pull -B Z http://localhost:$HGPORT/
323 $ hg pull -B Z http://localhost:$HGPORT/
324 pulling from http://localhost:$HGPORT/
324 pulling from http://localhost:$HGPORT/
325 no changes found
325 no changes found
326 divergent bookmark @ stored as @1
326 divergent bookmark @ stored as @1
327 adding remote bookmark foo
327 adding remote bookmark foo
328 adding remote bookmark foobar
328 adding remote bookmark foobar
329 divergent bookmark X stored as X@1
329 divergent bookmark X stored as X@1
330 adding remote bookmark Z
330 adding remote bookmark Z
331 importing bookmark Z
331 importing bookmark Z
332 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
332 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
333 requesting all changes
333 requesting all changes
334 adding changesets
334 adding changesets
335 adding manifests
335 adding manifests
336 adding file changes
336 adding file changes
337 added 5 changesets with 5 changes to 3 files (+2 heads)
337 added 5 changesets with 5 changes to 3 files (+2 heads)
338 updating to bookmark @
338 updating to bookmark @
339 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 $ hg -R cloned-bookmarks bookmarks
340 $ hg -R cloned-bookmarks bookmarks
341 * @ 1:9b140be10808
341 * @ 1:9b140be10808
342 X 1:9b140be10808
342 X 1:9b140be10808
343 Y 4:c922c0139ca0
343 Y 4:c922c0139ca0
344 Z 2:0d2164f0ce0d
344 Z 2:0d2164f0ce0d
345 foo -1:000000000000
345 foo -1:000000000000
346 foobar 1:9b140be10808
346 foobar 1:9b140be10808
347
347
348 $ cd ..
348 $ cd ..
349
349
350 Pushing a bookmark should only push the changes required by that
350 Pushing a bookmark should only push the changes required by that
351 bookmark, not all outgoing changes:
351 bookmark, not all outgoing changes:
352 $ hg clone http://localhost:$HGPORT/ addmarks
352 $ hg clone http://localhost:$HGPORT/ addmarks
353 requesting all changes
353 requesting all changes
354 adding changesets
354 adding changesets
355 adding manifests
355 adding manifests
356 adding file changes
356 adding file changes
357 added 5 changesets with 5 changes to 3 files (+2 heads)
357 added 5 changesets with 5 changes to 3 files (+2 heads)
358 updating to bookmark @
358 updating to bookmark @
359 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
360 $ cd addmarks
360 $ cd addmarks
361 $ echo foo > foo
361 $ echo foo > foo
362 $ hg add foo
362 $ hg add foo
363 $ hg commit -m 'add foo'
363 $ hg commit -m 'add foo'
364 $ echo bar > bar
364 $ echo bar > bar
365 $ hg add bar
365 $ hg add bar
366 $ hg commit -m 'add bar'
366 $ hg commit -m 'add bar'
367 $ hg co "tip^"
367 $ hg co "tip^"
368 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
368 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
369 $ hg book add-foo
369 $ hg book add-foo
370 $ hg book -r tip add-bar
370 $ hg book -r tip add-bar
371 Note: this push *must* push only a single changeset, as that's the point
371 Note: this push *must* push only a single changeset, as that's the point
372 of this test.
372 of this test.
373 $ hg push -B add-foo --traceback
373 $ hg push -B add-foo --traceback
374 pushing to http://localhost:$HGPORT/
374 pushing to http://localhost:$HGPORT/
375 searching for changes
375 searching for changes
376 remote: adding changesets
376 remote: adding changesets
377 remote: adding manifests
377 remote: adding manifests
378 remote: adding file changes
378 remote: adding file changes
379 remote: added 1 changesets with 1 changes to 1 files
379 remote: added 1 changesets with 1 changes to 1 files
380 updating bookmark @ failed!
380 updating bookmark @ failed!
381 exporting bookmark add-foo
381 exporting bookmark add-foo
382
382
383 $ cd ..
383 $ cd ..
@@ -1,384 +1,384 b''
1
1
2
2
3 This test tries to exercise the ssh functionality with a dummy script
3 This test tries to exercise the ssh functionality with a dummy script
4
4
5 creating 'remote' repo
5 creating 'remote' repo
6
6
7 $ hg init remote
7 $ hg init remote
8 $ cd remote
8 $ cd remote
9 $ echo this > foo
9 $ echo this > foo
10 $ echo this > fooO
10 $ echo this > fooO
11 $ hg ci -A -m "init" foo fooO
11 $ hg ci -A -m "init" foo fooO
12 $ cat <<EOF > .hg/hgrc
12 $ cat <<EOF > .hg/hgrc
13 > [server]
13 > [server]
14 > uncompressed = True
14 > uncompressed = True
15 >
15 >
16 > [hooks]
16 > [hooks]
17 > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
17 > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
18 > EOF
18 > EOF
19 $ cd ..
19 $ cd ..
20
20
21 repo not found error
21 repo not found error
22
22
23 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
23 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
24 remote: abort: there is no Mercurial repository here (.hg not found)!
24 remote: abort: there is no Mercurial repository here (.hg not found)!
25 abort: no suitable response from remote hg!
25 abort: no suitable response from remote hg!
26 [255]
26 [255]
27
27
28 non-existent absolute path
28 non-existent absolute path
29
29
30 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
30 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
31 remote: abort: there is no Mercurial repository here (.hg not found)!
31 remote: abort: there is no Mercurial repository here (.hg not found)!
32 abort: no suitable response from remote hg!
32 abort: no suitable response from remote hg!
33 [255]
33 [255]
34
34
35 clone remote via stream
35 clone remote via stream
36
36
37 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
37 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
38 streaming all changes
38 streaming all changes
39 4 files to transfer, 392 bytes of data
39 4 files to transfer, 392 bytes of data
40 transferred 392 bytes in * seconds (*/sec) (glob)
40 transferred 392 bytes in * seconds (*/sec) (glob)
41 updating to branch default
41 updating to branch default
42 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 $ cd local-stream
43 $ cd local-stream
44 $ hg verify
44 $ hg verify
45 checking changesets
45 checking changesets
46 checking manifests
46 checking manifests
47 crosschecking files in changesets and manifests
47 crosschecking files in changesets and manifests
48 checking files
48 checking files
49 2 files, 1 changesets, 2 total revisions
49 2 files, 1 changesets, 2 total revisions
50 $ cd ..
50 $ cd ..
51
51
52 clone remote via pull
52 clone remote via pull
53
53
54 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
54 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
55 requesting all changes
55 requesting all changes
56 adding changesets
56 adding changesets
57 adding manifests
57 adding manifests
58 adding file changes
58 adding file changes
59 added 1 changesets with 2 changes to 2 files
59 added 1 changesets with 2 changes to 2 files
60 updating to branch default
60 updating to branch default
61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62
62
63 verify
63 verify
64
64
65 $ cd local
65 $ cd local
66 $ hg verify
66 $ hg verify
67 checking changesets
67 checking changesets
68 checking manifests
68 checking manifests
69 crosschecking files in changesets and manifests
69 crosschecking files in changesets and manifests
70 checking files
70 checking files
71 2 files, 1 changesets, 2 total revisions
71 2 files, 1 changesets, 2 total revisions
72 $ echo '[hooks]' >> .hg/hgrc
72 $ echo '[hooks]' >> .hg/hgrc
73 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
73 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
74
74
75 empty default pull
75 empty default pull
76
76
77 $ hg paths
77 $ hg paths
78 default = ssh://user@dummy/remote
78 default = ssh://user@dummy/remote
79 $ hg pull -e "python \"$TESTDIR/dummyssh\""
79 $ hg pull -e "python \"$TESTDIR/dummyssh\""
80 pulling from ssh://user@dummy/remote
80 pulling from ssh://user@dummy/remote
81 searching for changes
81 searching for changes
82 no changes found
82 no changes found
83
83
84 local change
84 local change
85
85
86 $ echo bleah > foo
86 $ echo bleah > foo
87 $ hg ci -m "add"
87 $ hg ci -m "add"
88
88
89 updating rc
89 updating rc
90
90
91 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
91 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
92 $ echo "[ui]" >> .hg/hgrc
92 $ echo "[ui]" >> .hg/hgrc
93 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
93 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
94
94
95 find outgoing
95 find outgoing
96
96
97 $ hg out ssh://user@dummy/remote
97 $ hg out ssh://user@dummy/remote
98 comparing with ssh://user@dummy/remote
98 comparing with ssh://user@dummy/remote
99 searching for changes
99 searching for changes
100 changeset: 1:a28a9d1a809c
100 changeset: 1:a28a9d1a809c
101 tag: tip
101 tag: tip
102 user: test
102 user: test
103 date: Thu Jan 01 00:00:00 1970 +0000
103 date: Thu Jan 01 00:00:00 1970 +0000
104 summary: add
104 summary: add
105
105
106
106
107 find incoming on the remote side
107 find incoming on the remote side
108
108
109 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
109 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
110 comparing with ssh://user@dummy/local
110 comparing with ssh://user@dummy/local
111 searching for changes
111 searching for changes
112 changeset: 1:a28a9d1a809c
112 changeset: 1:a28a9d1a809c
113 tag: tip
113 tag: tip
114 user: test
114 user: test
115 date: Thu Jan 01 00:00:00 1970 +0000
115 date: Thu Jan 01 00:00:00 1970 +0000
116 summary: add
116 summary: add
117
117
118
118
119 find incoming on the remote side (using absolute path)
119 find incoming on the remote side (using absolute path)
120
120
121 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
121 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
122 comparing with ssh://user@dummy/$TESTTMP/local
122 comparing with ssh://user@dummy/$TESTTMP/local
123 searching for changes
123 searching for changes
124 changeset: 1:a28a9d1a809c
124 changeset: 1:a28a9d1a809c
125 tag: tip
125 tag: tip
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:00 1970 +0000
127 date: Thu Jan 01 00:00:00 1970 +0000
128 summary: add
128 summary: add
129
129
130
130
131 push
131 push
132
132
133 $ hg push
133 $ hg push
134 pushing to ssh://user@dummy/remote
134 pushing to ssh://user@dummy/remote
135 searching for changes
135 searching for changes
136 remote: adding changesets
136 remote: adding changesets
137 remote: adding manifests
137 remote: adding manifests
138 remote: adding file changes
138 remote: adding file changes
139 remote: added 1 changesets with 1 changes to 1 files
139 remote: added 1 changesets with 1 changes to 1 files
140 $ cd ../remote
140 $ cd ../remote
141
141
142 check remote tip
142 check remote tip
143
143
144 $ hg tip
144 $ hg tip
145 changeset: 1:a28a9d1a809c
145 changeset: 1:a28a9d1a809c
146 tag: tip
146 tag: tip
147 user: test
147 user: test
148 date: Thu Jan 01 00:00:00 1970 +0000
148 date: Thu Jan 01 00:00:00 1970 +0000
149 summary: add
149 summary: add
150
150
151 $ hg verify
151 $ hg verify
152 checking changesets
152 checking changesets
153 checking manifests
153 checking manifests
154 crosschecking files in changesets and manifests
154 crosschecking files in changesets and manifests
155 checking files
155 checking files
156 2 files, 2 changesets, 3 total revisions
156 2 files, 2 changesets, 3 total revisions
157 $ hg cat -r tip foo
157 $ hg cat -r tip foo
158 bleah
158 bleah
159 $ echo z > z
159 $ echo z > z
160 $ hg ci -A -m z z
160 $ hg ci -A -m z z
161 created new head
161 created new head
162
162
163 test pushkeys and bookmarks
163 test pushkeys and bookmarks
164
164
165 $ cd ../local
165 $ cd ../local
166 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
166 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
167 bookmarks
167 bookmarks
168 namespaces
168 phases
169 phases
169 namespaces
170 $ hg book foo -r 0
170 $ hg book foo -r 0
171 $ hg out -B
171 $ hg out -B
172 comparing with ssh://user@dummy/remote
172 comparing with ssh://user@dummy/remote
173 searching for changed bookmarks
173 searching for changed bookmarks
174 foo 1160648e36ce
174 foo 1160648e36ce
175 $ hg push -B foo
175 $ hg push -B foo
176 pushing to ssh://user@dummy/remote
176 pushing to ssh://user@dummy/remote
177 searching for changes
177 searching for changes
178 no changes found
178 no changes found
179 exporting bookmark foo
179 exporting bookmark foo
180 [1]
180 [1]
181 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
181 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
182 foo 1160648e36cec0054048a7edc4110c6f84fde594
182 foo 1160648e36cec0054048a7edc4110c6f84fde594
183 $ hg book -f foo
183 $ hg book -f foo
184 $ hg push --traceback
184 $ hg push --traceback
185 pushing to ssh://user@dummy/remote
185 pushing to ssh://user@dummy/remote
186 searching for changes
186 searching for changes
187 no changes found
187 no changes found
188 updating bookmark foo
188 updating bookmark foo
189 [1]
189 [1]
190 $ hg book -d foo
190 $ hg book -d foo
191 $ hg in -B
191 $ hg in -B
192 comparing with ssh://user@dummy/remote
192 comparing with ssh://user@dummy/remote
193 searching for changed bookmarks
193 searching for changed bookmarks
194 foo a28a9d1a809c
194 foo a28a9d1a809c
195 $ hg book -f -r 0 foo
195 $ hg book -f -r 0 foo
196 $ hg pull -B foo
196 $ hg pull -B foo
197 pulling from ssh://user@dummy/remote
197 pulling from ssh://user@dummy/remote
198 no changes found
198 no changes found
199 updating bookmark foo
199 updating bookmark foo
200 importing bookmark foo
200 importing bookmark foo
201 $ hg book -d foo
201 $ hg book -d foo
202 $ hg push -B foo
202 $ hg push -B foo
203 pushing to ssh://user@dummy/remote
203 pushing to ssh://user@dummy/remote
204 searching for changes
204 searching for changes
205 no changes found
205 no changes found
206 deleting remote bookmark foo
206 deleting remote bookmark foo
207 [1]
207 [1]
208
208
209 a bad, evil hook that prints to stdout
209 a bad, evil hook that prints to stdout
210
210
211 $ cat <<EOF > $TESTTMP/badhook
211 $ cat <<EOF > $TESTTMP/badhook
212 > import sys
212 > import sys
213 > sys.stdout.write("KABOOM\n")
213 > sys.stdout.write("KABOOM\n")
214 > EOF
214 > EOF
215
215
216 $ echo '[hooks]' >> ../remote/.hg/hgrc
216 $ echo '[hooks]' >> ../remote/.hg/hgrc
217 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
217 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
218 $ echo r > r
218 $ echo r > r
219 $ hg ci -A -m z r
219 $ hg ci -A -m z r
220
220
221 push should succeed even though it has an unexpected response
221 push should succeed even though it has an unexpected response
222
222
223 $ hg push
223 $ hg push
224 pushing to ssh://user@dummy/remote
224 pushing to ssh://user@dummy/remote
225 searching for changes
225 searching for changes
226 note: unsynced remote changes!
226 note: unsynced remote changes!
227 remote: adding changesets
227 remote: adding changesets
228 remote: adding manifests
228 remote: adding manifests
229 remote: adding file changes
229 remote: adding file changes
230 remote: added 1 changesets with 1 changes to 1 files
230 remote: added 1 changesets with 1 changes to 1 files
231 remote: KABOOM
231 remote: KABOOM
232 $ hg -R ../remote heads
232 $ hg -R ../remote heads
233 changeset: 3:1383141674ec
233 changeset: 3:1383141674ec
234 tag: tip
234 tag: tip
235 parent: 1:a28a9d1a809c
235 parent: 1:a28a9d1a809c
236 user: test
236 user: test
237 date: Thu Jan 01 00:00:00 1970 +0000
237 date: Thu Jan 01 00:00:00 1970 +0000
238 summary: z
238 summary: z
239
239
240 changeset: 2:6c0482d977a3
240 changeset: 2:6c0482d977a3
241 parent: 0:1160648e36ce
241 parent: 0:1160648e36ce
242 user: test
242 user: test
243 date: Thu Jan 01 00:00:00 1970 +0000
243 date: Thu Jan 01 00:00:00 1970 +0000
244 summary: z
244 summary: z
245
245
246
246
247 clone bookmarks
247 clone bookmarks
248
248
249 $ hg -R ../remote bookmark test
249 $ hg -R ../remote bookmark test
250 $ hg -R ../remote bookmarks
250 $ hg -R ../remote bookmarks
251 * test 2:6c0482d977a3
251 * test 2:6c0482d977a3
252 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
252 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
253 requesting all changes
253 requesting all changes
254 adding changesets
254 adding changesets
255 adding manifests
255 adding manifests
256 adding file changes
256 adding file changes
257 added 4 changesets with 5 changes to 4 files (+1 heads)
257 added 4 changesets with 5 changes to 4 files (+1 heads)
258 updating to branch default
258 updating to branch default
259 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
259 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 $ hg -R local-bookmarks bookmarks
260 $ hg -R local-bookmarks bookmarks
261 test 2:6c0482d977a3
261 test 2:6c0482d977a3
262
262
263 passwords in ssh urls are not supported
263 passwords in ssh urls are not supported
264 (we use a glob here because different Python versions give different
264 (we use a glob here because different Python versions give different
265 results here)
265 results here)
266
266
267 $ hg push ssh://user:erroneouspwd@dummy/remote
267 $ hg push ssh://user:erroneouspwd@dummy/remote
268 pushing to ssh://user:*@dummy/remote (glob)
268 pushing to ssh://user:*@dummy/remote (glob)
269 abort: password in URL not supported!
269 abort: password in URL not supported!
270 [255]
270 [255]
271
271
272 $ cd ..
272 $ cd ..
273
273
274 hide outer repo
274 hide outer repo
275 $ hg init
275 $ hg init
276
276
277 Test remote paths with spaces (issue2983):
277 Test remote paths with spaces (issue2983):
278
278
279 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
279 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
280 $ touch "$TESTTMP/a repo/test"
280 $ touch "$TESTTMP/a repo/test"
281 $ hg -R 'a repo' commit -A -m "test"
281 $ hg -R 'a repo' commit -A -m "test"
282 adding test
282 adding test
283 $ hg -R 'a repo' tag tag
283 $ hg -R 'a repo' tag tag
284 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
284 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
285 73649e48688a
285 73649e48688a
286
286
287 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
287 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
288
288
289 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
289 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
290 destination directory: a repo
290 destination directory: a repo
291 abort: destination 'a repo' is not empty
291 abort: destination 'a repo' is not empty
292 [255]
292 [255]
293
293
294 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
294 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
295 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
295 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
296 parameters:
296 parameters:
297
297
298 $ cat > ssh.sh << EOF
298 $ cat > ssh.sh << EOF
299 > userhost="\$1"
299 > userhost="\$1"
300 > SSH_ORIGINAL_COMMAND="\$2"
300 > SSH_ORIGINAL_COMMAND="\$2"
301 > export SSH_ORIGINAL_COMMAND
301 > export SSH_ORIGINAL_COMMAND
302 > PYTHONPATH="$PYTHONPATH"
302 > PYTHONPATH="$PYTHONPATH"
303 > export PYTHONPATH
303 > export PYTHONPATH
304 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
304 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
305 > EOF
305 > EOF
306
306
307 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
307 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
308 73649e48688a
308 73649e48688a
309
309
310 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
310 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
311 remote: Illegal repository "$TESTTMP/a'repo" (glob)
311 remote: Illegal repository "$TESTTMP/a'repo" (glob)
312 abort: no suitable response from remote hg!
312 abort: no suitable response from remote hg!
313 [255]
313 [255]
314
314
315 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
315 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
316 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
316 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
317 abort: no suitable response from remote hg!
317 abort: no suitable response from remote hg!
318 [255]
318 [255]
319
319
320 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
320 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
321 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
321 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
322 [255]
322 [255]
323
323
324 Test hg-ssh in read-only mode:
324 Test hg-ssh in read-only mode:
325
325
326 $ cat > ssh.sh << EOF
326 $ cat > ssh.sh << EOF
327 > userhost="\$1"
327 > userhost="\$1"
328 > SSH_ORIGINAL_COMMAND="\$2"
328 > SSH_ORIGINAL_COMMAND="\$2"
329 > export SSH_ORIGINAL_COMMAND
329 > export SSH_ORIGINAL_COMMAND
330 > PYTHONPATH="$PYTHONPATH"
330 > PYTHONPATH="$PYTHONPATH"
331 > export PYTHONPATH
331 > export PYTHONPATH
332 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
332 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
333 > EOF
333 > EOF
334
334
335 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
335 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
336 requesting all changes
336 requesting all changes
337 adding changesets
337 adding changesets
338 adding manifests
338 adding manifests
339 adding file changes
339 adding file changes
340 added 4 changesets with 5 changes to 4 files (+1 heads)
340 added 4 changesets with 5 changes to 4 files (+1 heads)
341 updating to branch default
341 updating to branch default
342 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
342 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
343
343
344 $ cd read-only-local
344 $ cd read-only-local
345 $ echo "baz" > bar
345 $ echo "baz" > bar
346 $ hg ci -A -m "unpushable commit" bar
346 $ hg ci -A -m "unpushable commit" bar
347 $ hg push --ssh "sh ../ssh.sh"
347 $ hg push --ssh "sh ../ssh.sh"
348 pushing to ssh://user@dummy/*/remote (glob)
348 pushing to ssh://user@dummy/*/remote (glob)
349 searching for changes
349 searching for changes
350 remote: Permission denied
350 remote: Permission denied
351 remote: abort: prechangegroup.hg-ssh hook failed
351 remote: abort: prechangegroup.hg-ssh hook failed
352 remote: Permission denied
352 remote: Permission denied
353 remote: abort: prepushkey.hg-ssh hook failed
353 remote: abort: prepushkey.hg-ssh hook failed
354 abort: unexpected response: empty string
354 abort: unexpected response: empty string
355 [255]
355 [255]
356
356
357 $ cd ..
357 $ cd ..
358
358
359 $ cat dummylog
359 $ cat dummylog
360 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
360 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
361 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
361 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
362 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
362 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
363 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
363 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
364 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
364 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
365 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
365 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
366 Got arguments 1:user@dummy 2:hg -R local serve --stdio
366 Got arguments 1:user@dummy 2:hg -R local serve --stdio
367 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
367 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
368 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
368 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
369 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
369 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
370 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
370 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
371 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
371 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
372 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
372 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
373 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
373 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
374 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
374 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
375 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
375 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
376 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
376 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
377 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
377 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
378 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
378 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
379 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
379 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
380 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
380 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
381 Got arguments 1:user@dummy 2:hg init 'a repo'
381 Got arguments 1:user@dummy 2:hg init 'a repo'
382 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
382 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
383 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
383 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
384 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
384 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
General Comments 0
You need to be logged in to leave comments. Login now